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 62.2 KB
Newer Older
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano 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
16
use std::collections::HashMap;

17
use rodal;
qinsoon's avatar
qinsoon committed
18
use ast::ptr::*;
qinsoon's avatar
qinsoon committed
19
use ast::ir::*;
20
use ast::inst::*;
qinsoon's avatar
qinsoon committed
21
use ast::types;
qinsoon's avatar
qinsoon committed
22
use ast::types::*;
qinsoon's avatar
qinsoon committed
23
use compiler::{Compiler, CompilerPolicy};
qinsoon's avatar
qinsoon committed
24
use compiler::backend;
qinsoon's avatar
qinsoon committed
25
use compiler::backend::BackendType;
qinsoon's avatar
qinsoon committed
26
use compiler::machine_code::CompiledFunction;
27

28
use runtime::thread::*;
29
use runtime::*;
qinsoon's avatar
qinsoon committed
30
use utils::ByteSize;
31
use utils::BitSize;
32
use utils::Address;
33
use runtime::mm as gc;
34
use vm::handle::*;
qinsoon's avatar
qinsoon committed
35
36
use vm::vm_options::VMOptions;
use vm::vm_options::MuLogLevel;
37

qinsoon's avatar
qinsoon committed
38
use log::LogLevel;
39
use std::sync::Arc;
qinsoon's avatar
qinsoon committed
40
use std::sync::RwLock;
41
use std::sync::RwLockWriteGuard;
42
use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
43

44
45
use std;
use utils::bit_utils::{bits_ones, u64_asr};
qinsoon's avatar
qinsoon committed
46

qinsoon's avatar
qinsoon committed
47
48
49
/// The VM struct. This stores metadata for the currently running Zebu instance.
/// This struct gets persisted in the boot image, and when the boot image is loaded,
/// everything should be back to the same status as before persisting.
qinsoon's avatar
[wip]    
qinsoon committed
50
///
qinsoon's avatar
qinsoon committed
51
52
53
/// This struct is usually used as Arc<VM> so it can be shared among threads. The
/// Arc<VM> is stored in every thread local of a Mu thread, so that they can refer
/// to the VM easily.
qinsoon's avatar
[wip]    
qinsoon committed
54
///
qinsoon's avatar
qinsoon committed
55
56
57
58
/// We are using fine-grained lock on VM to allow mutability on different fields in VM.
/// Also we use two-level locks for some data structures such as MuFunction/
/// MuFunctionVersion/CompiledFunction so that we can mutate on two
/// different functions/funcvers/etc at the same time.
qinsoon's avatar
[wip]    
qinsoon committed
59
60
61
62

//  FIXME: However, there are problems with fine-grained lock design,
//  and we will need to rethink. See Issue #2.
//  TODO: besides fields in VM, there are some 'globals' we need to persist
qinsoon's avatar
qinsoon committed
63
64
65
66
//  such as STRUCT_TAG_MAP, INTERNAL_ID and internal types from ir crate. The point is
//  ir crate should be independent and self-contained. But when persisting the 'world',
//  besides persisting VM struct (containing most of the 'world'), we also need to
//  specifically persist those globals.
67
pub struct VM { // The comments are the offset into the struct
68
    // ---serialize---
69

qinsoon's avatar
[wip]    
qinsoon committed
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
    /// next MuID to assign
    next_id: AtomicUsize,                                       // +0
    /// a map from MuID to MuName (for client to query)
    id_name_map: RwLock<HashMap<MuID, MuName>>,                 // +8
    /// a map from MuName to ID (for client to query)
    name_id_map: RwLock<HashMap<MuName, MuID>>,                 // +64
    /// types declared to the VM
    types: RwLock<HashMap<MuID, P<MuType>>>,                    // +120
    /// types that are resolved as BackendType
    backend_type_info: RwLock<HashMap<MuID, Box<BackendType>>>, // +176
    /// constants declared to the VM
    constants: RwLock<HashMap<MuID, P<Value>>>,                 // +232
    /// globals declared to the VM
    globals: RwLock<HashMap<MuID, P<Value>>>,                   // +288
    /// function signatures declared
    func_sigs: RwLock<HashMap<MuID, P<MuFuncSig>>>,             // +400
    /// functions declared to the VM
    funcs: RwLock<HashMap<MuID, RwLock<MuFunction>>>,           // +456
    /// primordial function that is set to make boot image
    pub primordial: RwLock<Option<PrimordialThreadInfo>>,       // +568
    /// current options for this VM
    pub vm_options: VMOptions,                                  // +624
92

93
    // ---partially serialize---
qinsoon's avatar
[wip]    
qinsoon committed
94
95
    /// compiled functions
    /// (we are not persisting generated code with compiled function)
96
    compiled_funcs: RwLock<HashMap<MuID, RwLock<CompiledFunction>>>, // +728
97

qinsoon's avatar
vm.rs    
qinsoon committed
98
    /// (callsite, catch block) pair for function versions
99
    exception_table: RwLock<HashMap<MuID, HashMap<MuName, MuName>>>, // +784
100

101
    // ---do not serialize---
qinsoon's avatar
vm.rs    
qinsoon committed
102
103
104
    /// global cell locations. We use this map to create handles for global cells,
    /// or dump globals into boot image. (this map does not get persisted because
    /// the location is changed in different runs)
105
106
    pub global_locations: RwLock<HashMap<MuID, ValueLocation>>,
    func_vers: RwLock<HashMap<MuID, RwLock<MuFunctionVersion>>>,
107

qinsoon's avatar
[wip]    
qinsoon committed
108
109
110
111
    /// all the funcref that clients want to store for AOT which are pending stores
    /// For AOT scenario, when client tries to store funcref to the heap, the store
    /// happens before we have an actual address for the function so we store a fake
    /// funcref and when generating boot image, we fix the funcref with a relocatable symbol
112
113
    aot_pending_funcref_store: RwLock<HashMap<Address, ValueLocation>>,

qinsoon's avatar
vm.rs    
qinsoon committed
114
115
116
    /// runtime exception table for exception handling
    /// a map from callsite address to (catch block address, CompiledFunction ptr) pair
    //  TODO: probably we should remove the pointer (its unsafe), thats why we need Sync/Send for VM
117
118
    pub compiled_exception_table: RwLock<HashMap<Address, (Address, *const CompiledFunction)>> // 896
}
qinsoon's avatar
vm.rs    
qinsoon committed
119

120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
unsafe impl rodal::Dump for VM {
    fn dump<D: ?Sized + rodal::Dumper>(&self, dumper: &mut D) {
        dumper.debug_record("VM", "dump");

        dumper.dump_object(&self.next_id);
        dumper.dump_object(&self.id_name_map);
        dumper.dump_object(&self.name_id_map);
        dumper.dump_object(&self.types);
        dumper.dump_object(&self.backend_type_info);
        dumper.dump_object(&self.constants);
        dumper.dump_object(&self.globals);
        dumper.dump_object(&self.func_sigs);
        dumper.dump_object(&self.funcs);
        dumper.dump_object(&self.primordial);
        dumper.dump_object(&self.vm_options);
        dumper.dump_object(&self.compiled_funcs);
        dumper.dump_object(&self.exception_table);

138
139
140
141
142
143
144
145
146
147
148
        // Dump empty maps so that we can safely read and modify them once loaded
        dumper.dump_padding(&self.global_locations);
        dumper.dump_object_here(&RwLock::new(rodal::EmptyHashMap::<MuID, ValueLocation>::new()));

        dumper.dump_padding(&self.func_vers);
        dumper.dump_object_here(&RwLock::new(rodal::EmptyHashMap::<MuID, RwLock<MuFunctionVersion>>::new()));

        dumper.dump_padding(&self.aot_pending_funcref_store);
        dumper.dump_object_here(&RwLock::new(rodal::EmptyHashMap::<Address, ValueLocation>::new()));

        // Dump an emepty hashmap for the other hashmaps
149
        dumper.dump_padding(&self.compiled_exception_table);
150
        dumper.dump_object_here(&RwLock::new(rodal::EmptyHashMap::<Address, (Address, *const CompiledFunction)>::new()));
151
    }
152
}
153

qinsoon's avatar
[wip]    
qinsoon committed
154
155
// *const CompiledFunction appears in compiled_exception_table makes
// the VM unsafe to Sync/Send. We explicitly mark it safe
156
157
unsafe impl Sync for VM {}
unsafe impl Send for VM {}
158

qinsoon's avatar
[wip]    
qinsoon committed
159
160
161
162
163
164
165
166
/// a fake funcref to store for AOT when client tries to store a funcref via API
//  For AOT scenario, when client tries to store funcref to the heap, the store
//  happens before we have an actual address for the function so we store a fake
//  funcref and when generating boot image, we fix the funcref with a relocatable symbol
const PENDING_FUNCREF : u64 = {
    use std::u64;
    u64::MAX
};
167

qinsoon's avatar
[wip]    
qinsoon committed
168
/// a macro to generate int8/16/32/64 from/to API calls
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
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
185
impl <'a> VM {
qinsoon's avatar
[wip]    
qinsoon committed
186
    /// creates a VM with default options
qinsoon's avatar
qinsoon committed
187
    pub fn new() -> VM {
qinsoon's avatar
qinsoon committed
188
189
190
        VM::new_internal(VMOptions::default())
    }

qinsoon's avatar
[wip]    
qinsoon committed
191
    /// creates a VM with specified options
qinsoon's avatar
qinsoon committed
192
193
194
195
    pub fn new_with_opts(str: &str) -> VM {
        VM::new_internal(VMOptions::init(str))
    }

qinsoon's avatar
[wip]    
qinsoon committed
196
    /// internal function to create a VM with options
qinsoon's avatar
qinsoon committed
197
198
    fn new_internal(options: VMOptions) -> VM {
        VM::start_logging(options.flag_log_level);
qinsoon's avatar
qinsoon committed
199

qinsoon's avatar
qinsoon committed
200
        let ret = VM {
201
            next_id: ATOMIC_USIZE_INIT,
qinsoon's avatar
qinsoon committed
202
            vm_options: options,
qinsoon's avatar
qinsoon committed
203
204
            id_name_map: RwLock::new(HashMap::new()),
            name_id_map: RwLock::new(HashMap::new()),
qinsoon's avatar
qinsoon committed
205
206
            constants: RwLock::new(HashMap::new()),
            types: RwLock::new(HashMap::new()),
qinsoon's avatar
qinsoon committed
207
            backend_type_info: RwLock::new(HashMap::new()),
qinsoon's avatar
qinsoon committed
208
            globals: RwLock::new(HashMap::new()),
209
            global_locations: RwLock::new(hashmap!{}),
qinsoon's avatar
qinsoon committed
210
            func_sigs: RwLock::new(HashMap::new()),
211
            func_vers: RwLock::new(HashMap::new()),
qinsoon's avatar
qinsoon committed
212
            funcs: RwLock::new(HashMap::new()),
qinsoon's avatar
qinsoon committed
213
            compiled_funcs: RwLock::new(HashMap::new()),
214
            exception_table: RwLock::new(HashMap::new()),
215
            primordial: RwLock::new(None),
216
            aot_pending_funcref_store: RwLock::new(HashMap::new()),
217
            compiled_exception_table: RwLock::new(HashMap::new()),
218
        };
qinsoon's avatar
qinsoon committed
219

220
        // insert all internal types
qinsoon's avatar
qinsoon committed
221
222
223
224
225
226
        {
            let mut types = ret.types.write().unwrap();
            for ty in INTERNAL_TYPES.iter() {
                types.insert(ty.id(), ty.clone());
            }
        }
qinsoon's avatar
qinsoon committed
227

qinsoon's avatar
[wip]    
qinsoon committed
228
        // starts allocating ID from USER_ID_START
229
        ret.next_id.store(USER_ID_START, Ordering::Relaxed);
qinsoon's avatar
qinsoon committed
230

231
232
233
        // init types
        types::init_types();

qinsoon's avatar
[wip]    
qinsoon committed
234
        // init runtime
235
        ret.init_runtime();
qinsoon's avatar
qinsoon committed
236

237
238
        ret
    }
