Commit 1fe63f37 authored by qinsoon's avatar qinsoon

test make_boot_image_simple should work (some path problems in the test

need to be fixed)
parent f1cec1aa
......@@ -1046,7 +1046,7 @@ impl MuEntityHeader {
*name_guard = Some(MuEntityHeader::name_check(name));
}
fn name_check(name: MuName) -> MuName {
pub fn name_check(name: MuName) -> MuName {
if name.starts_with("@") || name.starts_with("%") {
let (_, name) = name.split_at(1);
......
......@@ -2918,50 +2918,28 @@ fn write_const_value(f: &mut File, constant: P<Value>) {
}
}
pub fn emit_context(vm: &VM) {
pub fn emit_context_with_reloc(vm: &VM,
symbols: HashMap<Address, String>,
fields : HashMap<Address, String>) {
use std::path;
use std::io::prelude::*;
use rustc_serialize::json;
debug!("---Emit VM Context---");
create_emit_directory(vm);
let mut file_path = path::PathBuf::new();
file_path.push(&vm.vm_options.flag_aot_emit_dir);
file_path.push(AOT_EMIT_CONTEXT_FILE);
let mut file = match File::create(file_path.as_path()) {
Err(why) => panic!("couldn't create context file {}: {}", file_path.to_str().unwrap(), why),
Ok(file) => file
};
// bss
file.write_fmt(format_args!("\t.bss\n")).unwrap();
{
// put globals into bss section
// let globals = vm.globals().read().unwrap();
// for global in globals.values() {
// debug!("emit global: {}", global);
// let (size, align) = {
// let alloc_ty = {
// match global.v {
// Value_::Global(ref ty) => ty,
// _ => panic!("expected a global")
// }
// };
//
// debug!("getting type: {:?}", alloc_ty);
// let ty_info = vm.get_backend_type_info(alloc_ty.id());
// (ty_info.size, ty_info.alignment)
// };
//
// file.write_fmt(format_args!("\t{}\n", directive_globl(symbol(global.name().unwrap())))).unwrap();
// file.write_fmt(format_args!("\t{}\n", directive_comm(symbol(global.name().unwrap()), size, align))).unwrap();
// file.write("\n".as_bytes()).unwrap();
// }
}
// data
file.write("\t.data\n".as_bytes()).unwrap();
......@@ -2985,11 +2963,16 @@ pub fn emit_context(vm: &VM) {
// dump heap from globals
let global_addrs : Vec<Address> = global_locs_lock.values().map(|x| x.to_address()).collect();
debug!("going to dump these globals: {:?}", global_addrs);
let global_dump = mm::persist_heap(global_addrs);
let mut global_dump = mm::persist_heap(global_addrs);
debug!("Heap Dump from GC: {:?}", global_dump);
let ref objects = global_dump.objects;
let ref relocatable_refs = global_dump.relocatable_refs;
let ref mut relocatable_refs = global_dump.relocatable_refs;
// merge symbols with relocatable_refs
for (addr, str) in symbols {
relocatable_refs.insert(addr, str);
}
for obj_dump in objects.values() {
// .bytes xx,xx,xx,xx (between mem_start to reference_addr)
......@@ -3008,37 +2991,50 @@ pub fn emit_context(vm: &VM) {
}
// dump_label:
let dump_label = symbol(global_dump.relocatable_refs.get(&obj_dump.reference_addr).unwrap().clone());
let dump_label = symbol(relocatable_refs.get(&obj_dump.reference_addr).unwrap().clone());
file.write_fmt(format_args!("{}:\n", dump_label)).unwrap();
let base = obj_dump.reference_addr;
let mut cursor = obj_dump.reference_addr;
for ref_offset in obj_dump.reference_offsets.iter() {
let cur_ref_addr = base.plus(*ref_offset);
let end = obj_dump.mem_start.plus(obj_dump.mem_size);
assert!(base.is_aligned_to(POINTER_SIZE));
if cursor < cur_ref_addr {
// write all non-ref data
write_data_bytes(&mut file, cursor, cur_ref_addr);
}
let mut offset = 0;
// write ref with label
let load_ref = unsafe {cur_ref_addr.load::<Address>()};
if load_ref.is_zero() {
file.write("\t.quad 0\n".as_bytes()).unwrap();
} else {
let label = match global_dump.relocatable_refs.get(&load_ref) {
Some(label) => label,
None => panic!("cannot find label for address {}, it is not dumped by GC (why GC didn't trace to it)", load_ref)
};
while offset < obj_dump.mem_size {
let cur_addr = base.plus(offset);
if obj_dump.reference_offsets.contains(&offset) {
// write ref with label
let load_ref = unsafe {cur_addr.load::<Address>()};
if load_ref.is_zero() {
// write 0
file.write("\t.quad 0\n".as_bytes()).unwrap();
} else {
let label = match relocatable_refs.get(&load_ref) {
Some(label) => label,
None => panic!("cannot find label for address {}, it is not dumped by GC (why GC didn't trace to it)", load_ref)
};
file.write_fmt(format_args!("\t.quad {}\n", symbol(label.clone()))).unwrap();
}
} else if fields.contains_key(&cur_addr) {
// write uptr (or other relocatable value) with label
let label = fields.get(&cur_addr).unwrap();
file.write_fmt(format_args!("\t.quad {}\n", symbol(label.clone()))).unwrap();
} else {
// write plain word (as bytes)
let next_word_addr = cur_addr.plus(POINTER_SIZE);
if next_word_addr <= end {
write_data_bytes(&mut file, cur_addr, next_word_addr);
} else {
write_data_bytes(&mut file, cur_addr, end);
}
}
cursor = cur_ref_addr.plus(POINTER_SIZE);
offset += POINTER_SIZE;
}
// write whatever is after the last ref
write_data_bytes(&mut file, cursor, obj_dump.mem_start.plus(obj_dump.mem_size));
}
}
......@@ -3046,23 +3042,27 @@ pub fn emit_context(vm: &VM) {
trace!("start serializing vm");
{
let serialize_vm = json::encode(&vm).unwrap();
let vm_symbol = symbol("vm".to_string());
file.write_fmt(format_args!("{}\n", directive_globl(vm_symbol.clone()))).unwrap();
let escape_serialize_vm = serialize_vm.replace("\"", "\\\"");
file.write_fmt(format_args!("\t{}: .asciz \"{}\"", vm_symbol, escape_serialize_vm)).unwrap();
file.write("\n".as_bytes()).unwrap();
}
// main_thread
// let primordial = vm.primordial.read().unwrap();
// if primordial.is_some() {
// let primordial = primordial.as_ref().unwrap();
// }
// let primordial = vm.primordial.read().unwrap();
// if primordial.is_some() {
// let primordial = primordial.as_ref().unwrap();
// }
debug!("---finish---");
}
pub fn emit_context(vm: &VM) {
emit_context_with_reloc(vm, hashmap!{}, hashmap!{});
}
fn write_data_bytes(f: &mut File, from: Address, to: Address) {
use std::io::Write;
......
......@@ -2,9 +2,7 @@ extern crate hprof;
use ast::ir::*;
use vm::VM;
use std::cell::RefCell;
use std::sync::Arc;
pub mod passes;
pub mod backend;
......
......@@ -5,15 +5,8 @@
extern void* vm;
extern void mu_main(char*, int, char**);
extern void mu_trace_level_log();
int main(int argc, char** argv) {
mu_trace_level_log();
printf("main(), going to launch mu_main()\n");
char* serialize_vm = (char*) &vm;
printf("%s\n", serialize_vm);
mu_main(serialize_vm, argc, argv);
}
......@@ -34,6 +34,8 @@ extern "C" {
pub fn resolve_symbol(symbol: String) -> Address {
use std::ptr;
let symbol = MuEntityHeader::name_check(symbol);
let rtld_default = unsafe {dlopen(ptr::null(), 0)};
let ret = unsafe {dlsym(rtld_default, CString::new(symbol.clone()).unwrap().as_ptr())};
......
......@@ -102,15 +102,27 @@ pub fn link_primordial (funcs: Vec<MuName>, out: &str, vm: &VM) -> PathBuf {
ret.push(get_path_for_mu_context(vm));
// copy primoridal entry
let source = PathBuf::from(runtime::PRIMORDIAL_ENTRY);
let mut dest = PathBuf::from(&vm.vm_options.flag_aot_emit_dir);
dest.push("main.c");
let source = get_path_under_mu(runtime::PRIMORDIAL_ENTRY);
let dest = {
let mut ret = PathBuf::from(&vm.vm_options.flag_aot_emit_dir);
ret.push("main.c");
ret
};
trace!("copying from {:?} to {:?}", source, dest);
fs::copy(source.as_path(), dest.as_path()).unwrap();
// include the primordial C main
ret.push(dest);
// include mu static lib
let libmu = PathBuf::from("target/debug/libmu.a");
let libmu_path = if cfg!(debug_assertions) {
"target/debug/libmu.a"
} else {
"target/release/libmu.a"
};
let libmu = get_path_under_mu(libmu_path);
ret.push(libmu);
ret
......
......@@ -5,6 +5,7 @@ use ast::ir::*;
use vm::*;
use std::sync::Arc;
use std::path::PathBuf;
use std::process::Command;
use std::process::Output;
use std::os::unix::process::ExitStatusExt;
......@@ -48,6 +49,20 @@ pub fn exec_nocheck (mut cmd: Command) -> Output {
output
}
pub fn get_path_under_mu(str: &'static str) -> PathBuf {
use std::env;
match env::var("MU_RUST") {
Ok(v) => {
let mut ret = PathBuf::from(v);
ret.push(str);
ret
}
Err(_) => PathBuf::from(str)
}
}
#[cfg(target_os = "macos")]
pub fn get_dylib_name(name: &'static str) -> String {
format!("lib{}.dylib", name)
......
......@@ -47,7 +47,7 @@ impl Address {
pub fn align_up(&self, align: usize) -> Address {
Address((self.0 + align - 1) & !(align - 1))
}
pub fn is_aligned_to(&self, align: usize) -> bool {
self.0 % align == 0
}
......
......@@ -79,7 +79,6 @@ impl<K, V> Decodable for LinkedHashMap<K, V>
for i in 0..len {
let key = try!(d.read_map_elt_key(i, |d| Decodable::decode(d)));
let val = try!(d.read_map_elt_val(i, |d| Decodable::decode(d)));
println!("insert {}", i);
map.insert(key, val);
}
Ok(map)
......
......@@ -168,7 +168,7 @@ impl MuCtx {
}
pub fn handle_from_func(&mut self, id: MuID) -> *const APIHandle {
panic!("Not implemented")
prepare_handle(self.get_mvm().vm.handle_from_func(id))
}
pub fn handle_from_expose(&mut self, id: MuID) -> *const APIHandle {
......@@ -406,7 +406,7 @@ impl MuCtx {
}
pub fn make_boot_image(&mut self, whitelist: Vec<MuID>, primordial_func: Option<&APIHandle>, primordial_stack: Option<&APIHandle>, primordial_threadlocal: Option<&APIHandle>, sym_fields: Vec<&APIHandle>, sym_strings: Vec<String>, reloc_fields: Vec<&APIHandle>, reloc_strings: Vec<String>, output_file: String) {
panic!("Not implemented")
self.get_mvm().vm.make_boot_image(whitelist, primordial_func, primordial_stack, primordial_threadlocal, sym_fields, sym_strings, reloc_fields, reloc_strings, output_file);
}
}
......
......@@ -1976,7 +1976,14 @@ impl<'lb, 'lvm> BundleLoader<'lb, 'lvm> {
v: Instruction_::CommonInst_Unpin(0)
}
}
CMU_CI_UVM_THREAD_EXIT => {
Instruction {
hdr: hdr,
value: None,
ops: RwLock::new(vec![]),
v: Instruction_::ThreadExit
}
}
_ => unimplemented!()
}
}
......
......@@ -48,7 +48,7 @@ pub enum APIHandleValue {
// GenRef->IR->Child->Var->Global
Global(MuID),
Func,
Func(MuID),
ExpFunc,
// GenRef->IR->Child->Var->Local
......@@ -114,4 +114,11 @@ impl APIHandleValue {
_ => panic!("expected UFP handle")
}
}
pub fn as_func(&self) -> MuID {
match self {
&APIHandleValue::Func(id) => id,
_ => panic!("expected FuncRef")
}
}
}
\ No newline at end of file
......@@ -22,7 +22,6 @@ use vm::vm_options::MuLogLevel;
use rustc_serialize::{Encodable, Encoder, Decodable, Decoder};
use log::LogLevel;
use std::sync::Arc;
use std::path;
use std::sync::RwLock;
use std::sync::RwLockWriteGuard;
use std::sync::atomic::{AtomicUsize, AtomicBool, ATOMIC_BOOL_INIT, ATOMIC_USIZE_INIT, Ordering};
......@@ -944,45 +943,99 @@ impl <'a> VM {
}
#[allow(unused_variables)]
pub fn make_boot_image(&mut self,
pub fn make_boot_image(&self,
whitelist: Vec<MuID>,
primordial_func: Option<&APIHandle>, primordial_stack: Option<&APIHandle>,
primordial_threadlocal: Option<&APIHandle>,
sym_fields: Vec<&APIHandle>, sym_strings: Vec<String>,
reloc_fields: Vec<&APIHandle>, reloc_strings: Vec<String>,
output_file: String) {
use rustc_serialize::json;
let compiler = Compiler::new(CompilerPolicy::default(), self);
let funcs = self.funcs().write().unwrap();
let func_vers = self.func_vers().write().unwrap();
// make sure all functions in whitelist are compiled
for &id in whitelist.iter() {
if let Some(f) = funcs.get(&id) {
let f : &MuFunction = &f.read().unwrap();
match f.cur_ver {
Some(fv_id) => {
let mut func_ver = func_vers.get(&fv_id).unwrap().write().unwrap();
if !func_ver.is_compiled() {
compiler.compile(&mut func_ver);
trace!("Making boot image...");
let whitelist_funcs = {
let compiler = Compiler::new(CompilerPolicy::default(), self);
let funcs = self.funcs().read().unwrap();
let func_vers = self.func_vers().read().unwrap();
// make sure all functions in whitelist are compiled
let mut whitelist_funcs: Vec<MuID> = vec![];
for &id in whitelist.iter() {
if let Some(f) = funcs.get(&id) {
whitelist_funcs.push(id);
let f: &MuFunction = &f.read().unwrap();
match f.cur_ver {
Some(fv_id) => {
let mut func_ver = func_vers.get(&fv_id).unwrap().write().unwrap();
if !func_ver.is_compiled() {
compiler.compile(&mut func_ver);
}
}
None => panic!("whitelist function {} has no version defined", f)
}
None => panic!("whitelist function {} has no version defined", f)
}
}
whitelist_funcs
};
if primordial_threadlocal.is_some() {
// we are going to need to persist this threadlocal
unimplemented!()
}
// make sure only one of primordial_func or primoridial_stack is set
let has_primordial_func = primordial_func.is_some();
let has_primordial_stack = primordial_stack.is_some();
assert!(
(primordial_func.is_some() && primordial_stack.is_none())
|| (primordial_func.is_none() && primordial_stack.is_some())
// do not have promordial stack/func
(!has_primordial_func && !has_primordial_stack)
// have either stack or func
|| ((has_primordial_func && !has_primordial_stack) || (!has_primordial_func && has_primordial_stack))
);
let serialized = json::encode(self).unwrap();
unimplemented!()
// we assume client will start with a function (instead of a stack)
if has_primordial_stack {
unimplemented!()
} else {
// extract func id
let func_id = primordial_func.unwrap().v.as_func();
// make primordial thread in vm
self.make_primordial_thread(func_id, false, vec![]); // do not pass const args, use argc/argv
// emit context (serialized vm, etc)
backend::emit_context(self);
// link
self.link_boot_image(whitelist_funcs, output_file);
}
}
#[cfg(feature = "aot")]
fn link_boot_image(&self, funcs: Vec<MuID>, output_file: String) {
use testutil;
trace!("Linking boot image...");
let func_names = {
let funcs_guard = self.funcs().read().unwrap();
funcs.iter().map(|x| funcs_guard.get(x).unwrap().read().unwrap().name().unwrap()).collect()
};
trace!("functions: {:?}", func_names);
trace!("output : {}", output_file);
if output_file.ends_with("dylib") || output_file.ends_with("so") {
// compile as dynamic library
testutil::aot::link_dylib(func_names, &output_file, self);
} else {
// compile as executable
testutil::aot::link_primordial(func_names, &output_file, self);
}
trace!("Done!");
}
// -- API ---
......@@ -1197,6 +1250,15 @@ impl <'a> VM {
})
}
pub fn handle_from_func(&self, id: MuID) -> APIHandleResult {
let handle_id = self.next_id();
self.new_handle(APIHandle {
id: handle_id,
v : APIHandleValue::Func(id)
})
}
pub fn handle_from_global(&self, id: MuID) -> APIHandleResult {
let global_iref = {
let global_locs = self.global_locations.read().unwrap();
......
......@@ -989,7 +989,6 @@ def test_exception_stack_unwind():
assert fnp(100) == 10
@pytest.mark.xfail(reason='not implemented yet')
@may_spawn_proc
def test_make_boot_image_simple():
c_printf = rffi.llexternal('printf', [rffi.CCHARP], rffi.INT, _nowrapper=True)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment