GitLab will be upgraded on 30 Jan 2023 from 2.00 pm (AEDT) to 3.00 pm (AEDT). During the update, GitLab and Mattermost services will not be available. If you have any concerns with this, please talk to us at N110 (b) CSIT building.

vm.rs 58.2 KB
Newer Older
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
16
use std::collections::HashMap;

qinsoon's avatar
qinsoon committed
17
use ast::ptr::*;
qinsoon's avatar
qinsoon committed
18
use ast::ir::*;
19
use ast::inst::*;
qinsoon's avatar
qinsoon committed
20
use ast::types;
qinsoon's avatar
qinsoon committed
21
use ast::types::*;
qinsoon's avatar
qinsoon committed
22
use compiler::{Compiler, CompilerPolicy};
qinsoon's avatar
qinsoon committed
23
24
use compiler::backend;
use compiler::backend::BackendTypeInfo;
qinsoon's avatar
qinsoon committed
25
use compiler::machine_code::CompiledFunction;
26
27
use runtime::thread::*;
use runtime::ValueLocation;
qinsoon's avatar
qinsoon committed
28
use utils::ByteSize;
29
use utils::BitSize;
30
use utils::Address;
31
use runtime::mm as gc;
32
use vm::handle::*;
qinsoon's avatar
qinsoon committed
33
34
use vm::vm_options::VMOptions;
use vm::vm_options::MuLogLevel;
35

qinsoon's avatar
qinsoon committed
36
37
use rustc_serialize::{Encodable, Encoder, Decodable, Decoder};
use log::LogLevel;
38
use std::sync::Arc;
qinsoon's avatar
qinsoon committed
39
use std::sync::RwLock;
40
use std::sync::RwLockWriteGuard;
41
use std::sync::atomic::{AtomicUsize, AtomicBool, ATOMIC_BOOL_INIT, ATOMIC_USIZE_INIT, Ordering};
42

qinsoon's avatar
qinsoon committed
43
44
45
46
47
// FIXME:
// besides fields in VM, there are some 'globals' we need to persist
// such as STRUCT_TAG_MAP
// possibly INTERNAL_ID in ir.rs, internal types, etc

qinsoon's avatar
qinsoon committed
48
pub struct VM {
49
    // ---serialize---
qinsoon's avatar
qinsoon committed
50
    // 0
51
    next_id: AtomicUsize,
qinsoon's avatar
qinsoon committed
52
    // 1
qinsoon's avatar
qinsoon committed
53
    id_name_map: RwLock<HashMap<MuID, MuName>>,
qinsoon's avatar
qinsoon committed
54
    // 2
qinsoon's avatar
qinsoon committed
55
    name_id_map: RwLock<HashMap<MuName, MuID>>,
qinsoon's avatar
qinsoon committed
56
    // 3
qinsoon's avatar
qinsoon committed
57
    types: RwLock<HashMap<MuID, P<MuType>>>,
qinsoon's avatar
qinsoon committed
58
59
    // 4
    backend_type_info: RwLock<HashMap<MuID, Box<BackendTypeInfo>>>,
60
    // 5
qinsoon's avatar
qinsoon committed
61
    constants: RwLock<HashMap<MuID, P<Value>>>,
qinsoon's avatar
qinsoon committed
62
    // 6
qinsoon's avatar
qinsoon committed
63
    globals: RwLock<HashMap<MuID, P<Value>>>,
64
    pub global_locations: RwLock<HashMap<MuID, ValueLocation>>,
qinsoon's avatar
qinsoon committed
65
    // 7
qinsoon's avatar
qinsoon committed
66
    func_sigs: RwLock<HashMap<MuID, P<MuFuncSig>>>,
qinsoon's avatar
qinsoon committed
67
    // 8
qinsoon's avatar
qinsoon committed
68
    funcs: RwLock<HashMap<MuID, RwLock<MuFunction>>>,
qinsoon's avatar
qinsoon committed
69
70
    // 9
    func_vers: RwLock<HashMap<MuID, RwLock<MuFunctionVersion>>>,
71
72
    // 10
    pub primordial: RwLock<Option<MuPrimordialThread>>,
qinsoon's avatar
qinsoon committed
73
74
    // 11
    is_running: AtomicBool,
qinsoon's avatar
qinsoon committed
75
76
    // 12
    pub vm_options: VMOptions,
qinsoon's avatar
qinsoon committed
77
    
78
    // ---partially serialize---
qinsoon's avatar
qinsoon committed
79
    // 13
qinsoon's avatar
qinsoon committed
80
    compiled_funcs: RwLock<HashMap<MuID, RwLock<CompiledFunction>>>,
81
82
83
84
85
86

    // ---do not serialize---

    // client may try to store funcref to the heap, so that they can load it later, and call it
    // however the store may happen before we have an actual address to the func (in AOT scenario)
    aot_pending_funcref_store: RwLock<HashMap<Address, ValueLocation>>
87
88
}

89
90
91
use std::u64;
const PENDING_FUNCREF : u64 = u64::MAX;

qinsoon's avatar
qinsoon committed
92
const VM_SERIALIZE_FIELDS : usize = 14;
qinsoon's avatar
qinsoon committed
93

94
95
impl Encodable for VM {
    fn encode<S: Encoder> (&self, s: &mut S) -> Result<(), S::Error> {
96
97
        let mut field_i = 0;

qinsoon's avatar
qinsoon committed
98
99
        // serialize VM_SERIALIZE_FIELDS fields
        // PLUS ONE extra global STRUCT_TAG_MAP
100
        s.emit_struct("VM", VM_SERIALIZE_FIELDS + 2, |s| {
101
            // next_id
qinsoon's avatar
qinsoon committed
102
            trace!("...serializing next_id");
103
            try!(s.emit_struct_field("next_id", field_i, |s| {
104
105
                s.emit_usize(self.next_id.load(Ordering::SeqCst))
            }));
106
            field_i += 1;
107
108
                
            // id_name_map
qinsoon's avatar
qinsoon committed
109
            trace!("...serializing id_name_map");
110
111
            {
                let map : &HashMap<MuID, MuName> = &self.id_name_map.read().unwrap();            
112
                try!(s.emit_struct_field("id_name_map", field_i, |s| map.encode(s)));
113
            }
114
            field_i += 1;
115
116
            
            // name_id_map
qinsoon's avatar
qinsoon committed
117
            trace!("...serializing name_id_map");
118
119
            {
                let map : &HashMap<MuName, MuID> = &self.name_id_map.read().unwrap(); 
120
                try!(s.emit_struct_field("name_id_map", field_i, |s| map.encode(s)));
121
            }
122
            field_i += 1;
123
124
            
            // types
qinsoon's avatar
qinsoon committed
125
            trace!("...serializing types");
126
127
            {
                let types = &self.types.read().unwrap();
128
                try!(s.emit_struct_field("types", field_i, |s| types.encode(s)));
qinsoon's avatar
qinsoon committed
129
            }
130
131
            field_i += 1;

qinsoon's avatar
qinsoon committed
132
            // STRUCT_TAG_MAP
qinsoon's avatar
qinsoon committed
133
            trace!("...serializing struct_tag_map");
qinsoon's avatar
qinsoon committed
134
135
            {
                let struct_tag_map = types::STRUCT_TAG_MAP.read().unwrap();
136
137
138
139
140
141
142
143
144
                try!(s.emit_struct_field("struct_tag_map", field_i, |s| struct_tag_map.encode(s)));
            }
            field_i += 1;

            // HYBRID_TAG_MAP
            trace!("...serializing hybrid_tag_map");
            {
                let hybrid_tag_map = types::HYBRID_TAG_MAP.read().unwrap();
                try!(s.emit_struct_field("hybrid_tag_map", field_i, |s| hybrid_tag_map.encode(s)));
qinsoon's avatar
qinsoon committed
145
            }
146
            field_i += 1;
qinsoon's avatar
qinsoon committed
147
148
            
            // backend_type_info
qinsoon's avatar
qinsoon committed
149
            trace!("...serializing backend_type_info");
qinsoon's avatar
qinsoon committed
150
151
            {
                let backend_type_info : &HashMap<_, _> = &self.backend_type_info.read().unwrap();
152
                try!(s.emit_struct_field("backend_type_info", field_i, |s| backend_type_info.encode(s)));
qinsoon's avatar
qinsoon committed
153
            }
154
            field_i += 1;
qinsoon's avatar
qinsoon committed
155
156
            
            // constants
qinsoon's avatar
qinsoon committed
157
            trace!("...serializing constants");
qinsoon's avatar
qinsoon committed
158
159
            {
                let constants : &HashMap<_, _> = &self.constants.read().unwrap();
160
                try!(s.emit_struct_field("constants", field_i, |s| constants.encode(s)));
qinsoon's avatar
qinsoon committed
161
            }
162
            field_i += 1;
qinsoon's avatar
qinsoon committed
163
164
            
            // globals
qinsoon's avatar
qinsoon committed
165
            trace!("...serializing globals");
qinsoon's avatar
qinsoon committed
166
167
            {
                let globals: &HashMap<_, _> = &self.globals.read().unwrap();
168
                try!(s.emit_struct_field("globals", field_i, |s| globals.encode(s)));
qinsoon's avatar
qinsoon committed
169
            }
170
            field_i += 1;
qinsoon's avatar
qinsoon committed
171
172
            
            // func sigs
qinsoon's avatar
qinsoon committed
173
            trace!("...serializing func_sigs");
qinsoon's avatar
qinsoon committed
174
175
            {
                let func_sigs: &HashMap<_, _> = &self.func_sigs.read().unwrap();
176
                try!(s.emit_struct_field("func_sigs", field_i, |s| func_sigs.encode(s)));
qinsoon's avatar
qinsoon committed
177
            }
178
            field_i += 1;
qinsoon's avatar
qinsoon committed
179
180
            
            // funcs
qinsoon's avatar
qinsoon committed
181
            trace!("...serializing funcs");
qinsoon's avatar
qinsoon committed
182
183
            {
                let funcs : &HashMap<_, _> = &self.funcs.read().unwrap();
184
                try!(s.emit_struct_field("funcs", field_i, |s| {
qinsoon's avatar
qinsoon committed
185
186
187
188
189
190
191
192
193
194
195
196
                    s.emit_map(funcs.len(), |s| {
                        let mut i = 0;
                        for (k,v) in funcs.iter() {
                            s.emit_map_elt_key(i, |s| k.encode(s)).ok();
                            let func : &MuFunction = &v.read().unwrap();
                            s.emit_map_elt_val(i, |s| func.encode(s)).ok();
                            i += 1;
                        }
                        Ok(())
                    })
                }));
            }
197
            field_i += 1;
qinsoon's avatar
qinsoon committed
198
199
            
            // func_vers
qinsoon's avatar
qinsoon committed
200
            trace!("...serializing func_vers");
qinsoon's avatar
qinsoon committed
201
202
            {
                let func_vers : &HashMap<_, _> = &self.func_vers.read().unwrap();
203
                try!(s.emit_struct_field("func_vers", field_i, |s| {
qinsoon's avatar
qinsoon committed
204
205
206
207
208
209
210
211
212
213
214
215
                    s.emit_map(func_vers.len(), |s| {
                        let mut i = 0;
                        for (k, v) in func_vers.iter() {
                            try!(s.emit_map_elt_key(i, |s| k.encode(s)));
                            let func_ver : &MuFunctionVersion = &v.read().unwrap();
                            try!(s.emit_map_elt_val(i, |s| func_ver.encode(s)));
                            i += 1;
                        }
                        Ok(())
                    })
                }));
            }
216
217
            field_i += 1;

qinsoon's avatar
qinsoon committed
218
            // primordial
qinsoon's avatar
qinsoon committed
219
            trace!("...serializing primordial");
qinsoon's avatar
qinsoon committed
220
221
            {
                let primordial = &self.primordial.read().unwrap();
222
                try!(s.emit_struct_field("primordial", field_i, |s| primordial.encode(s)));
qinsoon's avatar
qinsoon committed
223
            }
224
            field_i += 1;
qinsoon's avatar
qinsoon committed
225
226
            
            // is_running
qinsoon's avatar
qinsoon committed
227
            trace!("...serializing is_running");
qinsoon's avatar
qinsoon committed
228
            {
229
                try!(s.emit_struct_field("is_running", field_i, |s| self.is_running.load(Ordering::SeqCst).encode(s)));
230
            }
231
            field_i += 1;
qinsoon's avatar
qinsoon committed
232
233
234
235
236
237
238

            // options
            trace!("...serializing vm_options");
            {
                try!(s.emit_struct_field("vm_options", field_i, |s| self.vm_options.encode(s)));
            }
            field_i += 1;
239
            
qinsoon's avatar
qinsoon committed
240
            // compiled_funcs
qinsoon's avatar
qinsoon committed
241
            trace!("...serializing compiled_funcs");
qinsoon's avatar
qinsoon committed
242
243
            {
                let compiled_funcs : &HashMap<_, _> = &self.compiled_funcs.read().unwrap();
244
                try!(s.emit_struct_field("compiled_funcs", field_i, |s| {
qinsoon's avatar
qinsoon committed
245
246
247
248
249
250
251
252
253
254
255
256
                    s.emit_map(compiled_funcs.len(), |s| {
                        let mut i = 0;
                        for (k, v) in compiled_funcs.iter() {
                            try!(s.emit_map_elt_key(i, |s| k.encode(s)));
                            let compiled_func : &CompiledFunction = &v.read().unwrap();
                            try!(s.emit_map_elt_val(i, |s| compiled_func.encode(s)));
                            i += 1;
                        }
                        Ok(())
                    })
                }));
            }
257
            field_i += 1;
qinsoon's avatar
qinsoon committed
258
            
qinsoon's avatar
qinsoon committed
259
            trace!("serializing finished");
260
261
262
            Ok(())
        })
    }
qinsoon's avatar
qinsoon committed
263
264
}

qinsoon's avatar
qinsoon committed
265
266
impl Decodable for VM {
    fn decode<D: Decoder>(d: &mut D) -> Result<VM, D::Error> {
267
268
269
        let mut field_i = 0;

        d.read_struct("VM", VM_SERIALIZE_FIELDS + 2, |d| {
qinsoon's avatar
qinsoon committed
270
            // next_id
271
            let next_id = try!(d.read_struct_field("next_id", field_i, |d| {
qinsoon's avatar
qinsoon committed
272
273
                d.read_usize()
            }));
274
            field_i += 1;
qinsoon's avatar
qinsoon committed
275
276
            
            // id_name_map
277
278
279
            let id_name_map = try!(d.read_struct_field("id_name_map", field_i, |d| Decodable::decode(d)));
            field_i += 1;

qinsoon's avatar
qinsoon committed
280
            // name_id_map
281
282
            let name_id_map = try!(d.read_struct_field("name_id_map", field_i, |d| Decodable::decode(d)));
            field_i += 1;
qinsoon's avatar
qinsoon committed
283
284
            
            // types
285
286
287
288
            let types = try!(d.read_struct_field("types", field_i, |d| Decodable::decode(d)));
            field_i += 1;

            // struct tag map
qinsoon's avatar
qinsoon committed
289
            {
290
                let mut struct_tag_map : HashMap<MuName, StructType_> = try!(d.read_struct_field("struct_tag_map", field_i, |d| Decodable::decode(d)));
qinsoon's avatar
qinsoon committed
291
292
293
294
295
296
                
                let mut map_guard = types::STRUCT_TAG_MAP.write().unwrap();
                map_guard.clear();
                for (k, v) in struct_tag_map.drain() {
                    map_guard.insert(k, v);
                }
297
298
299
300
301
302
303
304
305
306
307
308
309
                field_i += 1;
            }

            // hybrid tag map
            {
                let mut hybrid_tag_map : HashMap<MuName, HybridType_> = try!(d.read_struct_field("hybrid_tag_map", field_i, |d| Decodable::decode(d)));

                let mut map_guard = types::HYBRID_TAG_MAP.write().unwrap();
                map_guard.clear();
                for (k, v) in hybrid_tag_map.drain() {
                    map_guard.insert(k, v);
                }
                field_i += 1;
qinsoon's avatar
qinsoon committed
310
            }
qinsoon's avatar
qinsoon committed
311
312
            
            // backend_type_info
313
314
            let backend_type_info = try!(d.read_struct_field("backend_type_info", field_i, |d| Decodable::decode(d)));
            field_i += 1;
qinsoon's avatar
qinsoon committed
315
316
            
            // constants
317
318
            let constants = try!(d.read_struct_field("constants", field_i, |d| Decodable::decode(d)));
            field_i += 1;
qinsoon's avatar
qinsoon committed
319
320
            
            // globals
321
322
            let globals = try!(d.read_struct_field("globals", field_i, |d| Decodable::decode(d)));
            field_i += 1;
qinsoon's avatar
qinsoon committed
323
324
            
            // func sigs
325
326
            let func_sigs = try!(d.read_struct_field("func_sigs", field_i, |d| Decodable::decode(d)));
            field_i += 1;
qinsoon's avatar
qinsoon committed
327
328
            
            // funcs
329
            let funcs = try!(d.read_struct_field("funcs", field_i, |d| {
qinsoon's avatar
qinsoon committed
330
331
332
333
334
335
336
337
338
339
                d.read_map(|d, len| {
                    let mut map = HashMap::new();
                    for i in 0..len {
                        let key = try!(d.read_map_elt_key(i, |d| Decodable::decode(d)));
                        let val = RwLock::new(try!(d.read_map_elt_val(i, |d| Decodable::decode(d))));
                        map.insert(key, val);
                    }
                    Ok(map)
                })
            }));
340
            field_i += 1;
qinsoon's avatar
qinsoon committed
341
342
            
            // func_vers
343
            let func_vers = try!(d.read_struct_field("func_vers", field_i, |d| {
qinsoon's avatar
qinsoon committed
344
345
346
347
348
349
350
351
352
353
                d.read_map(|d, len| {
                    let mut map = HashMap::new();
                    for i in 0..len {
                        let key = try!(d.read_map_elt_key(i, |d| Decodable::decode(d)));
                        let val = RwLock::new(try!(d.read_map_elt_val(i, |d| Decodable::decode(d))));
                        map.insert(key, val);
                    }
                    Ok(map)
                })
            }));
354
            field_i += 1;
qinsoon's avatar
qinsoon committed
355
356
            
            // primordial
357
358
            let primordial = try!(d.read_struct_field("primordial", field_i, |d| Decodable::decode(d)));
            field_i += 1;
qinsoon's avatar
qinsoon committed
359
360

            // is_running
361
362
            let is_running = try!(d.read_struct_field("is_running", field_i, |d| Decodable::decode(d)));
            field_i += 1;
qinsoon's avatar
qinsoon committed
363
364
365
366

            // vm_options
            let vm_options = try!(d.read_struct_field("vm_options", field_i, |d| Decodable::decode(d)));
            field_i += 1;
qinsoon's avatar
qinsoon committed
367
            
qinsoon's avatar
qinsoon committed
368
            // compiled funcs
369
            let compiled_funcs = try!(d.read_struct_field("compiled_funcs", field_i, |d| {
qinsoon's avatar
qinsoon committed
370
371
372
373
374
375
376
377
378
379
                d.read_map(|d, len| {
                    let mut map = HashMap::new();
                    for i in 0..len {
                        let key = try!(d.read_map_elt_key(i, |d| Decodable::decode(d)));
                        let val = RwLock::new(try!(d.read_map_elt_val(i, |d| Decodable::decode(d))));
                        map.insert(key, val);
                    }
                    Ok(map)
                })
            }));
380
            field_i += 1;
qinsoon's avatar
qinsoon committed
381
            
qinsoon's avatar
qinsoon committed
382
383
384
385
386
387
388
389
            let vm = VM{
                next_id: ATOMIC_USIZE_INIT,
                id_name_map: RwLock::new(id_name_map),
                name_id_map: RwLock::new(name_id_map),
                types: RwLock::new(types),
                backend_type_info: RwLock::new(backend_type_info),
                constants: RwLock::new(constants),
                globals: RwLock::new(globals),
390
                global_locations: RwLock::new(hashmap!{}),
qinsoon's avatar
qinsoon committed
391
392
393
394
395
                func_sigs: RwLock::new(func_sigs),
                funcs: RwLock::new(funcs),
                func_vers: RwLock::new(func_vers),
                primordial: RwLock::new(primordial),
                is_running: ATOMIC_BOOL_INIT,
qinsoon's avatar
qinsoon committed
396
                vm_options: vm_options,
397
398
                compiled_funcs: RwLock::new(compiled_funcs),
                aot_pending_funcref_store: RwLock::new(HashMap::new())
qinsoon's avatar
qinsoon committed
399
400
401
402
403
404
405
406
407
408
            };
            
            vm.next_id.store(next_id, Ordering::SeqCst);
            vm.is_running.store(is_running, Ordering::SeqCst);
            
            Ok(vm)
        })
    }
}

