mod.rs 9.25 KB
Newer Older
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1
// Copyright 2017 The Australian National University
qinsoon's avatar
qinsoon committed
2
//
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
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
qinsoon's avatar
qinsoon committed
6
//
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
7
//     http://www.apache.org/licenses/LICENSE-2.0
qinsoon's avatar
qinsoon committed
8
//
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
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 utils;
16 17
use utils::Word;
use utils::Address;
18
use ast::ir::*;
19
use vm::VM;
20 21
use compiler::backend::RegGroup;

22 23
use libc::*;
use std;
24
use std::fmt;
25
use std::ffi::CString;
26 27
use std::ffi::CStr;
use std::sync::Arc;
28
use rodal;
29

qinsoon's avatar
qinsoon committed
30 31
/// memory management: allocation, reclamation
/// (the actual code is in src/gc, which gets re-exported in mm module)
32
pub mod mm;
qinsoon's avatar
qinsoon committed
33
/// thread management: stack, thread
qinsoon's avatar
qinsoon committed
34
pub mod thread;
qinsoon's avatar
qinsoon committed
35
/// mathematics functions
qinsoon's avatar
qinsoon committed
36
pub mod math;
qinsoon's avatar
qinsoon committed
37 38
/// a list of all entrypoints used by compiler to generate calls into runtime
/// (where generated code entries the runtime)
qinsoon's avatar
qinsoon committed
39
pub mod entrypoints;
qinsoon's avatar
qinsoon committed
40
/// exception handling
41 42
pub mod exception;

43

qinsoon's avatar
qinsoon committed
44 45 46
/// returns name for a function address
// FIXME: this actually returns the name and address of the nearest symbol (of any type)
//        that starts before function_addr (instead we want the nearest function symbol)
47
pub fn get_function_info(function_addr: Address) -> (CName, Address) {
48
    // dladdr will initialise this for us
qinsoon's avatar
qinsoon committed
49
    let mut info = unsafe { std::mem::uninitialized::<Dl_info>() };
50

qinsoon's avatar
qinsoon committed
51
    unsafe { dladdr(function_addr.to_ptr_mut::<c_void>(), &mut info) };
52

qinsoon's avatar
qinsoon committed
53
    let error = unsafe { dlerror() };
54
    if !error.is_null() {
qinsoon's avatar
qinsoon committed
55
        let cstr = unsafe { CStr::from_ptr(error) };
56 57 58 59 60 61
        error!("cannot find function address: {}", function_addr);
        error!("{}", cstr.to_str().unwrap());

        panic!("failed to resolve function address");
    }
    if !info.dli_sname.is_null() {
qinsoon's avatar
qinsoon committed
62 63 64 65 66
        (
            unsafe { CStr::from_ptr(info.dli_sname) }
                .to_str()
                .unwrap()
                .to_string(),
67
            Address::from_ptr(info.dli_saddr)
qinsoon's avatar
qinsoon committed
68
        )
69 70 71 72 73 74
    } else {
        ("UNKOWN".to_string(), Address::from_ptr(info.dli_saddr))
    }

}

75

qinsoon's avatar
qinsoon committed
76
/// returns address for a given symbol, e.g. function name
qinsoon's avatar
qinsoon committed
77
pub fn resolve_symbol(symbol: MuName) -> Address {
78
    use std::ptr;
79

80
    let c_symbol = CString::new(mangle_name(symbol.clone())).unwrap();
81

qinsoon's avatar
qinsoon committed
82 83 84 85
    let rtld_default = unsafe { dlopen(ptr::null(), 0) };
    let ret = unsafe { dlsym(rtld_default, c_symbol.as_ptr()) };

    let error = unsafe { dlerror() };
86
    if !error.is_null() {
qinsoon's avatar
qinsoon committed
87 88 89 90 91 92
        let cstr = unsafe { CStr::from_ptr(error) };
        panic!(
            "failed to resolve symbol: {} ({})",
            symbol,
            cstr.to_str().unwrap()
        );
93
    }
qinsoon's avatar
qinsoon committed
94

95 96 97
    Address::from_ptr(ret)
}

