GitLab will continue to be upgraded from 11.4.5-ce.0 on November 25th 2019 at 4.00pm (AEDT) to 5.00pm (AEDT) due to Critical Security Patch Availability. During the update, GitLab and Mattermost services will not be available.

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
}