409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
macro_rules! gen_handle_int {
    ($fn_from: ident, $fn_to: ident, $int_ty: ty) => {
        pub fn $fn_from (&self, num: $int_ty, len: BitSize) -> APIHandleResult {
            let handle_id = self.next_id();
            self.new_handle (APIHandle {
                id: handle_id,
                v: APIHandleValue::Int(num as u64, len)
            })
        }

        pub fn $fn_to (&self, handle: APIHandleArg) -> $int_ty {
            handle.v.as_int() as $int_ty
        }
    }
}

qinsoon's avatar
qinsoon committed
425
426
impl <'a> VM {
    pub fn new() -> VM {
qinsoon's avatar
qinsoon committed
427
428
429
430
431
432
433
        VM::new_internal(VMOptions::default())
    }

    pub fn new_with_opts(str: &str) -> VM {
        VM::new_internal(VMOptions::init(str))
    }

434
    #[cfg(not(feature = "sel4-rumprun"))]
qinsoon's avatar
qinsoon committed
435
436
    fn new_internal(options: VMOptions) -> VM {
        VM::start_logging(options.flag_log_level);
qinsoon's avatar
qinsoon committed
437

qinsoon's avatar
qinsoon committed
438
        let ret = VM {
439
            next_id: ATOMIC_USIZE_INIT,
440
            is_running: ATOMIC_BOOL_INIT,
qinsoon's avatar
qinsoon committed
441
442
            vm_options: options,

qinsoon's avatar
qinsoon committed
443
444
            id_name_map: RwLock::new(HashMap::new()),
            name_id_map: RwLock::new(HashMap::new()),
qinsoon's avatar
qinsoon committed
445

qinsoon's avatar
qinsoon committed
446
            constants: RwLock::new(HashMap::new()),
qinsoon's avatar
qinsoon committed
447

qinsoon's avatar
qinsoon committed
448
            types: RwLock::new(HashMap::new()),
qinsoon's avatar
qinsoon committed
449
            backend_type_info: RwLock::new(HashMap::new()),
qinsoon's avatar
qinsoon committed
450

qinsoon's avatar
qinsoon committed
451
            globals: RwLock::new(HashMap::new()),
452
            global_locations: RwLock::new(hashmap!{}),
qinsoon's avatar
qinsoon committed
453

qinsoon's avatar
qinsoon committed
454
            func_sigs: RwLock::new(HashMap::new()),
455
            func_vers: RwLock::new(HashMap::new()),
qinsoon's avatar
qinsoon committed
456
            funcs: RwLock::new(HashMap::new()),
qinsoon's avatar
qinsoon committed
457
            compiled_funcs: RwLock::new(HashMap::new()),
qinsoon's avatar
qinsoon committed
458

459
460
461
            primordial: RwLock::new(None),

            aot_pending_funcref_store: RwLock::new(HashMap::new())
462
        };
qinsoon's avatar
qinsoon committed
463

464
        // insert all intenral types
qinsoon's avatar
qinsoon committed
465
466
467
468
469
470
        {
            let mut types = ret.types.write().unwrap();
            for ty in INTERNAL_TYPES.iter() {
                types.insert(ty.id(), ty.clone());
            }
        }
qinsoon's avatar
qinsoon committed
471

472
        ret.is_running.store(false, Ordering::SeqCst);
Kunshan Wang's avatar
Kunshan Wang committed
473
474
475
476
477

        // Does not need SeqCst.
        //
        // If VM creates Mu threads and Mu threads calls traps, the trap handler still "happens
        // after" the creation of the VM itself. Rust does not have a proper memory model, but this
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
        // is how C++ works.
        //
        // If the client needs to create client-level threads, however, the client should properly
        // synchronise at the time of inter-thread communication, rather than creation of the VM.
        ret.next_id.store(USER_ID_START, Ordering::Relaxed);

        // init types
        types::init_types();

        ret.init_runtime();

        ret
    }

    #[cfg(feature = "sel4-rumprun")]
    fn new_internal(options: VMOptions) -> VM {
        VM::start_logging(options.flag_log_level);

496
        let mut ret = VM {
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
            next_id: ATOMIC_USIZE_INIT,
            is_running: ATOMIC_BOOL_INIT,
            vm_options: options,

            id_name_map: RwLock::new(HashMap::new()),
            name_id_map: RwLock::new(HashMap::new()),

            constants: RwLock::new(HashMap::new()),

            types: RwLock::new(HashMap::new()),
            backend_type_info: RwLock::new(HashMap::new()),

            globals: RwLock::new(HashMap::new()),
            global_locations: RwLock::new(hashmap!{}),

            func_sigs: RwLock::new(HashMap::new()),
            func_vers: RwLock::new(HashMap::new()),
            funcs: RwLock::new(HashMap::new()),
            compiled_funcs: RwLock::new(HashMap::new()),

            primordial: RwLock::new(None),

            aot_pending_funcref_store: RwLock::new(HashMap::new())
        };

        // currently, the default sizes don't work on sel4-rumprun platform
        // this is due to memory allocation size limitations
        ret.vm_options.flag_gc_immixspace_size = 1<<19;
        ret.vm_options.flag_gc_lospace_size = 1<<19;

        // insert all intenral types
        {
            let mut types = ret.types.write().unwrap();
            for ty in INTERNAL_TYPES.iter() {
                types.insert(ty.id(), ty.clone());
            }
        }

        ret.is_running.store(false, Ordering::SeqCst);

        // Does not need SeqCst.
        //
        // If VM creates Mu threads and Mu threads calls traps, the trap handler still "happens
        // after" the creation of the VM itself. Rust does not have a proper memory model, but this
Kunshan Wang's avatar
Kunshan Wang committed
541
542
543
544
        // is how C++ works.
        //
        // If the client needs to create client-level threads, however, the client should properly
        // synchronise at the time of inter-thread communication, rather than creation of the VM.
545
        ret.next_id.store(USER_ID_START, Ordering::Relaxed);
qinsoon's avatar
qinsoon committed
546

547
548
549
550
        // init types
        types::init_types();

        ret.init_runtime();
qinsoon's avatar
qinsoon committed
551

552
553
        ret
    }