qinsoon's avatar
qinsoon committed
239

qinsoon's avatar
[wip]    
qinsoon committed
240
    /// initializes runtime
241
    fn init_runtime(&self) {
qinsoon's avatar
qinsoon committed
242
243
244
        // init gc
        {
            let ref options = self.vm_options;
qinsoon's avatar
[wip]    
qinsoon committed
245
246
247
248
            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
249
250
251
        }
    }

qinsoon's avatar
[wip]    
qinsoon committed
252
    /// starts logging based on MuLogLevel flag
qinsoon's avatar
qinsoon committed
253
    fn start_logging(level: MuLogLevel) {
254
        use std::env;
qinsoon's avatar
qinsoon committed
255
256
257
258
259
260
261
        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),
262
263
264
265
266
267
            MuLogLevel::Env => {
                match env::var("MU_LOG_LEVEL") {
                    Ok(s) => VM::start_logging(MuLogLevel::from_string(s)),
                    _ => {} // Don't log
                }
            },
qinsoon's avatar
qinsoon committed
268
        }
qinsoon's avatar
qinsoon committed
269
270
    }

qinsoon's avatar
[wip]    
qinsoon committed
271
    /// starts trace-level logging
qinsoon's avatar
qinsoon committed
272
    pub fn start_logging_trace() {
qinsoon's avatar
qinsoon committed
273
274
        VM::start_logging_internal(LogLevel::Trace)
    }
qinsoon's avatar
[wip]    
qinsoon committed
275
276

    /// starts logging based on MU_LOG_LEVEL environment variable
277
278
279
    pub fn start_logging_env() {
        VM::start_logging(MuLogLevel::Env)
    }
qinsoon's avatar
qinsoon committed
280

qinsoon's avatar
[wip]    
qinsoon committed
281
282
    /// starts logging based on Rust's LogLevel
    /// (this function actually initializes logger and deals with error)
qinsoon's avatar
qinsoon committed
283
    fn start_logging_internal(level: LogLevel) {
284
285
286
287
288
289
290
291
292
        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
293

294
295
296
        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
297
298
        }
    }
299

qinsoon's avatar
[wip]    
qinsoon committed
300
301
    /// adds an exception callsite and catch block
    /// (later we will use this info to build an exception table for unwinding use)
302
    pub fn add_exception_callsite(&self, callsite: MuName, catch: MuName, fv: MuID) {
303
304
305
306
307
308
309
310
311
312
        let mut table = self.exception_table.write().unwrap();

        if table.contains_key(&fv) {
            let mut map = table.get_mut(&fv).unwrap();
            map.insert(callsite, catch);
        } else {
            let mut new_map = HashMap::new();
            new_map.insert(callsite, catch);
            table.insert(fv, new_map);
        };
313
314
    }

qinsoon's avatar
[wip]    
qinsoon committed
315
316
    /// resumes persisted VM. Ideally the VM should be back to the status when we start
    /// persisting it except a few fields that we do not want to persist.
317
    pub fn resume_vm(dumped_vm: *mut Arc<VM>) -> Arc<VM> {
qinsoon's avatar
[wip]    
qinsoon committed
318
        // load the vm back
319
        let vm = unsafe{rodal::load_asm_pointer_move(dumped_vm)};
qinsoon's avatar
[wip]    
qinsoon committed
320
321

        // initialize runtime
322
        vm.init_runtime();
qinsoon's avatar
qinsoon committed
323

qinsoon's avatar
[wip]    
qinsoon committed
324
325
326
        // construct exception table
        vm.build_exception_table();

qinsoon's avatar
qinsoon committed
327
328
329
        // restore gc types
        {
            let type_info_guard = vm.backend_type_info.read().unwrap();
qinsoon's avatar
qinsoon committed
330
            let mut type_info_vec: Vec<Box<BackendType>> = type_info_guard.values().map(|x| x.clone()).collect();
qinsoon's avatar
qinsoon committed
331
332
333
334
335
336
337
338
339
340
341
342
343
344
            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
345
                        mm::add_gc_type(GCType::new_noreftype(0, 8));
qinsoon's avatar
qinsoon committed
346
347
348
349
350
351
352
353
354
355
356
                        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;
            }
        }
357

358
359
        vm
    }
360

qinsoon's avatar
[wip]    
qinsoon committed
361
362
363
364
365
    /// builds a succinct exception table for fast query during exception unwinding
    /// We need this step because for AOT compilation, we do not know symbol address at compile,
    /// and resolving symbol address during exception handling is expensive. Thus when boot image
    /// gets executed, we first resolve symbols and store the results in another table for fast
    /// query.
