global_type_table.rs 7.36 KB
Newer Older
qinsoon's avatar
qinsoon committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14
// 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.

qinsoon's avatar
qinsoon committed
15
use std::sync::RwLock;
16
use std::sync::atomic::{AtomicUsize, Ordering};
qinsoon's avatar
qinsoon committed
17
use std::collections::HashMap;
qinsoon's avatar
qinsoon committed
18
use std::mem;
19 20
use utils::mem::*;
use utils::*;
qinsoon's avatar
qinsoon committed
21 22 23

use objectmodel::sidemap::TypeID;
use objectmodel::sidemap::N_TYPES;
qinsoon's avatar
qinsoon committed
24
use objectmodel::sidemap::type_encode::*;
qinsoon's avatar
qinsoon committed
25 26 27 28
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.
29
#[repr(C)]
30
pub struct GlobalTypeTable {
qinsoon's avatar
qinsoon committed
31 32 33
    /// current index for small entries
    small_entry_i: usize,
    /// current index for large entries
qinsoon's avatar
qinsoon committed
34 35
    large_entry_i: usize,
    /// full entries
36 37 38 39
    full_entry_i: usize,
    full_entries: RwLock<HashMap<usize, FullTypeEncode>>,

    #[allow(dead_code)]
40 41
    mmap_start: Address,
    mmap_size: ByteSize,
qinsoon's avatar
qinsoon committed
42

43
    table: [ShortTypeEncode; N_TYPES]
qinsoon's avatar
qinsoon committed
44 45 46 47
}

const SMALL_ENTRY_CAP: usize = 1 << SMALL_ID_WIDTH;
const LARGE_ENTRY_CAP: usize = N_TYPES;
qinsoon's avatar
qinsoon committed
48
const FULL_ENTRY_START: usize = LARGE_ENTRY_CAP + 1;
qinsoon's avatar
qinsoon committed
49 50

/// storing a pointer to the actual type table
51
static GLOBAL_TYPE_TABLE_PTR: AtomicUsize = AtomicUsize::new(0);
qinsoon's avatar
qinsoon committed
52
/// storing a pointer to the metadata of the type table
53
static GLOBAL_TYPE_TABLE_META: AtomicUsize = AtomicUsize::new(0);
qinsoon's avatar
qinsoon committed
54 55 56

impl GlobalTypeTable {
    pub fn init() {
57
        debug!("Init GlobalTypeTable...");
58 59
        let mmap_size = mem::size_of::<GlobalTypeTable>();
        let mmap = mmap_large(mmap_size);
qinsoon's avatar
qinsoon committed
60

61
        info!("Global Type Table allocated at {}", mmap);
qinsoon's avatar
qinsoon committed
62 63

        // start address of metadata
64
        let meta_addr = mmap;
qinsoon's avatar
qinsoon committed
65
        GLOBAL_TYPE_TABLE_META.store(meta_addr.as_usize(), Ordering::Relaxed);
66

67
        let meta: &mut GlobalTypeTable = unsafe { meta_addr.to_ref_mut() };
68

qinsoon's avatar
qinsoon committed
69
        // actual table
70
        let table_addr = Address::from_ptr(&meta.table as *const [ShortTypeEncode; N_TYPES]);
qinsoon's avatar
qinsoon committed
71
        GLOBAL_TYPE_TABLE_PTR.store(table_addr.as_usize(), Ordering::Relaxed);
qinsoon's avatar
qinsoon committed
72 73 74 75

        // initialize meta
        meta.small_entry_i = 0;
        meta.large_entry_i = SMALL_ENTRY_CAP;
qinsoon's avatar
qinsoon committed
76
        meta.full_entry_i = FULL_ENTRY_START;
qinsoon's avatar
qinsoon committed
77 78 79
        unsafe {
            use std::ptr;
            ptr::write(
80
                &mut meta.full_entries as *mut RwLock<HashMap<usize, FullTypeEncode>>,
qinsoon's avatar
qinsoon committed
81 82 83
                RwLock::new(HashMap::new())
            )
        }
84 85
        meta.mmap_start = mmap;
        meta.mmap_size = mmap_size;
qinsoon's avatar
qinsoon committed
86 87 88 89 90

        // save mmap
        trace!("Global Type Table initialization done");
    }

91
    pub fn cleanup() {
92
        // unmap the table
qinsoon's avatar
qinsoon committed
93 94 95 96 97 98 99 100 101
        if GLOBAL_TYPE_TABLE_META.load(Ordering::SeqCst) != 0 {
            let mmap_start = GlobalTypeTable::table_meta().mmap_start;
            let mmap_size = GlobalTypeTable::table_meta().mmap_size;
            munmap(mmap_start, mmap_size);

            // set pointers to zero
            GLOBAL_TYPE_TABLE_PTR.store(0, Ordering::Relaxed);
            GLOBAL_TYPE_TABLE_META.store(0, Ordering::Relaxed);
        }
102 103
    }

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