qinsoon's avatar
qinsoon committed
554

555
    fn init_runtime(&self) {
qinsoon's avatar
qinsoon committed
556
557
558
559
560
561
        // init log
        VM::start_logging(self.vm_options.flag_log_level);

        // init gc
        {
            let ref options = self.vm_options;
562
            gc::gc_init(options.flag_gc_immixspace_size, options.flag_gc_lospace_size, options.flag_gc_nthreads, !options.flag_gc_disable_collection);
qinsoon's avatar
qinsoon committed
563
564
565
566
567
568
569
570
571
572
573
574
        }
    }

    fn start_logging(level: MuLogLevel) {
        match level {
            MuLogLevel::None  => {},
            MuLogLevel::Error => VM::start_logging_internal(LogLevel::Error),
            MuLogLevel::Warn  => VM::start_logging_internal(LogLevel::Warn),
            MuLogLevel::Info  => VM::start_logging_internal(LogLevel::Info),
            MuLogLevel::Debug => VM::start_logging_internal(LogLevel::Debug),
            MuLogLevel::Trace => VM::start_logging_internal(LogLevel::Trace),
        }
qinsoon's avatar
qinsoon committed
575
576
577
    }

    pub fn start_logging_trace() {
qinsoon's avatar
qinsoon committed
578
579
580
581
        VM::start_logging_internal(LogLevel::Trace)
    }

    fn start_logging_internal(level: LogLevel) {
582
583
584
585
586
587
588
589
590
        use stderrlog;

        let verbose = match level {
            LogLevel::Error => 0,
            LogLevel::Warn  => 1,
            LogLevel::Info  => 2,
            LogLevel::Debug => 3,
            LogLevel::Trace => 4,
        };
qinsoon's avatar
qinsoon committed
591

592
593
594
        match stderrlog::new().verbosity(verbose).init() {
            Ok(()) => info!("logger initialized"),
            Err(e) => error!("failed to init logger, probably already initialized: {:?}", e)
qinsoon's avatar
qinsoon committed
595
596
        }
    }
597
    
598
599
600
    pub fn resume_vm(serialized_vm: &str) -> VM {
        use rustc_serialize::json;
        
qinsoon's avatar
qinsoon committed
601
        let vm : VM = json::decode(serialized_vm).unwrap();
602
        
603
        vm.init_runtime();
qinsoon's avatar
qinsoon committed
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622

        // restore gc types
        {
            let type_info_guard = vm.backend_type_info.read().unwrap();
            let mut type_info_vec: Vec<Box<BackendTypeInfo>> = type_info_guard.values().map(|x| x.clone()).collect();
            type_info_vec.sort_by(|a, b| a.gc_type.id.cmp(&b.gc_type.id));

            let mut expect_id = 0;
            for ty_info in type_info_vec.iter() {
                use runtime::mm;

                let ref gc_type = ty_info.gc_type;

                if gc_type.id != expect_id {
                    debug_assert!(expect_id < gc_type.id);

                    while expect_id < gc_type.id {
                        use runtime::mm::common::gctype::GCType;

qinsoon's avatar
qinsoon committed
623
                        mm::add_gc_type(GCType::new_noreftype(0, 8));
qinsoon's avatar
qinsoon committed
624
625
626
627
628
629
630
631
632
633
634
                        expect_id += 1;
                    }
                }

                // now expect_id == gc_type.id
                debug_assert!(expect_id == gc_type.id);

                mm::add_gc_type(gc_type.as_ref().clone());
                expect_id += 1;
            }
        }
635
636
637
638
        
        vm
    }
    
639
    pub fn next_id(&self) -> MuID {
Kunshan Wang's avatar
Kunshan Wang committed
640
641
642
        // This only needs to be atomic, and does not need to be a synchronisation operation. The
        // only requirement for IDs is that all IDs obtained from `next_id()` are different. So
        // `Ordering::Relaxed` is sufficient.
643
        self.next_id.fetch_add(1, Ordering::Relaxed)
644
645
    }
    