qinsoon's avatar
qinsoon committed
98 99 100 101 102 103 104 105 106
/// ValueLocation represents the runtime location for a value.
/// The purpose of this data structure is to refer to a location in a unified way
/// for both compile time (usually talking about symbols) and run time (talking about addresses)
/// A ValueLocation could be:
/// * a register (the register holds the value)
/// * a Constant (the value itself)
/// * a relocatable symbol (a relocatable symbol emitted by AOT compiler, which resides the value)
/// * a direct memory address (the address contains the value)
/// * a indirect memory address (the address contains a pointer to the value)
qinsoon's avatar
qinsoon committed
107
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
108
pub enum ValueLocation {
109 110
    Register(RegGroup, MuID),
    Constant(RegGroup, Word),
qinsoon's avatar
qinsoon committed
111 112 113
    Relocatable(RegGroup, MuName), // TODO: This only works for mu entities (add a flag to indicate
    // if its native or have a different variant?)
    Direct(RegGroup, Address),   // Not dumped
114
    Indirect(RegGroup, Address)  // Not dumped
qinsoon's avatar
qinsoon committed
115 116
}

qinsoon's avatar
qinsoon committed
117 118
rodal_enum!(ValueLocation{(Register: group, id), (Constant: group, word),
    (Relocatable: group, name)});
119

120 121 122 123 124 125 126
impl fmt::Display for ValueLocation {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &ValueLocation::Register(_, id) => write!(f, "VL_Reg: {}", id),
            &ValueLocation::Constant(_, val) => write!(f, "VL_Const: {}", val),
            &ValueLocation::Relocatable(_, ref name) => write!(f, "VL_Reloc: {}", name),
            &ValueLocation::Direct(_, addr) => write!(f, "VL_Direct: 0x{:x}", addr),
127
            &ValueLocation::Indirect(_, addr) => write!(f, "VL_Indirect: 0x{:x}", addr)
128 129 130 131
        }
    }
}

132
impl ValueLocation {
qinsoon's avatar
qinsoon committed
133
    /// loads value from a ValueLocation
134 135
    pub fn load_value(&self) -> (RegGroup, Word) {
        match self {
qinsoon's avatar
qinsoon committed
136 137 138 139 140 141 142
            &ValueLocation::Register(_, _) => unimplemented!(),
            &ValueLocation::Direct(group, addr) => (group, unsafe { addr.load::<Word>() }),
            &ValueLocation::Indirect(group, addr) => unsafe {
                let ptr = addr.load::<Address>();
                (group, ptr.load::<Word>())
            },
            &ValueLocation::Constant(group, word) => (group, word),
qinsoon's avatar
qinsoon committed
143 144
            &ValueLocation::Relocatable(group, ref symbol) => {
                let addr = resolve_symbol(symbol.clone());
qinsoon's avatar
qinsoon committed
145
                (group, unsafe { addr.load::<Word>() })
qinsoon's avatar
qinsoon committed
146
            }
147 148
        }
    }
qinsoon's avatar
qinsoon committed
149 150

    /// creates a ValueLocation from a constant, panics if impossible
qinsoon's avatar
qinsoon committed
151
    pub fn from_constant(c: Constant) -> ValueLocation {
152
        match c {
qinsoon's avatar
qinsoon committed
153 154 155 156 157 158 159 160 161
            Constant::Int(int_val) => {
                ValueLocation::Constant(RegGroup::GPR, utils::mem::u64_to_raw(int_val))
            }
            Constant::Float(f32_val) => {
                ValueLocation::Constant(RegGroup::FPR, utils::mem::f32_to_raw(f32_val))
            }
            Constant::Double(f64_val) => {
                ValueLocation::Constant(RegGroup::FPR, utils::mem::f64_to_raw(f64_val))
            }
162
            _ => unimplemented!()
163
        }
qinsoon's avatar
qinsoon committed
164
    }
qinsoon's avatar
qinsoon committed
165 166

    /// returns the address that contains the value
qinsoon's avatar
qinsoon committed
167 168
    pub fn to_address(&self) -> Address {
        match self {
qinsoon's avatar
qinsoon committed
169 170
            &ValueLocation::Direct(_, addr) => addr,
            &ValueLocation::Indirect(_, addr) => unsafe { addr.load::<Address>() },
qinsoon's avatar
qinsoon committed
171
            &ValueLocation::Relocatable(_, ref symbol) => resolve_symbol(symbol.clone()),
qinsoon's avatar
qinsoon committed
172 173 174
            &ValueLocation::Register(_, _) | &ValueLocation::Constant(_, _) => {
                panic!("a register/constant cannot be turned into address")
            }
qinsoon's avatar
qinsoon committed
175 176
        }
    }
177

qinsoon's avatar
qinsoon committed
178
    /// returns a relocatable symbol that contains the value, panics if impossible
179 180 181
    pub fn to_relocatable(&self) -> MuName {
        match self {
            &ValueLocation::Relocatable(_, ref name) => name.clone(),
182
            _ => panic!("expecting Relocatable location, found {}", self)
183 184
        }
    }
185 186
}

