muvm.rs 5.49 KB
Newer Older
1
// Copyright 2017 The Australian National University
2
//
3 4 5
// 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
6
//
7
//     http://www.apache.org/licenses/LICENSE-2.0
8
//
9 10 11 12 13 14
// 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.

15
use super::common::*;
16
use std::sync::Arc;
17

18 19 20 21
use runtime::thread;
use utils::Address;
use std::mem::transmute;

22 23
pub struct MuVM {
    // The actual VM
24
    pub vm: Arc<VM>,
25 26 27

    // Cache C strings. The C client expects `char*` from `name_of`. We assume the client won't
    // call `name_of` very often, so that we don't need to initialise this hashmap on startup.
28
    name_cache: Mutex<HashMap<MuID, CString>>
29 30 31 32 33 34 35 36 37 38
}

/**
 * Implement the methods of MuVM. Most methods implement the C-level methods, and others are
 * rust-level helpers. Most methods are forwarded to the underlying `VM.*` methods.
 */
impl MuVM {
    /**
     * Create a new micro VM instance from scratch.
     */
qinsoon's avatar
qinsoon committed
39
    pub fn new(opts: &str) -> MuVM {
40
        MuVM {
qinsoon's avatar
qinsoon committed
41
            vm: Arc::new(VM::new_with_opts(opts)),
42 43 44 45 46 47 48 49
            // Cache C strings. The C client expects `char*` from `name_of`. We assume the client
            // won't call `name_of` very often, so that we don't need to initialise this hashmap on
            // startup.
            //
            // RwLock won't work because Rust will not let me release the lock after reading
            // because other threads will remove that element from the cache, even though I only
            // monotonically add elements into the `name_cache`. I can't upgrade the lock from read
            // lock to write lock, otherwise it will deadlock.
50
            name_cache: Mutex::new(HashMap::new())
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
        }
    }

    pub fn new_context(&self) -> *mut CMuCtx {
        info!("Creating MuCtx...");

        let ctx = MuCtx::new(self);

        let ctx_ptr = Box::into_raw(ctx);

        debug!("The MuCtx address: {:?}", ctx_ptr);

        let cctx = make_new_MuCtx(ctx_ptr as *mut c_void);

        debug!("The C-visible CMuCtx struct address: {:?}", cctx);

67 68 69
        unsafe {
            (*ctx_ptr).c_struct = cctx;
        }
70 71 72 73 74

        cctx
    }

    pub fn id_of(&self, name: MuName) -> MuID {
qinsoon's avatar
qinsoon committed
75
        self.vm.id_of(&name)
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
    }

    pub fn name_of(&self, id: MuID) -> CMuCString {
        let mut map = self.name_cache.lock().unwrap();

        let cname = map.entry(id).or_insert_with(|| {
            let rustname = self.vm.name_of(id);
            CString::new(rustname).unwrap()
        });

        cname.as_ptr()
    }

    pub fn set_trap_handler(&self, trap_handler: CMuTrapHandler, userdata: CMuCPtr) {
        panic!("Not implemented")
    }

93
    pub fn compile_to_sharedlib(&self, lib_name: String, extra_srcs: Vec<String>) {
94 95 96
        extern crate libloading as ll;

        use compiler::*;
97
        use linkutils::aot;
98

99
        let funcs: Vec<MuID> = {
100 101 102 103
            let funcs = self.vm.funcs().read().unwrap();
            funcs.keys().map(|x| *x).collect()
        };

104 105 106 107 108 109 110 111 112 113
        self.vm.make_boot_image_internal(
            funcs,
            None,
            None,
            None,
            vec![],
            vec![],
            vec![],
            vec![],
            extra_srcs,
114
            lib_name
115
        );
116 117 118 119 120 121
    }

    pub fn current_thread_as_mu_thread(&self, threadlocal: CMuCPtr) {
        unsafe {
            thread::MuThread::current_thread_as_mu_thread(
                transmute::<CMuCPtr, Address>(threadlocal),
122
                self.vm.clone()
123
            );
124
        }
125
    }
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
}

/**
 * Create a micro VM instance, and expose it as a C-visible `*mut CMuVM` pointer.
 *
 * NOTE: When used as an API (such as in tests), please use `mu::vm::api::mu_fastimpl_new` instead.
 *
 * This method is not part of the API defined by the Mu spec. It is used **when the client starts
 * the process and creates the micor VM**. For example, it is used if the client wants to build
 * boot images, or if the client implements most of its parts in C and onlu uses the micro VM as
 * the JIT compiler.
 *
 * The boot image itself should use `VM::resume_vm` to restore the saved the micro VM. There is no
 * need in the boot image itself to expose the `MuVM` structure to the trap handler. Trap handlers
 * only see `MuCtx`, and it is enough for most of the works.
 */
#[no_mangle]
143
pub extern "C" fn mu_fastimpl_new() -> *mut CMuVM {
144
    mu_fastimpl_new_with_opts(ptr::null())
qinsoon's avatar
qinsoon committed
145 146 147
}

#[no_mangle]
148
pub extern "C" fn mu_fastimpl_new_with_opts(opts: *const c_char) -> *mut CMuVM {
149 150
    info!("Creating Mu micro VM fast implementation instance...");

151 152 153 154
    let str_opts = {
        if opts == ptr::null() {
            ""
        } else {
155
            let cstr = unsafe { CStr::from_ptr(opts) };
156 157
            match cstr.to_str() {
                Ok(str) => str,
158
                Err(_) => panic!("invalid utf8 string as options: {:?}", cstr)
159 160 161 162 163
            }
        }
    };

    let mvm = Box::new(MuVM::new(str_opts));
164 165 166 167 168 169 170 171 172
    let mvm_ptr = Box::into_raw(mvm);

    debug!("The MuVM instance address: {:?}", mvm_ptr);

    let c_mvm = make_new_MuVM(mvm_ptr as *mut c_void);

    debug!("The C-visible CMuVM struct address: {:?}", c_mvm);

    c_mvm
173
}
174 175 176 177 178 179

use vm::built_info;

#[no_mangle]
pub extern "C" fn mu_get_version() -> *const c_char {
    built_info::ZEBU_VERSION_C_STR.as_ptr()
180
}