646
647
648
649
650
651
    pub fn run_vm(&self) {
        self.is_running.store(true, Ordering::SeqCst);
    }
    
    pub fn is_running(&self) -> bool {
        self.is_running.load(Ordering::Relaxed)
qinsoon's avatar
qinsoon committed
652
653
    }
    
654
    pub fn set_name(&self, entity: &MuEntity) {
qinsoon's avatar
qinsoon committed
655
        let id = entity.id();
656
        let name = entity.name().unwrap();
qinsoon's avatar
qinsoon committed
657
658
        
        let mut map = self.id_name_map.write().unwrap();
659
        map.insert(id, name.clone());
qinsoon's avatar
qinsoon committed
660
661
662
663
664
        
        let mut map2 = self.name_id_map.write().unwrap();
        map2.insert(name, id);
    }
    
Kunshan Wang's avatar
Kunshan Wang committed
665
    pub fn id_of_by_refstring(&self, name: &String) -> MuID {
qinsoon's avatar
qinsoon committed
666
        let map = self.name_id_map.read().unwrap();
667
668
669
670
        match map.get(name) {
            Some(id) => *id,
            None => panic!("cannot find id for name: {}", name)
        }
Kunshan Wang's avatar
Kunshan Wang committed
671
    }
672
673
674

    /// should only used by client
    /// 'name' used internally may be slightly different to remove some special symbols
Kunshan Wang's avatar
Kunshan Wang committed
675
676
    pub fn id_of(&self, name: &str) -> MuID {
        self.id_of_by_refstring(&name.to_string())
qinsoon's avatar
qinsoon committed
677
    }
678
679
680

    /// should only used by client
    /// 'name' used internally may be slightly different to remove some special symbols
qinsoon's avatar
qinsoon committed
681
682
    pub fn name_of(&self, id: MuID) -> MuName {
        let map = self.id_name_map.read().unwrap();
683
        map.get(&id).unwrap().clone()
qinsoon's avatar
qinsoon committed
684
685
    }
    
686
    pub fn declare_const(&self, entity: MuEntityHeader, ty: P<MuType>, val: Constant) -> P<Value> {
qinsoon's avatar
qinsoon committed
687
        let mut constants = self.constants.write().unwrap();
688
        let ret = P(Value{hdr: entity, ty: ty, v: Value_::Constant(val)});
689

690
        self.declare_const_internal(&mut constants, ret.id(), ret.clone());
qinsoon's avatar
qinsoon committed
691
692
693
        
        ret
    }
694
695
696
697

    fn declare_const_internal(&self, map: &mut RwLockWriteGuard<HashMap<MuID, P<Value>>>, id: MuID, val: P<Value>) {
        debug_assert!(!map.contains_key(&id));

qinsoon's avatar
qinsoon committed
698
        trace!("declare const #{} = {}", id, val);
699
700
        map.insert(id, val);
    }
qinsoon's avatar
qinsoon committed
701
    
702
703
704
705
706
707
708
    pub fn get_const(&self, id: MuID) -> P<Value> {
        let const_lock = self.constants.read().unwrap();
        match const_lock.get(&id) {
            Some(ret) => ret.clone(),
            None => panic!("cannot find const #{}", id)
        }
    }
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727

    pub fn get_const_nocheck(&self, id: MuID) -> Option<P<Value>> {
        let const_lock = self.constants.read().unwrap();
        match const_lock.get(&id) {
            Some(ret) => Some(ret.clone()),
            None => None
        }
    }

    #[cfg(feature = "aot")]
    pub fn allocate_const(&self, val: P<Value>) -> ValueLocation {
        let id = val.id();
        let name = match val.name() {
            Some(name) => format!("CONST_{}_{}", id, name),
            None => format!("CONST_{}", id)
        };

        ValueLocation::Relocatable(backend::RegGroup::GPR, name)
    }
728
    
729
    pub fn declare_global(&self, entity: MuEntityHeader, ty: P<MuType>) -> P<Value> {
qinsoon's avatar
qinsoon committed
730
        let global = P(Value{
731
732
            hdr: entity,
            ty: self.declare_type(MuEntityHeader::unnamed(self.next_id()), MuType_::iref(ty.clone())),
733
            v: Value_::Global(ty)
qinsoon's avatar
qinsoon committed
734
        });
qinsoon's avatar
qinsoon committed
735
736
        
        let mut globals = self.globals.write().unwrap();
737
        let mut global_locs = self.global_locations.write().unwrap();
738

739
        self.declare_global_internal(&mut globals, &mut global_locs, global.id(), global.clone());
qinsoon's avatar
qinsoon committed
740
        
qinsoon's avatar
qinsoon committed
741
        global
qinsoon's avatar
qinsoon committed
742
    }
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775

    fn declare_global_internal(
        &self,
        globals: &mut RwLockWriteGuard<HashMap<MuID, P<Value>>>,
        global_locs: &mut RwLockWriteGuard<HashMap<MuID, ValueLocation>>,
        id: MuID, val: P<Value>
    ) {
        self.declare_global_internal_no_alloc(globals, id, val.clone());
        self.alloc_global(global_locs, id, val);
    }

    // when bulk declaring, we hold locks for everything, we cannot resolve backend type, and do alloc
    fn declare_global_internal_no_alloc(
        &self,
        globals: &mut RwLockWriteGuard<HashMap<MuID, P<Value>>>,
        id: MuID, val: P<Value>
    ) {
        debug_assert!(!globals.contains_key(&id));

        info!("declare global #{} = {}", id, val);
        globals.insert(id, val.clone());
    }

    fn alloc_global(
        &self,
        global_locs: &mut RwLockWriteGuard<HashMap<MuID, ValueLocation>>,
        id: MuID, val: P<Value>
    ) {
        let backend_ty = self.get_backend_type_info(val.ty.get_referenced_ty().unwrap().id());
        let loc = gc::allocate_global(val, backend_ty);
        info!("allocate global #{} as {}", id, loc);
        global_locs.insert(id, loc);
    }
qinsoon's avatar
qinsoon committed
776
    