qinsoon's avatar
qinsoon committed
187 188 189 190 191
/// a C wrapper as main function for executable boot images"
/// The C wrapper does:
/// 1. loads the persisted VM
/// 2. invokes mu_main() to hand the control to Rust code
/// 3. returns the return value set by SetRetval
qinsoon's avatar
qinsoon committed
192
pub const PRIMORDIAL_ENTRY: &'static str = "src/runtime/main.c";
193

qinsoon's avatar
qinsoon committed
194
/// starts trace level logging, this function will be called from C
195
#[no_mangle]
qinsoon's avatar
qinsoon committed
196
pub extern "C" fn mu_trace_level_log() {
qinsoon's avatar
qinsoon committed
197
    VM::start_logging_trace();
198 199
}

200 201 202
#[no_mangle]
pub static mut LAST_TIME: c_ulong = 0;

qinsoon's avatar
qinsoon committed
203
/// the main function for executable boot image, this function will be called from C
204
#[no_mangle]
qinsoon's avatar
qinsoon committed
205 206 207 208
pub extern "C" fn mu_main(
    edata: *const (),
    dumped_vm: *mut Arc<VM>,
    argc: c_int,
209
    argv: *const *const c_char
qinsoon's avatar
qinsoon committed
210
) {
211
    VM::start_logging_env();
212
    debug!("mu_main() started...");
213

qinsoon's avatar
qinsoon committed
214
    // load and resume the VM
qinsoon's avatar
qinsoon committed
215 216 217
    unsafe {
        rodal::load_asm_bounds(
            rodal::Address::from_ptr(dumped_vm),
218
            rodal::Address::from_ptr(edata)
qinsoon's avatar
qinsoon committed
219 220
        )
    };
221
    let vm = VM::resume_vm(dumped_vm);
qinsoon's avatar
qinsoon committed
222
    // find the primordial function as an entry
223
    let primordial = vm.primordial().read().unwrap();
224 225 226 227
    if primordial.is_none() {
        panic!("no primordial thread/stack/function. Client should provide an entry point");
    } else {
        let primordial = primordial.as_ref().unwrap();
qinsoon's avatar
qinsoon committed
228

229 230
        // create mu stack
        let stack = vm.new_stack(primordial.func_id);
qinsoon's avatar
qinsoon committed
231 232 233

        // if the primordial named some const arguments, we use the const args
        // otherwise we push 'argc' and 'argv' to new stack
qinsoon's avatar
qinsoon committed
234 235 236 237 238 239
        let args: Vec<ValueLocation> = if primordial.has_const_args {
            primordial
                .args
                .iter()
                .map(|arg| ValueLocation::from_constant(arg.clone()))
                .collect()
qinsoon's avatar
qinsoon committed
240 241 242 243 244 245 246 247 248 249 250
        } else {
            let mut args = vec![];

            // 1st arg: argc
            args.push(ValueLocation::from_constant(Constant::Int(argc as u64)));

            // 2nd arg: argv
            args.push(ValueLocation::from_constant(Constant::Int(argv as u64)));

            args
        };
qinsoon's avatar
qinsoon committed
251

qinsoon's avatar
qinsoon committed
252
        // FIXME: currently assumes no user defined thread local - See Issue #48
qinsoon's avatar
qinsoon committed
253 254 255 256
        let thread = thread::MuThread::new_thread_normal(
            stack,
            unsafe { Address::zero() },
            args,
257
            vm.clone()
qinsoon's avatar
qinsoon committed
258 259
        );

260 261
        thread.join().unwrap();
    }
262
}
263

qinsoon's avatar
qinsoon committed
264
/// runtime function to print a hex value (for PRINTHEX instruction for debugging use)
265
#[no_mangle]
qinsoon's avatar
qinsoon committed
266
pub extern "C" fn muentry_print_hex(x: u64) {
267
    println!("PRINTHEX: 0x{:x}", x);
268 269 270
}

#[no_mangle]
qinsoon's avatar
qinsoon committed
271
pub unsafe extern "C" fn muentry_mem_zero(dest: *mut u8, size: usize) {
272
    std::ptr::write_bytes(dest, 0, size);
qinsoon's avatar
qinsoon committed
273
}