366
367
368
369
370
371
372
373
374
375
376
    pub fn build_exception_table(&self) {
        let exception_table = self.exception_table.read().unwrap();
        let compiled_funcs = self.compiled_funcs.read().unwrap();
        let mut compiled_exception_table = self.compiled_exception_table.write().unwrap();

        for (fv, map) in exception_table.iter() {
            let ref compiled_func = *compiled_funcs.get(fv).unwrap().read().unwrap();

            for (callsite, catch_block) in map.iter() {
                let catch_addr = if catch_block.is_empty() {
                    unsafe {Address::zero()}
377
                } else {
378
                    resolve_symbol(catch_block.clone())
379
380
                };

381
                compiled_exception_table.insert(resolve_symbol(callsite.clone()), (catch_addr, &*compiled_func));
382
383
            }
        }
384
    }
qinsoon's avatar
[wip]    
qinsoon committed
385
386

    /// returns a valid ID for use next
387
    pub fn next_id(&self) -> MuID {
Kunshan Wang's avatar
Kunshan Wang committed
388
389
390
        // 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.
391
        self.next_id.fetch_add(1, Ordering::Relaxed)
392
    }
qinsoon's avatar
[wip]    
qinsoon committed
393

394
395
396
    /// are we doing AOT compilation? (feature = aot when building Zebu)
    pub fn is_doing_aot(&self) -> bool {
        return cfg!(feature = "aot")
397
    }
398
399
400
401

    /// are we doing JIT compilation? (feature = jit when building Zebu)
    pub fn is_doing_jit(&self) -> bool {
        return cfg!(feature = "jit")
qinsoon's avatar
qinsoon committed
402
    }
403
404

    /// informs VM about a client-supplied name
405
    pub fn set_name(&self, entity: &MuEntity) {
qinsoon's avatar
qinsoon committed
406
        let id = entity.id();
407
        let name = entity.name().unwrap();
qinsoon's avatar
qinsoon committed
408
409
        
        let mut map = self.id_name_map.write().unwrap();
410
        map.insert(id, name.clone());
qinsoon's avatar
qinsoon committed
411
412
413
414
        
        let mut map2 = self.name_id_map.write().unwrap();
        map2.insert(name, id);
    }
qinsoon's avatar
vm.rs    
qinsoon committed
415
416
417
418
419

    /// returns Mu ID for a client-supplied name
    /// This function should only used by client, 'name' used internally may be slightly different
    /// due to removal of some special symbols in the MuName. See name_check() in ir.rs
    pub fn id_of(&self, name: &str) -> MuID {
qinsoon's avatar
qinsoon committed
420
        let map = self.name_id_map.read().unwrap();
421
422
423
424
        match map.get(name) {
            Some(id) => *id,
            None => panic!("cannot find id for name: {}", name)
        }
Kunshan Wang's avatar
Kunshan Wang committed
425
    }
426

qinsoon's avatar
vm.rs    
qinsoon committed
427
428
429
    /// returns the client-supplied Mu name for Mu ID
    /// This function should only used by client, 'name' used internally may be slightly different
    /// due to removal of some special symbols in the MuName. See name_check() in ir.rs
qinsoon's avatar
qinsoon committed
430
431
    pub fn name_of(&self, id: MuID) -> MuName {
        let map = self.id_name_map.read().unwrap();
432
        map.get(&id).unwrap().clone()
qinsoon's avatar
qinsoon committed
433
    }
qinsoon's avatar
vm.rs    
qinsoon committed
434
435

    /// declares a constant
436
437
    pub fn declare_const(&self, entity: MuEntityHeader, ty: P<MuType>, val: Constant) -> P<Value> {
        let ret = P(Value{hdr: entity, ty: ty, v: Value_::Constant(val)});
438

qinsoon's avatar
vm.rs    
qinsoon committed
439
        let mut constants = self.constants.write().unwrap();
440
        self.declare_const_internal(&mut constants, ret.id(), ret.clone());
qinsoon's avatar
qinsoon committed
441
442
443
        
        ret
    }
444

qinsoon's avatar
vm.rs    
qinsoon committed
445
    /// adds a constant to the map (already acquired lock)
446
447
448
    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
vm.rs    
qinsoon committed
449
        info!("declare const #{} = {}", id, val);
450
451
        map.insert(id, val);
    }
qinsoon's avatar
vm.rs    
qinsoon committed
452
453

    /// gets the constant P<Value> for a given Mu ID, panics if there is no type with the ID
454
455
456
457
458
459
460
    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)
        }
    }
461

qinsoon's avatar
vm.rs    
qinsoon committed
462
463
    /// allocates memory for a constant that needs to be put in memory
    /// For AOT, we simply create a label for it, and let code emitter allocate the memory
464
465
466
467
468
469
470
471
472
473
    #[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)
    }
qinsoon's avatar
vm.rs    
qinsoon committed
474
475

    /// declares a global
476
    pub fn declare_global(&self, entity: MuEntityHeader, ty: P<MuType>) -> P<Value> {
qinsoon's avatar
vm.rs    
qinsoon committed
477
        // create iref value for the global
qinsoon's avatar
qinsoon committed
478
        let global = P(Value{
479
480
            hdr: entity,
            ty: self.declare_type(MuEntityHeader::unnamed(self.next_id()), MuType_::iref(ty.clone())),
481
            v: Value_::Global(ty)
qinsoon's avatar
qinsoon committed
482
        });
qinsoon's avatar
vm.rs    
qinsoon committed
483

qinsoon's avatar
qinsoon committed
484
        let mut globals = self.globals.write().unwrap();
485
        let mut global_locs = self.global_locations.write().unwrap();
486
        self.declare_global_internal(&mut globals, &mut global_locs, global.id(), global.clone());
qinsoon's avatar
qinsoon committed
487
        
qinsoon's avatar
qinsoon committed
488
        global
qinsoon's avatar
qinsoon committed
489
    }