777
778
    pub fn declare_type(&self, entity: MuEntityHeader, ty: MuType_) -> P<MuType> {
        let ty = P(MuType{hdr: entity, v: ty});
qinsoon's avatar
qinsoon committed
779
        
qinsoon's avatar
qinsoon committed
780
        let mut types = self.types.write().unwrap();
781

782
        self.declare_type_internal(&mut types, ty.id(), ty.clone());
qinsoon's avatar
qinsoon committed
783
784
785
        
        ty
    }
786
787
788
789
790

    fn declare_type_internal(&self, types: &mut RwLockWriteGuard<HashMap<MuID, P<MuType>>>, id: MuID, ty: P<MuType>) {
        debug_assert!(!types.contains_key(&id));

        types.insert(id, ty.clone());
qinsoon's avatar
qinsoon committed
791

qinsoon's avatar
qinsoon committed
792
        trace!("declare type #{} = {}", id, ty);
qinsoon's avatar
qinsoon committed
793
794
795
796
        if ty.is_struct() {
            let tag = ty.get_struct_hybrid_tag().unwrap();
            let struct_map_guard = STRUCT_TAG_MAP.read().unwrap();
            let struct_inner = struct_map_guard.get(&tag).unwrap();
qinsoon's avatar
qinsoon committed
797
            trace!("  {}", struct_inner);
qinsoon's avatar
qinsoon committed
798
799
800
801
        } else if ty.is_hybrid() {
            let tag = ty.get_struct_hybrid_tag().unwrap();
            let hybrid_map_guard = HYBRID_TAG_MAP.read().unwrap();
            let hybrid_inner = hybrid_map_guard.get(&tag).unwrap();
qinsoon's avatar
qinsoon committed
802
            trace!("  {}", hybrid_inner);
qinsoon's avatar
qinsoon committed
803
        }
804
    }
qinsoon's avatar
qinsoon committed
805
    
806
807
808
809
810
811
812
813
    pub fn get_type(&self, id: MuID) -> P<MuType> {
        let type_lock = self.types.read().unwrap();
        match type_lock.get(&id) {
            Some(ret) => ret.clone(),
            None => panic!("cannot find type #{}", id)
        }
    }    
    
814
815
    pub fn declare_func_sig(&self, entity: MuEntityHeader, ret_tys: Vec<P<MuType>>, arg_tys: Vec<P<MuType>>) -> P<MuFuncSig> {
        let ret = P(MuFuncSig{hdr: entity, ret_tys: ret_tys, arg_tys: arg_tys});
816
817

        let mut func_sigs = self.func_sigs.write().unwrap();
818
        self.declare_func_sig_internal(&mut func_sigs, ret.id(), ret.clone());
qinsoon's avatar
qinsoon committed
819
820
821
        
        ret
    }
822
823
824
825
826
827
828

    fn declare_func_sig_internal(&self, sigs: &mut RwLockWriteGuard<HashMap<MuID, P<MuFuncSig>>>, id: MuID, sig: P<MuFuncSig>) {
        debug_assert!(!sigs.contains_key(&id));

        info!("declare func sig #{} = {}", id, sig);
        sigs.insert(id, sig);
    }
qinsoon's avatar
qinsoon committed
829
    
830
831
832
833
834
835
836
837
    pub fn get_func_sig(&self, id: MuID) -> P<MuFuncSig> {
        let func_sig_lock = self.func_sigs.read().unwrap();
        match func_sig_lock.get(&id) {
            Some(ret) => ret.clone(),
            None => panic!("cannot find func sig #{}", id)
        }
    }
    
838
    pub fn declare_func (&self, func: MuFunction) {
qinsoon's avatar
qinsoon committed
839
        let mut funcs = self.funcs.write().unwrap();
840
841
842
843
844
845
846
847
848

        self.declare_func_internal(&mut funcs, func.id(), func);
    }

    fn declare_func_internal(&self, funcs: &mut RwLockWriteGuard<HashMap<MuID, RwLock<MuFunction>>>, id: MuID, func: MuFunction) {
        debug_assert!(!funcs.contains_key(&id));

        info!("declare func #{} = {}", id, func);
        funcs.insert(id, RwLock::new(func));
849
    }
850
851
852
853
854
855
856
857
858

    /// this is different than vm.name_of()
    pub fn get_func_name(&self, id: MuID) -> MuName {
        let funcs_lock = self.funcs.read().unwrap();
        match funcs_lock.get(&id) {
            Some(func) => func.read().unwrap().name().unwrap(),
            None => panic!("cannot find name for Mu function #{}")
        }
    }
859
    
860
861
862
863
864
865
866
867
868
    /// The IR builder needs to look-up the function signature from the existing function ID.
    pub fn get_func_sig_for_func(&self, id: MuID) -> P<MuFuncSig> {
        let funcs_lock = self.funcs.read().unwrap();
        match funcs_lock.get(&id) {
            Some(func) => func.read().unwrap().sig.clone(),
            None => panic!("cannot find Mu function #{}", id)
        }
    }    
    
869
    pub fn define_func_version (&self, func_ver: MuFunctionVersion) {
qinsoon's avatar
qinsoon committed
870
        info!("define function version {}", func_ver);
871
        // record this version
qinsoon's avatar
qinsoon committed
872
        let func_ver_id = func_ver.id();
873
874
        {
            let mut func_vers = self.func_vers.write().unwrap();
qinsoon's avatar
qinsoon committed
875
            func_vers.insert(func_ver_id, RwLock::new(func_ver));
876
877
878
879
        }
        
        // acquire a reference to the func_ver
        let func_vers = self.func_vers.read().unwrap();
qinsoon's avatar
qinsoon committed
880
        let func_ver = func_vers.get(&func_ver_id).unwrap().write().unwrap();
881
882
883
        
        // change current version to this (obsolete old versions)
        let funcs = self.funcs.read().unwrap();
qinsoon's avatar
qinsoon committed
884
        debug_assert!(funcs.contains_key(&func_ver.func_id)); // it should be declared before defining
qinsoon's avatar
qinsoon committed
885
        let mut func = funcs.get(&func_ver.func_id).unwrap().write().unwrap();
886
        
887
888
889
890
        func.new_version(func_ver.id());
        
        // redefinition happens here
        // do stuff        
891
    }
