mod.rs 8.71 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))
    }

}

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

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

    let error = unsafe {dlerror()};
    if !error.is_null() {
        let cstr = unsafe {CStr::from_ptr(error)};
81 82
        error!("cannot find symbol: {}", symbol);
        error!("{}", cstr.to_str().unwrap());
83 84

        panic!("failed to resolve symbol");
85 86 87 88 89
    }
    
    Address::from_ptr(ret)
}

qinsoon's avatar
qinsoon committed
90 91 92 93 94 95 96 97 98
/// 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
99
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
100
pub enum ValueLocation {
101 102 103 104 105
    Register    (RegGroup, MuID),
    Constant    (RegGroup, Word),
    Relocatable (RegGroup, MuName),
    Direct      (RegGroup, Address),  // Not dumped
    Indirect    (RegGroup, Address),  // Not dumped
qinsoon's avatar
qinsoon committed
106 107
}

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

110 111 112 113 114 115 116 117 118 119 120 121
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)
        }
    }
}

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

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

    /// returns the address that contains the value
qinsoon's avatar
qinsoon committed
157 158
    pub fn to_address(&self) -> Address {
        match self {
qinsoon's avatar
qinsoon committed
159
            &ValueLocation::Direct(_, addr)   => addr,
qinsoon's avatar
qinsoon committed
160
            &ValueLocation::Indirect(_, addr) => unsafe {addr.load::<Address>()},
qinsoon's avatar
qinsoon committed
161 162 163
            &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
164 165
        }
    }
166

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

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

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

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

    // load and resume the VM
196 197
    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
198 199

    // find the primordial function as an entry
200 201 202 203 204 205 206 207
    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
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223

        // 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
        };
224
        
qinsoon's avatar
qinsoon committed
225
        // FIXME: currently assumes no user defined thread local - See Issue #48
226
        let thread = thread::MuThread::new_thread_normal(stack, unsafe{Address::zero()}, args, vm.clone());
227 228 229
        
        thread.join().unwrap();
    }
230
}
231

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