490

qinsoon's avatar
vm.rs    
qinsoon committed
491
    /// adds the global to the map (already acquired lock), and allocates memory for it
492
493
494
495
496
497
498
499
500
501
    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);
    }

qinsoon's avatar
vm.rs    
qinsoon committed
502
503
504
    /// adds the global to the map (already acquired lock)
    /// when bulk declaring, we hold locks for everything, we cannot resolve backend type and do alloc
    /// so we add globals to the map, and then allocate them later
505
506
507
508
509
510
511
512
513
514
515
    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());
    }

qinsoon's avatar
vm.rs    
qinsoon committed
516
    /// allocates memory for a global cell
517
518
519
520
521
    fn alloc_global(
        &self,
        global_locs: &mut RwLockWriteGuard<HashMap<MuID, ValueLocation>>,
        id: MuID, val: P<Value>
    ) {
522
        let backend_ty = self.get_backend_type_info(val.ty.get_referent_ty().unwrap().id());
523
        let loc = gc::allocate_global(val, backend_ty);
qinsoon's avatar
vm.rs    
qinsoon committed
524
        trace!("allocate global #{} as {}", id, loc);
525
526
        global_locs.insert(id, loc);
    }
qinsoon's avatar
vm.rs    
qinsoon committed
527
528

    /// declares a type
529
530
    pub fn declare_type(&self, entity: MuEntityHeader, ty: MuType_) -> P<MuType> {
        let ty = P(MuType{hdr: entity, v: ty});
531

qinsoon's avatar
vm.rs    
qinsoon committed
532
        let mut types = self.types.write().unwrap();
533
        self.declare_type_internal(&mut types, ty.id(), ty.clone());
qinsoon's avatar
qinsoon committed
534
535
536
        
        ty
    }
537

qinsoon's avatar
vm.rs    
qinsoon committed
538
    /// adds the type to the map (already acquired lock)
539
540
541
542
    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
vm.rs    
qinsoon committed
543
        info!("declare type #{} = {}", id, ty);
qinsoon's avatar
qinsoon committed
544

qinsoon's avatar
vm.rs    
qinsoon committed
545
        // for struct/hybrid, also adds to struct/hybrid tag map
qinsoon's avatar
qinsoon committed
546
547
548
549
        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
550
            trace!("  {}", struct_inner);
qinsoon's avatar
qinsoon committed
551
552
553
554
        } 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
555
            trace!("  {}", hybrid_inner);
qinsoon's avatar
qinsoon committed
556
        }
557
    }
qinsoon's avatar
vm.rs    
qinsoon committed
558
559

    /// gets the type for a given Mu ID, panics if there is no type with the ID
560
561
562
563
564
565
566
    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)
        }
    }    
qinsoon's avatar
vm.rs    
qinsoon committed
567
568

    /// declares a function signature
569
570
    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});
571
572

        let mut func_sigs = self.func_sigs.write().unwrap();
573
        self.declare_func_sig_internal(&mut func_sigs, ret.id(), ret.clone());
qinsoon's avatar
qinsoon committed
574
575
576
        
        ret
    }
577

qinsoon's avatar
vm.rs    
qinsoon committed
578
    /// adds a function signature to the map (already acquired lock)
579
580
581
582
583
584
    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
vm.rs    
qinsoon committed
585
586

    /// gets the function signature for a given ID, panics if there is no func sig with the ID
587
588
589
590
591
592
593
    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)
        }
    }
qinsoon's avatar
vm.rs    
qinsoon committed
594
595

    /// declares a Mu function
596
    pub fn declare_func (&self, func: MuFunction) {
qinsoon's avatar
qinsoon committed
597
        let mut funcs = self.funcs.write().unwrap();
598
599
600
601

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

qinsoon's avatar
vm.rs    
qinsoon committed
602
    /// adds a Mu function to the map (already acquired lock)
603
604
605
606
607
    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));
608
    }
609

qinsoon's avatar
vm.rs    
qinsoon committed
610
611
612
613
    /// gets the function name for a function (by ID), panics if there is no function with the ID
    /// Note this name is the internal name, which is different than
    /// the client-supplied name from vm.name_of()
    pub fn get_name_for_func(&self, id: MuID) -> MuName {
614
615
616
617
618
619
        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 #{}")
        }
    }
qinsoon's avatar
vm.rs    
qinsoon committed
620
621
622

    /// gets the function signature for a function (by ID), panics if there is no function with the ID
    pub fn get_sig_for_func(&self, id: MuID) -> P<MuFuncSig> {
623
624
625
626
627
        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)
        }
qinsoon's avatar
vm.rs    
qinsoon committed
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
    }

    /// gets the current function version for a Mu function (by ID)
    /// returns None if the function does not exist, or no version is defined for the function
    pub fn get_cur_version_for_func(&self, fid: MuID) -> Option<MuID> {
        let funcs_guard = self.funcs.read().unwrap();
        match funcs_guard.get(&fid) {
            Some(rwlock_func) => {
                let func_guard = rwlock_func.read().unwrap();
                func_guard.cur_ver
            },
            None => None
        }
    }

    /// gets the address as ValueLocation of a Mu function (by ID)
    pub fn get_address_for_func(&self, func_id: MuID) -> ValueLocation {
        let funcs = self.funcs.read().unwrap();
        let func : &MuFunction = &funcs.get(&func_id).unwrap().read().unwrap();

        if self.is_doing_jit() {
            unimplemented!()
        } else {
            ValueLocation::Relocatable(backend::RegGroup::GPR, func.name().unwrap())
        }
    }

    /// defines a function version
