mod.rs 8.97 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.

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 49
    // dladdr will initialise this for us
    let mut info = unsafe{std::mem::uninitialized::<Dl_info>()};
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68

    unsafe {dladdr(function_addr.to_ptr_mut::<c_void>(), &mut info)};

    let error = unsafe {dlerror()};
    if !error.is_null() {
        let cstr = unsafe {CStr::from_ptr(error)};
        error!("cannot find function address: {}", function_addr);
        error!("{}", cstr.to_str().unwrap());

        panic!("failed to resolve function address");
    }
    if !info.dli_sname.is_null() {
        (unsafe {CStr::from_ptr(info.dli_sname)}.to_str().unwrap().to_string(), Address::from_ptr(info.dli_saddr))
    } else {
        ("UNKOWN".to_string(), Address::from_ptr(info.dli_saddr))
    }

}

69 70

/// returns address for a given symbol, e.g. function namepub fn resolve_symbol(symbol: MuName) -> Address {
qinsoon's avatar
qinsoon committed
71
pub fn resolve_symbol(symbol: MuName) -> Address {
72
    use std::ptr;
73

74
    let c_symbol = CString::new(mangle_name(symbol.clone())).unwrap();
75 76
    
    let rtld_default = unsafe {dlopen(ptr::null(), 0)};
77
    let ret = unsafe {dlsym(rtld_default, c_symbol.as_ptr())};
78 79 80 81

    let error = unsafe {dlerror()};
    if !error.is_null() {
        let cstr = unsafe {CStr::from_ptr(error)};
82
        panic!("failed to resolve symbol: {} ({})", symbol, cstr.to_str().unwrap());
83 84 85 86 87
    }
    
    Address::from_ptr(ret)
}

qinsoon's avatar
qinsoon committed
88 89 90 91 92 93 94 95 96
/// 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
97
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
98
pub enum ValueLocation {
99 100
    Register(RegGroup, MuID),
    Constant(RegGroup, Word),
101 102
    Relocatable(RegGroup, MuName),// TODO: This only works for mu entities (add a flag to indicate if its native or have a different variant?)
    
103 104
    Direct(RegGroup, Address),    // Not dumped
    Indirect(RegGroup, Address),  // Not dumped
qinsoon's avatar
qinsoon committed
105 106
}

107 108
rodal_enum!(ValueLocation{(Register: group, id), (Constant: group, word), (Relocatable: group, name)});

109 110 111 112 113 114 115 116 117 118 119 120
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),
            &ValueLocation::Indirect(_, addr) => write!(f, "VL_Indirect: 0x{:x}", addr)
        }
    }
}

121
impl ValueLocation {
qinsoon's avatar
qinsoon committed
122
    /// loads value from a ValueLocation
123 124
    pub fn load_value(&self) -> (RegGroup, Word) {
        match self {
qinsoon's avatar
qinsoon committed
125 126 127 128 129 130 131 132 133 134
            &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>())
                }
            }
135 136 137
            &ValueLocation::Constant(group, word) => {
                (group, word)
            }
qinsoon's avatar
qinsoon committed
138 139 140 141
            &ValueLocation::Relocatable(group, ref symbol) => {
                let addr = resolve_symbol(symbol.clone());
                (group, unsafe {addr.load::<Word>()})
            }
142 143
        }
    }
qinsoon's avatar
qinsoon committed
144 145

    /// creates a ValueLocation from a constant, panics if impossible
qinsoon's avatar
qinsoon committed
146
    pub fn from_constant(c: Constant) -> ValueLocation {
147
        match c {
qinsoon's avatar
qinsoon committed
148 149
            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)),
150 151 152
            Constant::Double(f64_val) => ValueLocation::Constant(RegGroup::FPR, utils::mem::f64_to_raw(f64_val)),
            _ => unimplemented!()
        }
qinsoon's avatar
qinsoon committed
153
    }
qinsoon's avatar
qinsoon committed
154 155

    /// returns the address that contains the value