    #[inline(always)]
110
    pub fn table() -> &'static mut [ShortTypeEncode; N_TYPES] {
qinsoon's avatar
qinsoon committed
111
        unsafe { mem::transmute(GLOBAL_TYPE_TABLE_PTR.load(Ordering::Relaxed)) }
qinsoon's avatar
qinsoon committed
112 113
    }

114
    pub fn insert_small_entry(entry: ShortTypeEncode) -> TypeID {
115 116
        let meta = GlobalTypeTable::table_meta();
        let table = GlobalTypeTable::table();
qinsoon's avatar
qinsoon committed
117 118 119 120 121 122 123 124 125 126 127

        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")
        }
    }

128
    pub fn insert_large_entry(entry: ShortTypeEncode) -> TypeID {
129 130
        let meta = GlobalTypeTable::table_meta();
        let table = GlobalTypeTable::table();
qinsoon's avatar
qinsoon committed
131 132 133 134 135 136 137 138 139 140

        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")
        }
    }
qinsoon's avatar
qinsoon committed
141

142
    pub fn force_set_short_entry(index: TypeID, entry: ShortTypeEncode) {
143 144
        let meta = GlobalTypeTable::table_meta();
        let table = GlobalTypeTable::table();
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164

        table[index] = entry;

        if index < SMALL_ENTRY_CAP {
            if meta.small_entry_i < index {
                meta.small_entry_i = index;
            }
        } else if index < LARGE_ENTRY_CAP {
            if meta.large_entry_i < index {
                meta.large_entry_i = index;
            }
        } else {
            panic!(
                "TypeID {} exceeds LARGE_ENTRY_CAP, try use insert_full_entry() instead",
                index
            )
        }
    }

    pub fn insert_full_entry(entry: FullTypeEncode) -> TypeID {
qinsoon's avatar
qinsoon committed
165 166 167
        let meta = GlobalTypeTable::table_meta();

        let mut lock = meta.full_entries.write().unwrap();
168
        let id = meta.full_entry_i;
qinsoon's avatar
qinsoon committed
169
        lock.insert(id, entry);
170
        meta.full_entry_i += 1;
qinsoon's avatar
qinsoon committed
171 172 173 174

        id
    }

175
    pub fn force_set_full_entry(index: TypeID, entry: FullTypeEncode) {
176
        let meta = GlobalTypeTable::table_meta();
177 178 179 180 181 182 183 184 185 186
        let mut lock = meta.full_entries.write().unwrap();
        assert!(!lock.contains_key(&index));
        lock.insert(index, entry);

        if meta.full_entry_i < index {
            meta.full_entry_i = index;
        }
    }

    pub fn get_full_type(id: usize) -> FullTypeEncode {
qinsoon's avatar
qinsoon committed
187 188 189 190 191
        let meta = GlobalTypeTable::table_meta();
        let lock = meta.full_entries.read().unwrap();
        debug_assert!(lock.contains_key(&id));
        lock.get(&id).unwrap().clone()
    }
qinsoon's avatar
qinsoon committed
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
}

#[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;
210
            ShortTypeEncode::new(8, 12, fix_ty, 0, [0; 63])
qinsoon's avatar
qinsoon committed
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
        };
        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);
    }
}