656
    pub fn define_func_version (&self, func_ver: MuFunctionVersion) {
qinsoon's avatar
qinsoon committed
657
        info!("define function version {}", func_ver);
qinsoon's avatar
vm.rs    
qinsoon committed
658
        // add this funcver to map
qinsoon's avatar
qinsoon committed
659
        let func_ver_id = func_ver.id();
660
661
        {
            let mut func_vers = self.func_vers.write().unwrap();
qinsoon's avatar
qinsoon committed
662
            func_vers.insert(func_ver_id, RwLock::new(func_ver));
663
664
665
666
        }
        
        // acquire a reference to the func_ver
        let func_vers = self.func_vers.read().unwrap();
qinsoon's avatar
qinsoon committed
667
        let func_ver = func_vers.get(&func_ver_id).unwrap().write().unwrap();
668
        
qinsoon's avatar
vm.rs    
qinsoon committed
669
        // change current version of the function to new version (obsolete old versions)
670
        let funcs = self.funcs.read().unwrap();
qinsoon's avatar
qinsoon committed
671
        debug_assert!(funcs.contains_key(&func_ver.func_id)); // it should be declared before defining
qinsoon's avatar
qinsoon committed
672
        let mut func = funcs.get(&func_ver.func_id).unwrap().write().unwrap();
673
        
674
        func.new_version(func_ver.id());
qinsoon's avatar
vm.rs    
qinsoon committed
675
676
677
678
679

        if self.is_doing_jit() {
            // redefinition may happen, we need to check
            unimplemented!()
        }
680
    }
681

qinsoon's avatar
vm.rs    
qinsoon committed
682
683
684
685
    /// adds 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.
686
687
688
689
690
691
692
    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>>,
693
694
                        new_func_vers: &mut HashMap<MuID, Box<MuFunctionVersion>>,
                        arc_vm: Arc<VM>
695
696
697
                        ) {
        // Make sure other components, if ever acquiring multiple locks at the same time, acquire
        // them in this order, to prevent deadlock.
698
699
700
        {
            let mut id_name_map = self.id_name_map.write().unwrap();
            let mut name_id_map = self.name_id_map.write().unwrap();
qinsoon's avatar
vm.rs    
qinsoon committed
701
702
703
704
705
706
            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();
707

708
709
710
711
            for (id, name) in new_id_name_map.drain() {
                id_name_map.insert(id, name.clone());
                name_id_map.insert(name, id);
            }
712

713
714
715
            for (id, obj) in new_types.drain() {
                self.declare_type_internal(&mut types, id, obj);
            }
716

717
718
719
            for (id, obj) in new_constants.drain() {
                self.declare_const_internal(&mut constants, id, obj);
            }
720

721
722
723
724
            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);
            }
725

726
727
728
            for (id, obj) in new_func_sigs.drain() {
                self.declare_func_sig_internal(&mut func_sigs, id, obj);
            }
729

730
731
732
            for (id, obj) in new_funcs.drain() {
                self.declare_func_internal(&mut funcs, id, *obj);
            }
733

734
735
736
            for (id, obj) in new_func_vers.drain() {
                let func_id = obj.func_id;
                func_vers.insert(id, RwLock::new(*obj));
737

738
739
740
741
742
743
                {
                    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);
                }
744
745
746
            }
        }
        // Locks released here
747
748
749
750
751
752
753

        // 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
754
            let created = unsafe {MuThread::current_thread_as_mu_thread(Address::zero(), arc_vm.clone())};
755
756
757
758

            for (id, global) in globals.iter() {
                self.alloc_global(&mut global_locs, *id, global.clone());
            }
759
760
761
762

            if created {
                unsafe {MuThread::cleanup_current_mu_thread()};
            }
763
        }
764
    }
qinsoon's avatar
vm.rs    
qinsoon committed
765
766

    /// informs the VM of a newly compiled function (the function and funcver should already be declared before this call)
767
    pub fn add_compiled_func (&self, func: CompiledFunction) {
qinsoon's avatar
qinsoon committed
768
        debug_assert!(self.funcs.read().unwrap().contains_key(&func.func_id));
qinsoon's avatar
qinsoon committed
769
        debug_assert!(self.func_vers.read().unwrap().contains_key(&func.func_ver_id));
qinsoon's avatar
qinsoon committed
770

qinsoon's avatar
qinsoon committed
771
        self.compiled_funcs.write().unwrap().insert(func.func_ver_id, RwLock::new(func));
qinsoon's avatar
qinsoon committed
772
    }
qinsoon's avatar
vm.rs    
qinsoon committed
773
774

    /// gets the backend/storage type for a given Mu type (by ID)
qinsoon's avatar
qinsoon committed
775
    pub fn get_backend_type_info(&self, tyid: MuID) -> Box<BackendType> {
qinsoon's avatar
vm.rs    
qinsoon committed
776
        // if we already resolved this type, return the BackendType
qinsoon's avatar
qinsoon committed
777
778
779
        {
            let read_lock = self.backend_type_info.read().unwrap();
        
780
            match read_lock.get(&tyid) {
qinsoon's avatar
qinsoon committed
781
782
783
784
                Some(info) => {return info.clone();},
                None => {}
            }
        }
785

qinsoon's avatar
vm.rs    
qinsoon committed
786
        // otherwise, we need to resolve the type now
787
        let types = self.types.read().unwrap();
qinsoon's avatar
qinsoon committed
788
789
790
791
        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
792
        let resolved = Box::new(backend::BackendType::resolve(ty, self));
qinsoon's avatar
vm.rs    
qinsoon committed
793
794

        // insert the type so later we do not need to resolve it again
qinsoon's avatar
qinsoon committed
795
        let mut write_lock = self.backend_type_info.write().unwrap();
796
        write_lock.insert(tyid, resolved.clone());
qinsoon's avatar
qinsoon committed
797
798
799
        
        resolved        
    }
