global_type_table.rs 5.8 KB
Newer Older
qinsoon's avatar
qinsoon committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
// Copyright 2017 The Australian National University
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::sync::Mutex;
use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
use std::mem;
use utils::mem::memmap;
use utils::math;
use utils::Address;

use objectmodel::sidemap::TypeID;
use objectmodel::sidemap::N_TYPES;
use objectmodel::sidemap::type_encode::TypeEncode;
use objectmodel::sidemap::object_encode::SMALL_ID_WIDTH;

/// represents a chunk of memory as global type table, which contains some metadata for the
/// type table and all the type encoding entries.
///
/// The memory looks like this
///
/// |----------------|
/// | metadata(this) |
/// | ...            |
/// |----------------| <- global_type_table points to this
/// |                |    at next 128 bytes alignment (size of TypeEncoding)
/// | small entries  |
/// | ...            |
/// | ...            |
/// |----------------| (8192 entries = 1 << 13 (SMALL_ID_WIDTH) )
/// | large entries  |
/// | ...            |
/// | ...            |
/// |________________|
///
#[repr(C, packed)]
47
pub struct GlobalTypeTable {
qinsoon's avatar
qinsoon committed
48 49 50 51 52 53 54 55 56 57
    /// current index for small entries
    small_entry_i: usize,
    /// current index for large entries
    large_entry_i: usize
}

const SMALL_ENTRY_CAP: usize = 1 << SMALL_ID_WIDTH;
const LARGE_ENTRY_CAP: usize = N_TYPES;

/// storing a pointer to the actual type table
qinsoon's avatar
qinsoon committed
58
static GLOBAL_TYPE_TABLE_PTR: AtomicUsize = ATOMIC_USIZE_INIT;
qinsoon's avatar
qinsoon committed
59
/// storing a pointer to the metadata of the type table
qinsoon's avatar
qinsoon committed
60
static GLOBAL_TYPE_TABLE_META: AtomicUsize = ATOMIC_USIZE_INIT;
qinsoon's avatar
qinsoon committed
61 62 63
/// save Mmap to keep the memory map alive
//  it is okay to use lock here, as we won't actually access this field
lazy_static!{
qinsoon's avatar
qinsoon committed
64
    static ref GTT_MMAP: Mutex<Option<memmap::MmapMut>> = Mutex::new(None);
qinsoon's avatar
qinsoon committed
65 66 67 68
}

impl GlobalTypeTable {
    pub fn init() {
qinsoon's avatar
qinsoon committed
69
        let mut mmap_lock = GTT_MMAP.lock().unwrap();
qinsoon's avatar
qinsoon committed
70 71 72 73 74
        assert!(mmap_lock.is_none());

        let entry_size = mem::size_of::<TypeEncode>();
        let metadata_size = math::align_up(mem::size_of::<GlobalTypeTable>(), entry_size);

qinsoon's avatar
qinsoon committed
75
        let mut mmap = match memmap::MmapMut::map_anon(metadata_size + N_TYPES * entry_size) {
qinsoon's avatar
qinsoon committed
76 77 78 79
            Ok(m) => m,
            Err(_) => panic!("failed to mmap for global type table")
        };

qinsoon's avatar
qinsoon committed
80
        info!("Global Type Table allocated at {:?}", mmap.as_mut_ptr());
qinsoon's avatar
qinsoon committed
81 82

        // start address of metadata
qinsoon's avatar
qinsoon committed
83
        let meta_addr = Address::from_ptr::<u8>(mmap.as_mut_ptr());
qinsoon's avatar
qinsoon committed
84
        GLOBAL_TYPE_TABLE_META.store(meta_addr.as_usize(), Ordering::Relaxed);
qinsoon's avatar
qinsoon committed
85 86
        // actual table
        let table_addr = meta_addr + metadata_size;
qinsoon's avatar
qinsoon committed
87
        GLOBAL_TYPE_TABLE_PTR.store(table_addr.as_usize(), Ordering::Relaxed);
qinsoon's avatar
qinsoon committed
88 89 90 91 92 93 94 95 96 97 98 99 100

        // initialize meta
        let meta: &mut GlobalTypeTable = unsafe { meta_addr.to_ptr_mut().as_mut().unwrap() };
        meta.small_entry_i = 0;
        meta.large_entry_i = SMALL_ENTRY_CAP;

        // save mmap
        *mmap_lock = Some(mmap);
        trace!("Global Type Table initialization done");
    }

    #[inline(always)]
    fn table_meta() -> &'static mut GlobalTypeTable {
qinsoon's avatar
qinsoon committed
101
        unsafe { mem::transmute(GLOBAL_TYPE_TABLE_META.load(Ordering::Relaxed)) }
qinsoon's avatar
qinsoon committed
102 103 104
    }

    #[inline(always)]
105
    pub fn table() -> &'static mut [TypeEncode; N_TYPES] {
qinsoon's avatar
qinsoon committed
106
        unsafe { mem::transmute(GLOBAL_TYPE_TABLE_PTR.load(Ordering::Relaxed)) }
qinsoon's avatar
qinsoon committed
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
    }

    pub fn insert_small_entry(entry: TypeEncode) -> TypeID {
        let mut meta = GlobalTypeTable::table_meta();
        let mut table = GlobalTypeTable::table();

        if meta.small_entry_i < SMALL_ENTRY_CAP {
            let id = meta.small_entry_i;
            table[id] = entry;
            meta.small_entry_i += 1;
            id
        } else {
            panic!("small type entries overflow the global type table")
        }
    }

    pub fn insert_large_entry(entry: TypeEncode) -> TypeID {
        let mut meta = GlobalTypeTable::table_meta();
        let mut table = GlobalTypeTable::table();

        if meta.large_entry_i < LARGE_ENTRY_CAP {
            let id = meta.large_entry_i;
            table[id] = entry;
            meta.large_entry_i += 1;
            id
        } else {
            panic!("large type entries overflow the global type table")
        }
    }
}

#[cfg(test)]
mod global_type_table_test {
    use super::*;
    use objectmodel::sidemap::type_encode::WordType::*;
    use start_logging_trace;

    #[test]
    fn test_insert() {
        start_logging_trace();

        GlobalTypeTable::init();
        let ty = {
            let mut fix_ty = [0; 63];
            fix_ty[0] = 0b11100100u8;
            fix_ty[1] = 0b00011011u8;
            fix_ty[2] = 0b11100100u8;
            TypeEncode::new(12, fix_ty, 0, [0; 63])
        };
        let tyid = GlobalTypeTable::insert_small_entry(ty) as usize;

        let ref loaded_ty = GlobalTypeTable::table()[tyid];
        assert_eq!(loaded_ty.fix_ty(0), NonRef);
        assert_eq!(loaded_ty.fix_ty(1), Ref);
        assert_eq!(loaded_ty.fix_ty(2), WeakRef);
        assert_eq!(loaded_ty.fix_ty(3), TaggedRef);
        assert_eq!(loaded_ty.fix_ty(4), TaggedRef);
        assert_eq!(loaded_ty.fix_ty(5), WeakRef);
        assert_eq!(loaded_ty.fix_ty(6), Ref);
        assert_eq!(loaded_ty.fix_ty(7), NonRef);
        assert_eq!(loaded_ty.fix_ty(8), NonRef);
        assert_eq!(loaded_ty.fix_ty(9), Ref);
        assert_eq!(loaded_ty.fix_ty(10), WeakRef);
        assert_eq!(loaded_ty.fix_ty(11), TaggedRef);
    }
}