qinsoon's avatar
qinsoon committed
156 157
    pub fn to_address(&self) -> Address {
        match self {
qinsoon's avatar
qinsoon committed
158
            &ValueLocation::Direct(_, addr)   => addr,
qinsoon's avatar
qinsoon committed
159
            &ValueLocation::Indirect(_, addr) => unsafe {addr.load::<Address>()},
qinsoon's avatar
qinsoon committed
160 161 162
            &ValueLocation::Relocatable(_, ref symbol) => resolve_symbol(symbol.clone()),
            &ValueLocation::Register(_, _)
            | &ValueLocation::Constant(_, _)  => panic!("a register/constant cannot be turned into address")
qinsoon's avatar
qinsoon committed
163 164
        }
    }
165

qinsoon's avatar
qinsoon committed
166
    /// returns a relocatable symbol that contains the value, panics if impossible
167 168 169 170 171 172
    pub fn to_relocatable(&self) -> MuName {
        match self {
            &ValueLocation::Relocatable(_, ref name) => name.clone(),
            _ => panic!("expecting Relocatable location, found {}", self)
        }
    }
173 174
}

qinsoon's avatar
qinsoon committed
175 176 177 178 179
/// 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
180 181
pub const PRIMORDIAL_ENTRY : &'static str = "src/runtime/main.c";

qinsoon's avatar
qinsoon committed
182
/// starts trace level logging, this function will be called from C
183 184
#[no_mangle]
pub extern fn mu_trace_level_log() {
qinsoon's avatar
qinsoon committed
185
    VM::start_logging_trace();
186 187
}

188 189 190
#[no_mangle]
pub static mut LAST_TIME: c_ulong = 0;

qinsoon's avatar
qinsoon committed
191
/// the main function for executable boot image, this function will be called from C
192
#[no_mangle]
193 194
pub extern fn mu_main(edata: *const(), dumped_vm : *mut Arc<VM>, argc: c_int, argv: *const *const c_char) {
    VM::start_logging_env();
195
    debug!("mu_main() started...");
196

qinsoon's avatar
qinsoon committed
197
    // load and resume the VM
198 199
    unsafe{rodal::load_asm_bounds(rodal::Address::from_ptr(dumped_vm), rodal::Address::from_ptr(edata))};
    let vm = VM::resume_vm(dumped_vm);
qinsoon's avatar
qinsoon committed
200
    // find the primordial function as an entry
201 202 203 204 205 206 207 208
    let primordial = vm.primordial.read().unwrap();
    if primordial.is_none() {
        panic!("no primordial thread/stack/function. Client should provide an entry point");
    } else {
        let primordial = primordial.as_ref().unwrap();
        
        // create mu stack
        let stack = vm.new_stack(primordial.func_id);
qinsoon's avatar
qinsoon committed
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224

        // if the primordial named some const arguments, we use the const args
        // otherwise we push 'argc' and 'argv' to new stack
        let args : Vec<ValueLocation> = if primordial.has_const_args {
            primordial.args.iter().map(|arg| ValueLocation::from_constant(arg.clone())).collect()
        } 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
        };
225
        
qinsoon's avatar
qinsoon committed
226
        // FIXME: currently assumes no user defined thread local - See Issue #48
227
        let thread = thread::MuThread::new_thread_normal(stack, unsafe{Address::zero()}, args, vm.clone());
228 229 230
        
        thread.join().unwrap();
    }
231
}
232

qinsoon's avatar
qinsoon committed
233
/// runtime function to print a hex value (for PRINTHEX instruction for debugging use)
234 235
#[no_mangle]
pub extern fn muentry_print_hex(x: u64) {
236
    println!("PRINTHEX: 0x{:x}", x);
237 238 239 240 241
}

#[no_mangle]
pub unsafe extern fn muentry_mem_zero(dest: *mut u8, size: usize) {
    std::ptr::write_bytes(dest, 0, size);
242
}