qinsoon's avatar
vm.rs    
qinsoon committed
800
801
802
803

    /// gets the backend/storage type size for a given Mu type (by ID)
    /// This is equivalent to vm.get_backend_type_info(id).size
    pub fn get_backend_type_size(&self, tyid: MuID) -> ByteSize {
qinsoon's avatar
qinsoon committed
804
805
        self.get_backend_type_info(tyid).size
    }
qinsoon's avatar
vm.rs    
qinsoon committed
806
807

    /// returns the lock for globals
qinsoon's avatar
qinsoon committed
808
    pub fn globals(&self) -> &RwLock<HashMap<MuID, P<Value>>> {
qinsoon's avatar
qinsoon committed
809
810
        &self.globals
    }
qinsoon's avatar
vm.rs    
qinsoon committed
811
812

    /// returns the lock for functions
qinsoon's avatar
qinsoon committed
813
    pub fn funcs(&self) -> &RwLock<HashMap<MuID, RwLock<MuFunction>>> {
qinsoon's avatar
qinsoon committed
814
        &self.funcs
815
    }
qinsoon's avatar
vm.rs    
qinsoon committed
816
817

    /// returns the lock for function versions
qinsoon's avatar
qinsoon committed
818
    pub fn func_vers(&self) -> &RwLock<HashMap<MuID, RwLock<MuFunctionVersion>>> {
819
820
        &self.func_vers
    }
qinsoon's avatar
qinsoon committed
821

qinsoon's avatar
vm.rs    
qinsoon committed
822
    /// returns the lock for compiled functions
qinsoon's avatar
qinsoon committed
823
    pub fn compiled_funcs(&self) -> &RwLock<HashMap<MuID, RwLock<CompiledFunction>>> {
824
825
        &self.compiled_funcs
    }
qinsoon's avatar
vm.rs    
qinsoon committed
826
827

    /// returns the lock for types
828
829
830
    pub fn types(&self) -> &RwLock<HashMap<MuID, P<MuType>>> {
        &self.types
    }
qinsoon's avatar
vm.rs    
qinsoon committed
831
832

    /// returns the lock for function signatures
833
834
835
    pub fn func_sigs(&self) -> &RwLock<HashMap<MuID, P<MuFuncSig>>> {
        &self.func_sigs
    }
836

qinsoon's avatar
vm.rs    
qinsoon committed
837
    /// set info (entry function, arguments) for primordial thread for boot image
qinsoon's avatar
qinsoon committed
838
    pub fn set_primordial_thread(&self, func_id: MuID, has_const_args: bool, args: Vec<Constant>) {
839
        let mut guard = self.primordial.write().unwrap();
qinsoon's avatar
qinsoon committed
840
        *guard = Some(PrimordialThreadInfo {func_id: func_id, has_const_args: has_const_args, args: args});
qinsoon's avatar
qinsoon committed
841
    }
842

qinsoon's avatar
vm.rs    
qinsoon committed
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
    /// makes a boot image
    /// We are basically following the spec for this API calls. However, there are a few differences:
    /// 1. we are not doing 'automagic' relocation for unsafe pointers, relocation of unsafe pointers
    ///    needs to be done via explicit sym_fields/strings, reloc_fields/strings
    /// 2. if the output name for the boot image has extension name for dynamic libraries
    ///    (.so or .dylib), we generate a dynamic library as boot image. Otherwise, we generate
    ///    an executable.
    /// 3. we do not support primordial stack (as Kunshan pointed out, making boot image with a
    ///    primordial stack may get deprecated)
    ///
    /// args:
    /// whitelist               : functions to be put into the boot image
    /// primordial_func         : starting function for the boot image
    /// primordial_stack        : starting stack for the boot image
    ///                           (client should name either primordial_func or stack, currently Zebu only supports func)
    /// primordial_threadlocal  : thread local for the starting thread
    /// sym_fields/strings      : declare an address with symbol
    /// reloc_fields/strings    : declare an field pointing to a symbol
    /// output_file             : path for the boot image
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
    pub fn make_boot_image(&self,
                            whitelist: Vec<MuID>,
                            primordial_func: Option<&APIHandle>, primordial_stack: Option<&APIHandle>,
                            primordial_threadlocal: Option<&APIHandle>,
                            sym_fields: Vec<&APIHandle>, sym_strings: Vec<String>,
                            reloc_fields: Vec<&APIHandle>, reloc_strings: Vec<String>,
                            output_file: String) {
        self.make_boot_image_internal(
            whitelist,
            primordial_func, primordial_stack,
            primordial_threadlocal,
            sym_fields, sym_strings,
            reloc_fields, reloc_strings,
            vec![],
            output_file
        )
    }
qinsoon's avatar
vm.rs    
qinsoon committed
879
880
881
882

    /// the actual function to make boot image
    /// One difference from the public one is that we allow linking extra source code during
    /// generating the boot image.
qinsoon's avatar
qinsoon committed
883
    #[allow(unused_variables)]
