Commit f6bac8b3 authored by qinsoon's avatar qinsoon

[wip] working on NEW instruction

parent c281eacf
......@@ -669,7 +669,17 @@ impl fmt::Display for MemoryLocation {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&MemoryLocation::Address{ref base, ref offset, ref index, scale} => {
write!(f, "{} + {} + {} * {}", base, offset.as_ref().unwrap(), index.as_ref().unwrap(), scale.unwrap())
// base
write!(f, "[{}", base).unwrap();
// offset
if offset.is_some() {
write!(f, " + {}", offset.as_ref().unwrap()).unwrap();
}
// index/scale
if index.is_some() && scale.is_some() {
write!(f, " + {} * {}", index.as_ref().unwrap(), scale.unwrap()).unwrap();
}
write!(f, "]")
}
&MemoryLocation::Symbolic{ref base, ref label} => {
if base.is_some() {
......
......@@ -10,6 +10,7 @@ use ast::types;
use ast::types::*;
use vm::VM;
use vm::CompiledFunction;
use runtime::mm;
use runtime::ValueLocation;
use runtime::thread;
use runtime::entrypoints;
......@@ -424,6 +425,20 @@ impl <'a> InstructionSelection {
self.emit_runtime_entry(&entrypoints::SWAP_BACK_TO_NATIVE_STACK, vec![tl.clone()], f_content, f_context, vm);
}
Instruction_::New(ref ty) => {
let ty_info = vm.get_backend_type_info(ty.id());
if ty_info.size > mm::LARGE_OBJECT_THRESHOLD {
// emit large object allocation
unimplemented!()
} else {
// emit immix allocation
// get allocator
let tl = self.emit_get_threadlocal(f_content, f_context, vm);
}
}
_ => unimplemented!()
} // main switch
......
......@@ -15,6 +15,7 @@ pub mod heap;
pub use heap::immix::ImmixMutatorLocal as Mutator;
use utils::ObjectReference;
use heap::immix::BYTES_IN_LINE;
use heap::immix::ImmixSpace;
use heap::immix::ImmixMutatorLocal;
use heap::freelist;
......@@ -25,6 +26,8 @@ use std::sync::Arc;
use std::sync::RwLock;
use std::boxed::Box;
pub const LARGE_OBJECT_THRESHOLD : usize = BYTES_IN_LINE;
#[repr(C)]
pub struct GC {
immix_space: Arc<ImmixSpace>,
......
......@@ -216,13 +216,15 @@ lazy_static! {
pub static ref NATIVE_SP_LOC_OFFSET : usize = mem::size_of::<MuEntityHeader>()
+ mem::size_of::<Box<mm::Mutator>>()
+ mem::size_of::<Option<Box<MuStack>>>();
pub static ref ALLOCATOR_OFFSET : usize = mem::size_of::<MuEntityHeader>();
}
#[cfg(target_arch = "x86_64")]
#[cfg(target_os = "macos")]
#[link(name = "runtime")]
extern "C" {
fn set_thread_local(thread: *mut MuThread);
pub fn set_thread_local(thread: *mut MuThread);
pub fn get_thread_local() -> Address;
}
......@@ -245,6 +247,16 @@ impl MuThread {
}
}
pub fn fake_thread(id: MuID, allocator: Box<mm::Mutator>) -> MuThread {
MuThread {
hdr: MuEntityHeader::unnamed(id),
allocator: allocator,
stack: None,
native_sp_loc: unsafe {Address::zero()},
user_tls: None
}
}
#[no_mangle]
#[allow(unused_variables)]
pub extern fn mu_thread_launch(id: MuID, stack: Box<MuStack>, user_tls: Option<Address>, vm: &VM) -> JoinHandle<()> {
......
......@@ -189,19 +189,19 @@ impl Decodable for VM {
}
// backend_type_info
let backend_type_info = try!(d.read_struct_field("backend_type_info", 4, |d| Decodable::decode(d)));
let backend_type_info = try!(d.read_struct_field("backend_type_info", 5, |d| Decodable::decode(d)));
// constants
let constants = try!(d.read_struct_field("constants", 5, |d| Decodable::decode(d)));
let constants = try!(d.read_struct_field("constants", 6, |d| Decodable::decode(d)));
// globals
let globals = try!(d.read_struct_field("globals", 6, |d| Decodable::decode(d)));
let globals = try!(d.read_struct_field("globals", 7, |d| Decodable::decode(d)));
// func sigs
let func_sigs = try!(d.read_struct_field("func_sigs", 7, |d| Decodable::decode(d)));
let func_sigs = try!(d.read_struct_field("func_sigs", 8, |d| Decodable::decode(d)));
// funcs
let funcs = try!(d.read_struct_field("funcs", 8, |d| {
let funcs = try!(d.read_struct_field("funcs", 9, |d| {
d.read_map(|d, len| {
let mut map = HashMap::new();
for i in 0..len {
......@@ -214,7 +214,7 @@ impl Decodable for VM {
}));
// func_vers
let func_vers = try!(d.read_struct_field("func_vers", 9, |d| {
let func_vers = try!(d.read_struct_field("func_vers", 10, |d| {
d.read_map(|d, len| {
let mut map = HashMap::new();
for i in 0..len {
......@@ -227,9 +227,9 @@ impl Decodable for VM {
}));
// primordial
let primordial = try!(d.read_struct_field("primordial", 10, |d| Decodable::decode(d)));
let primordial = try!(d.read_struct_field("primordial", 11, |d| Decodable::decode(d)));
let is_running = try!(d.read_struct_field("is_running", 11, |d| Decodable::decode(d)));
let is_running = try!(d.read_struct_field("is_running", 12, |d| Decodable::decode(d)));
let vm = VM{
next_id: ATOMIC_USIZE_INIT,
......
......@@ -2,4 +2,5 @@ mod test_pre_instsel;
mod test_instsel;
mod test_regalloc;
mod test_global;
mod test_compiler;
\ No newline at end of file
mod test_compiler;
mod test_alloc;
\ No newline at end of file
extern crate log;
extern crate simple_logger;
extern crate libloading;
extern crate mu;
use self::mu::ast::types::*;
use self::mu::ast::ir::*;
use self::mu::ast::inst::*;
use self::mu::vm::*;
use self::mu::compiler::*;
use self::mu::runtime::thread;
use self::mu::runtime::thread::MuThread;
use self::mu::runtime::mm;
use self::mu::utils::ByteSize;
use std::sync::Arc;
use std::sync::RwLock;
use std::collections::HashMap;
use aot;
#[test]
fn test_instruction_new() {
simple_logger::init_with_level(log::LogLevel::Trace).ok();
let vm = Arc::new(alloc_new());
let compiler = Compiler::new(CompilerPolicy::default(), vm.clone());
let func_id = vm.id_of("alloc_new");
{
let funcs = vm.funcs().read().unwrap();
let func = funcs.get(&func_id).unwrap().read().unwrap();
let func_vers = vm.func_vers().read().unwrap();
let mut func_ver = func_vers.get(&func.cur_ver.unwrap()).unwrap().write().unwrap();
compiler.compile(&mut func_ver);
}
backend::emit_context(&vm);
let dylib = aot::link_dylib(vec![Mu("fac")], "liballoc_new.dylib");
let lib = libloading::Library::new(dylib.as_os_str()).unwrap();
unsafe {
let alloc_new : libloading::Symbol<unsafe extern fn() -> u64> = lib.get(b"alloc_new").unwrap();
// before invoking it, we need to disguise current thread as mu thread (having an allocator)
fake_mutator_for_cur_thread(&vm);
let ret = alloc_new();
println!("return value from alloc_new is {}", ret);
assert!(ret == 1);
}
}
fn fake_mutator_for_cur_thread(vm: &VM) {
// init gc
const IMMIX_SPACE_SIZE : ByteSize = 500 << 20;
const LO_SPACE_SIZE : ByteSize = 500 << 20;
mm::gc_init(IMMIX_SPACE_SIZE, LO_SPACE_SIZE, 8);
let mut mutator = mm::new_mutator();
let muthread : *mut MuThread = Box::into_raw(Box::new(MuThread::fake_thread(vm.next_id(), mutator)));
unsafe {thread::set_thread_local(muthread)};
}
#[allow(unused_variables)]
pub fn alloc_new() -> VM {
let vm = VM::new();
// .typedef @int64 = int<64>
// .typedef @iref_int64 = iref<int<64>>
let type_def_int64 = vm.declare_type(vm.next_id(), MuType_::int(64));
vm.set_name(type_def_int64.as_entity(), "int64".to_string());
let type_def_iref_int64 = vm.declare_type(vm.next_id(), MuType_::iref(type_def_int64.clone()));
vm.set_name(type_def_iref_int64.as_entity(), "iref_int64".to_string());
let type_def_ref_int64 = vm.declare_type(vm.next_id(), MuType_::muref(type_def_int64.clone()));
vm.set_name(type_def_ref_int64.as_entity(), "ref_int64".to_string());
// .const @int_64_0 <@int_64> = 0
// .const @int_64_1 <@int_64> = 1
let const_def_int64_0 = vm.declare_const(vm.next_id(), type_def_int64.clone(), Constant::Int(0));
vm.set_name(const_def_int64_0.as_entity(), "int64_0".to_string());
let const_def_int64_1 = vm.declare_const(vm.next_id(), type_def_int64.clone(), Constant::Int(1));
vm.set_name(const_def_int64_1.as_entity(), "int64_1".to_string());
// .funcsig @alloc_new_sig = () -> (@int64)
let func_sig = vm.declare_func_sig(vm.next_id(), vec![], vec![type_def_int64.clone()]);
vm.set_name(func_sig.as_entity(), "alloc_new_sig".to_string());
// .funcdecl @alloc_new <@alloc_new_sig>
let func = MuFunction::new(vm.next_id(), func_sig.clone());
vm.set_name(func.as_entity(), "alloc_new".to_string());
let func_id = func.id();
vm.declare_func(func);
// .funcdef @alloc VERSION @v1 <@alloc_new_sig>
let mut func_ver = MuFunctionVersion::new(vm.next_id(), func_id, func_sig.clone());
// %blk_0():
let mut blk_0 = Block::new(vm.next_id());
vm.set_name(blk_0.as_entity(), "blk_0".to_string());
// %a = NEW <@int64_t>
let blk_0_a = func_ver.new_ssa(vm.next_id(), type_def_ref_int64.clone());
vm.set_name(blk_0_a.as_entity(), "blk_0_a".to_string());
let blk_0_inst0 = func_ver.new_inst(vm.next_id(), Instruction{
value: Some(vec![blk_0_a.clone_value()]),
ops: RwLock::new(vec![]),
v: Instruction_::New(type_def_int64.clone())
});
// %a_iref = GETIREF <@int_64> @a
let blk_0_a_iref = func_ver.new_ssa(vm.next_id(), type_def_iref_int64.clone());
vm.set_name(blk_0_a.as_entity(), "blk_0_a_iref".to_string());
let blk_0_inst1 = func_ver.new_inst(vm.next_id(), Instruction{
value: Some(vec![blk_0_a_iref.clone_value()]),
ops: RwLock::new(vec![blk_0_a.clone()]),
v: Instruction_::GetIRef(0)
});
// STORE <@int_64> @a @int_64_1
let blk_0_const_int64_1 = func_ver.new_constant(vm.next_id(), const_def_int64_1.clone());
let blk_0_inst2 = func_ver.new_inst(vm.next_id(), Instruction{
value: None,
ops: RwLock::new(vec![blk_0_a.clone(), blk_0_const_int64_1.clone()]),
v: Instruction_::Store{
is_ptr: false,
order: MemoryOrder::Relaxed,
mem_loc: 0,
value: 1
}
});
// %x = LOAD <@int_64> @a_iref
let blk_0_x = func_ver.new_ssa(vm.next_id(), type_def_int64.clone());
vm.set_name(blk_0_x.as_entity(), "blk_0_x".to_string());
let blk_0_inst3 = func_ver.new_inst(vm.next_id(), Instruction{
value: Some(vec![blk_0_x.clone_value()]),
ops: RwLock::new(vec![blk_0_a_iref.clone()]),
v: Instruction_::Load{
is_ptr: false,
order: MemoryOrder::Relaxed,
mem_loc: 0
}
});
let blk_0_term = func_ver.new_inst(vm.next_id(), Instruction{
value: None,
ops: RwLock::new(vec![blk_0_x.clone()]),
v: Instruction_::Return(vec![0])
});
let blk_0_content = BlockContent {
args: vec![],
body: vec![blk_0_inst0, blk_0_inst1, blk_0_inst2, blk_0_term],
keepalives: None
};
blk_0.content = Some(blk_0_content);
func_ver.define(FunctionContent{
entry: blk_0.id(),
blocks: {
let mut ret = HashMap::new();
ret.insert(blk_0.id(), blk_0);
ret
}
});
vm.define_func_version(func_ver);
vm
}
\ No newline at end of file
......@@ -455,119 +455,5 @@ pub fn global_access() -> VM {
vm.define_func_version(func_ver);
vm
}
#[test]
#[allow(unused_variables)]
fn test_alloc_new() {
let vm = alloc_new();
}
#[allow(unused_variables)]
pub fn alloc_new() -> VM {
let vm = VM::new();
// .typedef @int64 = int<64>
// .typedef @iref_int64 = iref<int<64>>
let type_def_int64 = vm.declare_type(vm.next_id(), MuType_::int(64));
vm.set_name(type_def_int64.as_entity(), "int64".to_string());
let type_def_iref_int64 = vm.declare_type(vm.next_id(), MuType_::iref(type_def_int64.clone()));
vm.set_name(type_def_iref_int64.as_entity(), "iref_int64".to_string());
let type_def_ref_int64 = vm.declare_type(vm.next_id(), MuType_::muref(type_def_int64.clone()));
vm.set_name(type_def_ref_int64.as_entity(), "ref_int64".to_string());
// .const @int_64_0 <@int_64> = 0
// .const @int_64_1 <@int_64> = 1
let const_def_int64_0 = vm.declare_const(vm.next_id(), type_def_int64.clone(), Constant::Int(0));
vm.set_name(const_def_int64_0.as_entity(), "int64_0".to_string());
let const_def_int64_1 = vm.declare_const(vm.next_id(), type_def_int64.clone(), Constant::Int(1));
vm.set_name(const_def_int64_1.as_entity(), "int64_1".to_string());
// .funcsig @alloc_new_sig = () -> ()
let func_sig = vm.declare_func_sig(vm.next_id(), vec![], vec![]);
vm.set_name(func_sig.as_entity(), "alloc_new_sig".to_string());
// .funcdecl @alloc_new <@alloc_new_sig>
let func = MuFunction::new(vm.next_id(), func_sig.clone());
vm.set_name(func.as_entity(), "alloc_new".to_string());
let func_id = func.id();
vm.declare_func(func);
// .funcdef @alloc VERSION @v1 <@alloc_new_sig>
let mut func_ver = MuFunctionVersion::new(vm.next_id(), func_id, func_sig.clone());
// %blk_0():
let mut blk_0 = Block::new(vm.next_id());
vm.set_name(blk_0.as_entity(), "blk_0".to_string());
// %a = NEW <@int64_t>
let blk_0_a = func_ver.new_ssa(vm.next_id(), type_def_ref_int64.clone());
vm.set_name(blk_0_a.as_entity(), "blk_0_a".to_string());
let blk_0_inst0 = func_ver.new_inst(vm.next_id(), Instruction{
value: Some(vec![blk_0_a.clone_value()]),
ops: RwLock::new(vec![]),
v: Instruction_::New(type_def_int64.clone())
});
// STORE <@int_64> @a @int_64_1
let blk_0_const_int64_1 = func_ver.new_constant(vm.next_id(), const_def_int64_1.clone());
let blk_0_inst0 = func_ver.new_inst(vm.next_id(), Instruction{
value: None,
ops: RwLock::new(vec![blk_0_a.clone(), blk_0_const_int64_1.clone()]),
v: Instruction_::Store{
is_ptr: false,
order: MemoryOrder::Relaxed,
mem_loc: 0,
value: 1
}
});
// %a_iref = GETIREF <@int_64> @a
let blk_0_a_iref = func_ver.new_ssa(vm.next_id(), type_def_iref_int64.clone());
vm.set_name(blk_0_a.as_entity(), "blk_0_a_iref".to_string());
let blk_0_inst1 = func_ver.new_inst(vm.next_id(), Instruction{
value: Some(vec![blk_0_a_iref.clone_value()]),
ops: RwLock::new(vec![blk_0_a.clone()]),
v: Instruction_::GetIRef(0)
});
// %x = LOAD <@int_64> @a_iref
let blk_0_x = func_ver.new_ssa(vm.next_id(), type_def_int64.clone());
vm.set_name(blk_0_x.as_entity(), "blk_0_x".to_string());
let blk_0_inst2 = func_ver.new_inst(vm.next_id(), Instruction{
value: Some(vec![blk_0_x.clone_value()]),
ops: RwLock::new(vec![blk_0_a_iref.clone()]),
v: Instruction_::Load{
is_ptr: false,
order: MemoryOrder::Relaxed,
mem_loc: 0
}
});
let blk_0_term = func_ver.new_inst(vm.next_id(), Instruction{
value: None,
ops: RwLock::new(vec![blk_0_x.clone()]),
v: Instruction_::Return(vec![0])
});
let blk_0_content = BlockContent {
args: vec![],
body: vec![blk_0_inst0, blk_0_inst1, blk_0_inst2, blk_0_term],
keepalives: None
};
blk_0.content = Some(blk_0_content);
func_ver.define(FunctionContent{
entry: blk_0.id(),
blocks: {
let mut ret = HashMap::new();
ret.insert(blk_0.id(), blk_0);
ret
}
});
vm.define_func_version(func_ver);
vm
}
\ No newline at end of file
mod test_thread;
mod test_alloc;
mod test_gc_harness;
mod test_gc;
//disable this for now - it doesnt run
......
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