892
893
894
895
896
897
898
899
900
901
902
903
904
905

    /// Add a new bundle into VM.
    ///
    /// This function will drain the contents of all arguments.
    ///
    /// Ideally, this function should happen atomically. e.g. The client should not see a new type
    /// added without also seeing a new function added.
    pub fn declare_many(&self,
                        new_id_name_map: &mut HashMap<MuID, MuName>,
                        new_types: &mut HashMap<MuID, P<MuType>>,
                        new_func_sigs: &mut HashMap<MuID, P<MuFuncSig>>,
                        new_constants: &mut HashMap<MuID, P<Value>>,
                        new_globals: &mut HashMap<MuID, P<Value>>,
                        new_funcs: &mut HashMap<MuID, Box<MuFunction>>,
906
907
                        new_func_vers: &mut HashMap<MuID, Box<MuFunctionVersion>>,
                        arc_vm: Arc<VM>
908
909
910
                        ) {
        // Make sure other components, if ever acquiring multiple locks at the same time, acquire
        // them in this order, to prevent deadlock.
911
912
913
914
915
916
917
918
919
        {
            let mut id_name_map = self.id_name_map.write().unwrap();
            let mut name_id_map = self.name_id_map.write().unwrap();
            let mut types = self.types.write().unwrap();
            let mut constants = self.constants.write().unwrap();
            let mut globals = self.globals.write().unwrap();
            let mut func_sigs = self.func_sigs.write().unwrap();
            let mut funcs = self.funcs.write().unwrap();
            let mut func_vers = self.func_vers.write().unwrap();
920

921
922
923
924
            for (id, name) in new_id_name_map.drain() {
                id_name_map.insert(id, name.clone());
                name_id_map.insert(name, id);
            }
925

926
927
928
            for (id, obj) in new_types.drain() {
                self.declare_type_internal(&mut types, id, obj);
            }
929

930
931
932
            for (id, obj) in new_constants.drain() {
                self.declare_const_internal(&mut constants, id, obj);
            }
933

934
935
936
937
            for (id, obj) in new_globals.drain() {
                // we bulk allocate later (since we are holding all the locks, we cannot find ty info)
                self.declare_global_internal_no_alloc(&mut globals, id, obj);
            }
938

939
940
941
            for (id, obj) in new_func_sigs.drain() {
                self.declare_func_sig_internal(&mut func_sigs, id, obj);
            }
942

943
944
945
            for (id, obj) in new_funcs.drain() {
                self.declare_func_internal(&mut funcs, id, *obj);
            }
946

947
948
949
            for (id, obj) in new_func_vers.drain() {
                let func_id = obj.func_id;
                func_vers.insert(id, RwLock::new(*obj));
950

951
952
953
954
955
956
                {
                    trace!("Adding funcver {} as a version of {}...", id, func_id);
                    let func = funcs.get_mut(&func_id).unwrap();
                    func.write().unwrap().new_version(id);
                    trace!("Added funcver {} as a version of {} {:?}.", id, func_id, func);
                }
957
958
959
            }
        }
        // Locks released here
960
961
962
963
964
965
966

        // allocate all the globals defined
        {
            let globals = self.globals.read().unwrap();
            let mut global_locs = self.global_locations.write().unwrap();

            // make sure current thread has allocator
967
            let created = unsafe {MuThread::current_thread_as_mu_thread(Address::zero(), arc_vm.clone())};
968
969
970
971

            for (id, global) in globals.iter() {
                self.alloc_global(&mut global_locs, *id, global.clone());
            }
972
973
974
975

            if created {
                unsafe {MuThread::cleanup_current_mu_thread()};
            }
976
        }
977
    }
978
    
979
    pub fn add_compiled_func (&self, func: CompiledFunction) {
qinsoon's avatar
qinsoon committed
980
        debug_assert!(self.funcs.read().unwrap().contains_key(&func.func_id));
qinsoon's avatar
qinsoon committed
981
        debug_assert!(self.func_vers.read().unwrap().contains_key(&func.func_ver_id));
qinsoon's avatar
qinsoon committed
982

qinsoon's avatar
qinsoon committed
983
        self.compiled_funcs.write().unwrap().insert(func.func_ver_id, RwLock::new(func));
qinsoon's avatar
qinsoon committed
984
985
    }
    
qinsoon's avatar
qinsoon committed
986
    pub fn get_backend_type_info(&self, tyid: MuID) -> Box<BackendTypeInfo> {        
qinsoon's avatar
qinsoon committed
987
988
989
        {
            let read_lock = self.backend_type_info.read().unwrap();
        
990
            match read_lock.get(&tyid) {
qinsoon's avatar
qinsoon committed
991
992
993
994
                Some(info) => {return info.clone();},
                None => {}
            }
        }
995
996

        let types = self.types.read().unwrap();
qinsoon's avatar
qinsoon committed
997
998
999
1000
        let ty = match types.get(&tyid) {
            Some(ty) => ty,
            None => panic!("invalid type id during get_backend_type_info(): {}", tyid)
        };
qinsoon's avatar
qinsoon committed
1001
        let resolved = Box::new(backend::resolve_backend_type_info(ty, self));
qinsoon's avatar
qinsoon committed
1002
1003
        
        let mut write_lock = self.backend_type_info.write().unwrap();
1004
        write_lock.insert(tyid, resolved.clone());
qinsoon's avatar
qinsoon committed
1005
1006
1007
1008
        
        resolved        
    }
    
qinsoon's avatar
qinsoon committed
1009
1010
1011
1012
    pub fn get_type_size(&self, tyid: MuID) -> ByteSize {
        self.get_backend_type_info(tyid).size
    }
    
qinsoon's avatar
qinsoon committed
1013
    pub fn globals(&self) -> &RwLock<HashMap<MuID, P<Value>>> {
qinsoon's avatar
qinsoon committed
1014
1015
1016
        &self.globals
    }
    
qinsoon's avatar
qinsoon committed
1017
    pub fn funcs(&self) -> &RwLock<HashMap<MuID, RwLock<MuFunction>>> {
qinsoon's avatar
qinsoon committed
1018
        &self.funcs
1019
    }
1020
    
qinsoon's avatar
qinsoon committed
1021
    pub fn func_vers(&self) -> &RwLock<HashMap<MuID, RwLock<MuFunctionVersion>>> {
1022
1023
        &self.func_vers
    }
qinsoon's avatar
qinsoon committed
1024
1025
1026
1027
1028
1029
1030
1031
1032