884
885
886
887
888
889
890
891
    pub fn make_boot_image_internal(&self,
                                   whitelist: Vec<MuID>,
                                   primordial_func: Option<&APIHandle>, primordial_stack: Option<&APIHandle>,
                                   primordial_threadlocal: Option<&APIHandle>,
                                   sym_fields: Vec<&APIHandle>, sym_strings: Vec<String>,
                                   reloc_fields: Vec<&APIHandle>, reloc_strings: Vec<String>,
                                   extra_sources_to_link: Vec<String>,
                                   output_file: String) {
qinsoon's avatar
vm.rs    
qinsoon committed
892
        info!("Making boot image...");
893

qinsoon's avatar
vm.rs    
qinsoon committed
894
        // compile the whitelist functions
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
        let whitelist_funcs = {
            let compiler = Compiler::new(CompilerPolicy::default(), self);
            let funcs = self.funcs().read().unwrap();
            let func_vers = self.func_vers().read().unwrap();

            // make sure all functions in whitelist are compiled
            let mut whitelist_funcs: Vec<MuID> = vec![];
            for &id in whitelist.iter() {
                if let Some(f) = funcs.get(&id) {
                    whitelist_funcs.push(id);

                    let f: &MuFunction = &f.read().unwrap();
                    match f.cur_ver {
                        Some(fv_id) => {
                            let mut func_ver = func_vers.get(&fv_id).unwrap().write().unwrap();
                            if !func_ver.is_compiled() {
                                compiler.compile(&mut func_ver);
                            }
qinsoon's avatar
qinsoon committed
913
                        }
914
                        None => panic!("whitelist function {} has no version defined", f)
qinsoon's avatar
qinsoon committed
915
916
917
                    }
                }
            }
918
919
920
921
922
923
924

            whitelist_funcs
        };

        if primordial_threadlocal.is_some() {
            // we are going to need to persist this threadlocal
            unimplemented!()
qinsoon's avatar
qinsoon committed
925
926
        }

927
928
929
930
931
        let has_primordial_func  = primordial_func.is_some();
        let has_primordial_stack = primordial_stack.is_some();

        // we assume client will start with a function (instead of a stack)
        if has_primordial_stack {
qinsoon's avatar
vm.rs    
qinsoon committed
932
            panic!("Zebu doesnt support creating primordial thread from a stack, name a entry function instead")
933
        } else {
934
935
936
937
938
            if has_primordial_func {
                // extract func id
                let func_id = primordial_func.unwrap().v.as_funcref();

                // make primordial thread in vm
qinsoon's avatar
qinsoon committed
939
                self.set_primordial_thread(func_id, false, vec![]);    // do not pass const args, use argc/argv
940
941
942
            } else {
                warn!("no entry function is passed");
            }
943

qinsoon's avatar
vm.rs    
qinsoon committed
944
            // deal with relocation symbols, zip the two vectors into a hashmap
qinsoon's avatar
qinsoon committed
945
            assert_eq!(sym_fields.len(), sym_strings.len());
qinsoon's avatar
vm.rs    
qinsoon committed
946
947
            let symbols : HashMap<Address, MuName> = sym_fields.into_iter().map(|handle| handle.v.as_address())
                .zip(sym_strings.into_iter().map(|name| name_check(name.clone()))).collect();
qinsoon's avatar
qinsoon committed
948

qinsoon's avatar
vm.rs    
qinsoon committed
949
950
            // deal with relocation fields
            // zip the two vectors into a hashmap, and add fields for pending funcref stores
qinsoon's avatar
qinsoon committed
951
952
            assert_eq!(reloc_fields.len(), reloc_strings.len());
            let fields = {
qinsoon's avatar
vm.rs    
qinsoon committed
953
954
955
956
                // init reloc fields with client-supplied field/symbol pair
                let mut reloc_fields : HashMap<Address, MuName> = reloc_fields.into_iter()
                    .map(|handle| handle.v.as_address())
                    .zip(reloc_strings.into_iter().map(|name| name_check(name.clone()))).collect();
957
958
959
960
961

                // pending funcrefs - we want to replace them as symbol
                {
                    let mut pending_funcref = self.aot_pending_funcref_store.write().unwrap();
                    for (addr, vl) in pending_funcref.drain() {
qinsoon's avatar
vm.rs    
qinsoon committed
962
                        reloc_fields.insert(addr, name_check(vl.to_relocatable()));
963
                    }
qinsoon's avatar
qinsoon committed
964
                }
965

qinsoon's avatar
vm.rs    
qinsoon committed
966
                reloc_fields
qinsoon's avatar
qinsoon committed
967
968
            };

qinsoon's avatar
vm.rs    
qinsoon committed
969
            // emit context (persist vm, etc)
qinsoon's avatar
qinsoon committed
970
            backend::emit_context_with_reloc(self, symbols, fields);
971
972

            // link
973
            self.link_boot_image(whitelist_funcs, extra_sources_to_link, output_file);
974
975
976
        }
    }

qinsoon's avatar
vm.rs    
qinsoon committed
977
978
    /// links boot image (generates a dynamic library is the specified output file
    /// has dylib extension, otherwise generates an executable)
979
    #[cfg(feature = "aot")]
980
    fn link_boot_image(&self, funcs: Vec<MuID>, extra_srcs: Vec<String>, output_file: String) {
981
982
        use testutil;

qinsoon's avatar
vm.rs    
qinsoon committed
983
        info!("Linking boot image...");
984
985
986
987
988
989
990

        let func_names = {
            let funcs_guard = self.funcs().read().unwrap();
            funcs.iter().map(|x| funcs_guard.get(x).unwrap().read().unwrap().name().unwrap()).collect()
        };

        trace!("functions: {:?}", func_names);
991
        trace!("extern sources: {:?}", extra_srcs);
992
993
994
995
        trace!("output   : {}", output_file);

        if output_file.ends_with("dylib") || output_file.ends_with("so") {
            // compile as dynamic library
996
            testutil::aot::link_dylib_with_extra_srcs(func_names, extra_srcs, &output_file, self);
997
        } else {
qinsoon's avatar
vm.rs    
qinsoon committed
998
999
1000
            if extra_srcs.len() != 0 {
                panic!("trying to create an executable with linking extern sources, unimplemented");
            }
1001
1002
1003
1004
1005