Commit 06c91e7f authored by qinsoon's avatar qinsoon

persisting hybrid works

parent 65b51d5f
Pipeline #250 failed with stage
in 24 minutes and 36 seconds
......@@ -83,6 +83,18 @@ impl MuType {
}
}
pub fn get_hybrid_varpart_ty(&self) -> Option<P<MuType>> {
match self.v {
MuType_::Hybrid(ref tag) => {
let map_lock = HYBRID_TAG_MAP.read().unwrap();
let hybrid_inner = map_lock.get(tag).unwrap();
Some(hybrid_inner.var_ty.clone())
},
_ => None
}
}
pub fn get_referenced_ty(&self) -> Option<P<MuType>> {
use types::MuType_::*;
match self.v {
......
......@@ -13,7 +13,7 @@ use vm::VM;
use runtime::ValueLocation;
use runtime::thread::MuThread;
fn allocate(size: ByteSize, align: ByteSize, encode: u64) -> ObjectReference {
fn allocate(size: ByteSize, align: ByteSize, encode: u64, hybrid_len: Option<u64>) -> ObjectReference {
let allocator = (&mut MuThread::current_mut().allocator) as *mut Mutator;
let ret = if size > LARGE_OBJECT_THRESHOLD {
......@@ -22,7 +22,11 @@ fn allocate(size: ByteSize, align: ByteSize, encode: u64) -> ObjectReference {
alloc(allocator, size, align)
};
muentry_init_object(allocator, ret, encode);
if hybrid_len.is_none() {
muentry_init_object(allocator, ret, encode);
} else {
muentry_init_hybrid(allocator, ret, encode, hybrid_len.unwrap());
}
ret
}
......@@ -36,27 +40,29 @@ pub fn allocate_fixed(ty: P<MuType>, vm: &VM) -> Address {
trace!("API: gc ty : {:?}", gctype);
trace!("API: encode : {:b}", encode);
allocate(backendtype.size, backendtype.alignment, encode).to_address()
allocate(gctype.size(), gctype.alignment, encode, None).to_address()
}
pub fn allocate_global(value: P<Value>, vm: &VM) -> ValueLocation {
let tyid = value.ty.id();
pub fn allocate_hybrid(ty: P<MuType>, len: u64, vm: &VM) -> Address {
let backendtype = vm.get_backend_type_info((ty.id()));
let gctype = backendtype.gc_type.clone();
let encode = get_gc_type_encode(gctype.id);
let referenced_type = match value.ty.get_referenced_ty() {
Some(ty) => ty,
None => panic!("expected global to be an iref type, found {}", value.ty)
};
trace!("API: allocate fixed ty: {}", ty);
trace!("API: gc ty : {:?}", gctype);
trace!("API: encode : {:b}", encode);
let backendtype = vm.get_backend_type_info(referenced_type.id());
let gctype = backendtype.gc_type.clone();
let gctype_id = gctype.id;
let encode = get_gc_type_encode(gctype_id);
allocate(gctype.size_hybrid(len as u32), gctype.alignment, encode, Some(len)).to_address()
}
trace!("API: allocate global ty: {}", referenced_type);
trace!("API: gc ty : {:?}", gctype);
trace!("API: encode : {:b}", encode);
pub fn allocate_global(iref_global: P<Value>, vm: &VM) -> ValueLocation {
let tyid = iref_global.ty.id();
let addr = allocate(backendtype.size, backendtype.alignment, encode).to_address();
let referenced_type = match iref_global.ty.get_referenced_ty() {
Some(ty) => ty,
None => panic!("expected global to be an iref type, found {}", iref_global.ty)
};
let addr = allocate_fixed(referenced_type, vm);
ValueLocation::Direct(RegGroup::GPR, addr)
}
......@@ -61,14 +61,21 @@ impl APIHandleValue {
pub fn as_ref(&self) -> (P<MuType>, Address) {
match self {
&APIHandleValue::Ref(ref ty, addr) => (ty.clone(), addr),
_ => panic!("expected Ref")
_ => panic!("expected Ref handle")
}
}
pub fn as_iref(&self) -> (P<MuType>, Address) {
match self {
&APIHandleValue::IRef(ref ty, addr) => (ty.clone(), addr),
_ => panic!("expected IRef")
_ => panic!("expected IRef handle")
}
}
pub fn as_int(&self) -> u64 {
match self {
&APIHandleValue::Int(val, _) => val,
_ => panic!("expected Int handle")
}
}
}
......
......@@ -869,6 +869,19 @@ impl <'a> VM {
})
}
pub fn new_hybrid(&self, tyid: MuID, length: Arc<APIHandle>) -> Arc<APIHandle> {
let ty = self.get_type(tyid);
let len = self.handle_to_uint64(length);
let addr = gc::allocate_hybrid(ty.clone(), len, self);
trace!("API: allocated hybrid type {} of length {} at {}", ty, len, addr);
self.new_handle(APIHandle {
id: self.next_id(),
v: APIHandleValue::Ref(ty, addr)
})
}
pub fn handle_get_iref(&self, handle_ref: Arc<APIHandle>) -> Arc<APIHandle> {
let (ty, addr) = handle_ref.v.as_ref();
......@@ -879,6 +892,40 @@ impl <'a> VM {
})
}
pub fn handle_shift_iref(&self, handle_iref: Arc<APIHandle>, offset: Arc<APIHandle>) -> Arc<APIHandle> {
let (ty, addr) = handle_iref.v.as_iref();
let offset = self.handle_to_uint64(offset);
let offset_addr = {
let backend_ty = self.get_backend_type_info(ty.id());
addr.plus(backend_ty.size * (offset as usize))
};
self.new_handle(APIHandle {
id: self.next_id(),
v : APIHandleValue::IRef(ty, offset_addr)
})
}
pub fn handle_get_var_part_iref(&self, handle_iref: Arc<APIHandle>) -> Arc<APIHandle> {
let (ty, addr) = handle_iref.v.as_iref();
let varpart_addr = {
let backend_ty = self.get_backend_type_info(ty.id());
addr.plus(backend_ty.size)
};
let varpart_ty = match ty.get_hybrid_varpart_ty() {
Some(ty) => ty,
None => panic!("cannot get varpart ty from {}", ty)
};
self.new_handle(APIHandle {
id: self.next_id(),
v : APIHandleValue::IRef(varpart_ty, varpart_addr)
})
}
pub fn handle_get_field_iref(&self, handle_iref: Arc<APIHandle>, field: usize) -> Arc<APIHandle> {
let (ty, addr) = handle_iref.v.as_iref();
......@@ -926,4 +973,8 @@ impl <'a> VM {
v : APIHandleValue::Int(num, len)
})
}
pub fn handle_to_uint64(&self, handle: Arc<APIHandle>) -> u64 {
handle.v.as_int()
}
}
macro_rules! typedef {
// int, floating point
(($vm: expr) $name: ident = mu_int($len: expr)) => {
let $name = $vm.declare_type($vm.next_id(), MuType_::int($len));
$vm.set_name($name.as_entity(), Mu(stringify!($name)));
......@@ -8,6 +9,7 @@ macro_rules! typedef {
$vm.set_name($name.as_entity(), Mu(stringify!($name)));
};
// ref, iref, ptr
(($vm: expr) $name: ident = mu_ref($ty: ident)) => {
let $name = $vm.declare_type($vm.next_id(), MuType_::muref($ty.clone()));
$vm.set_name($name.as_entity(), Mu(stringify!($name)));
......@@ -21,6 +23,7 @@ macro_rules! typedef {
$vm.set_name($name.as_entity(), Mu(stringify!($name)));
};
// struct
(($vm: expr) $name: ident = mu_struct($($ty: ident), *)) => {
let $name = $vm.declare_type($vm.next_id(), MuType_::mustruct(Mu(stringify!($name)), vec![$($ty.clone()),*]));
$vm.set_name($name.as_entity(), Mu(stringify!($name)));
......@@ -37,6 +40,7 @@ macro_rules! typedef {
MuType_::mustruct_put(&Mu(stringify!($name)), vec![$($ty.clone()), *])
};
// hybrid
(($vm: expr) $name: ident = mu_hybrid($($ty: ident), *); $var_ty: ident) => {
let $name = $vm.declare_type($vm.next_id(), MuType_::hybrid(Mu(stringify!($name)), vec![$($ty.clone()), *], $var_ty.clone()));
$vm.set_name($name.as_entity(), Mu(stringify!($name)));
......@@ -46,6 +50,7 @@ macro_rules! typedef {
$vm.set_name($name.as_entity(), Mu(stringify!($name)));
};
// funcref
(($vm: expr) $name: ident = mu_funcref($sig: ident)) => {
let $name = $vm.declare_type($vm.next_id(), MuType_::funcref($sig.clone()));
$vm.set_name($name.as_entity(), Mu(stringify!($name)));
......
......@@ -195,7 +195,7 @@ fn test_persist_linked_list() {
assert!(output.status.code().is_some());
let ret_code = output.status.code().unwrap();
println!("return code: {} (i.e. the value set before)", ret_code);
println!("return code: {}", ret_code);
assert!(ret_code == 10);
}
......@@ -250,7 +250,7 @@ fn persist_linked_list(vm: &VM) {
cond = CMPOP (CmpOp::EQ) cursor ref_node_null_local
);
// BRANCH2 exit[sum] loop_body[cursor, sum]
// BRANCH2 cond exit[sum] loop_body[cursor, sum]
block! ((vm, persist_linked_list_v1) blk_exit);
block! ((vm, persist_linked_list_v1) blk_loop_body);
inst! ((vm, persist_linked_list_v1) blk_loop_head_branch2:
......@@ -335,4 +335,224 @@ fn persist_linked_list(vm: &VM) {
define_func_ver!((vm) persist_linked_list_v1 (entry: blk_entry) {
blk_entry, blk_loop_head, blk_loop_body, blk_exit
});
}
#[test]
fn test_persist_hybrid() {
VM::start_logging_trace();
let vm = Arc::new(VM::new());
unsafe {
MuThread::current_thread_as_mu_thread(Address::zero(), vm.clone());
}
persist_hybrid(&vm);
let compiler = Compiler::new(CompilerPolicy::default(), vm.clone());
let func_id = vm.id_of("persist_hybrid");
{
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);
}
// create hybrid by api
const HYBRID_LENGTH : usize = 5;
{
let hybrid_tyid = vm.id_of("hybrid");
let hybrid_len = vm.handle_from_uint64(HYBRID_LENGTH as u64, 64);
let hybrid = vm.new_hybrid(hybrid_tyid, hybrid_len);
let hybrid_iref = vm.handle_get_iref(hybrid.clone());
let hybrid_varpart = vm.handle_get_var_part_iref(hybrid_iref);
// create int64 objects to fill var part
let int64_tyid = vm.id_of("int64");
for i in 0..HYBRID_LENGTH {
// new node
let node_ref = vm.new_fixed(int64_tyid);
let node_iref = vm.handle_get_iref(node_ref.clone());
// store i into node
let int_handle = vm.handle_from_uint64(i as u64, 64);
handle::store(MemoryOrder::Relaxed, node_iref, int_handle.clone());
// store node to hybrid
let hybrid_cell = vm.handle_shift_iref(hybrid_varpart.clone(), int_handle);
handle::store(MemoryOrder::Relaxed, hybrid_cell, node_ref);
}
// store last_node in global
let global_id = vm.id_of("my_global");
let global_handle = vm.handle_from_global(global_id);
handle::store(MemoryOrder::Relaxed, global_handle, hybrid);
}
// then emit context (global will be put into context.s
vm.make_primordial_thread(func_id, vec![Constant::Int(HYBRID_LENGTH as u64)]);
backend::emit_context(&vm);
// link
let executable = aot::link_primordial(vec![Mu("persist_hybrid")], "persist_hybrid_test", &vm);
let output = aot::execute_nocheck(executable);
assert!(output.status.code().is_some());
let ret_code = output.status.code().unwrap();
println!("return code: {}", ret_code);
assert!(ret_code == 10);
}
fn persist_hybrid(vm: &VM) {
typedef! ((vm) int1 = mu_int(1));
typedef! ((vm) int64 = mu_int(64));
typedef! ((vm) ref_int64 = mu_ref(int64));
typedef! ((vm) iref_int64 = mu_iref(int64));
typedef! ((vm) hybrid = mu_hybrid(none; ref_int64));
typedef! ((vm) ref_hybrid = mu_ref(hybrid));
typedef! ((vm) iref_ref_hybrid = mu_iref(ref_hybrid));
typedef! ((vm) iref_ref_int64 = mu_iref(ref_int64));
globaldef! ((vm) <ref_hybrid> my_global);
constdef! ((vm) <int64> int64_0 = Constant::Int(0));
constdef! ((vm) <int64> int64_1 = Constant::Int(1));
funcsig! ((vm) sig = (int64) -> (int64));
funcdecl! ((vm) <sig> persist_hybrid);
funcdef! ((vm) <sig> persist_hybrid VERSION persist_hybrid_v1);
// --- blk entry ---
block! ((vm, persist_hybrid_v1) blk_entry);
ssa! ((vm, persist_hybrid_v1) <int64> hybrid_len);
global! ((vm, persist_hybrid_v1) blk_entry_my_global = my_global);
// %h = LOAD %blk_entry_my_global
ssa! ((vm, persist_hybrid_v1) <ref_hybrid> h);
inst! ((vm, persist_hybrid_v1) blk_entry_load:
h = LOAD blk_entry_my_global (is_ptr: false, order: MemoryOrder::SeqCst)
);
// %var_h = GETVARPARTIREF %h
ssa! ((vm, persist_hybrid_v1) <iref_ref_int64> var_h);
inst! ((vm, persist_hybrid_v1) blk_entry_getvarpart:
var_h = GETVARPARTIREF h (is_ptr: false)
);
// BRANCH loop_head (varpart: %var_h, sum: 0, i: 0, n: %hybrid_len)
block! ((vm, persist_hybrid_v1) blk_loop_head);
consta! ((vm, persist_hybrid_v1) int64_0_local = int64_0);
inst! ((vm, persist_hybrid_v1) blk_entry_branch:
BRANCH blk_loop_head (var_h, int64_0_local, int64_0_local, hybrid_len)
);
define_block! ((vm, persist_hybrid_v1) blk_entry(hybrid_len) {
blk_entry_load, blk_entry_getvarpart, blk_entry_branch
});
// --- blk loop_head ---
ssa! ((vm, persist_hybrid_v1) <iref_ref_int64> head_varpart);
ssa! ((vm, persist_hybrid_v1) <int64> head_sum);
ssa! ((vm, persist_hybrid_v1) <int64> head_i);
ssa! ((vm, persist_hybrid_v1) <int64> head_n);
// %cond = CMP ULT %i %n
ssa! ((vm, persist_hybrid_v1) <int1> cond);
inst! ((vm, persist_hybrid_v1) blk_loop_head_cmp:
cond = CMPOP (CmpOp::ULT) head_i head_n
);
// BRANCH2 cond loop_body[varpart, sum, i, n] exit[sum]
block! ((vm, persist_hybrid_v1) blk_loop_body);
block! ((vm, persist_hybrid_v1) blk_exit);
inst! ((vm, persist_hybrid_v1) blk_loop_head_branch2:
BRANCH2 (cond, head_varpart, head_sum, head_i, head_n)
IF (OP 0)
THEN blk_loop_body (vec![1, 2, 3, 4]) WITH 0.9f32,
ELSE blk_exit (vec![2])
);
define_block! ((vm, persist_hybrid_v1) blk_loop_head(head_varpart, head_sum, head_i, head_n) {
blk_loop_head_cmp, blk_loop_head_branch2
});
// --- blk loop_body ---
ssa! ((vm, persist_hybrid_v1) <iref_ref_int64> varpart);
ssa! ((vm, persist_hybrid_v1) <int64> sum);
ssa! ((vm, persist_hybrid_v1) <int64> i);
ssa! ((vm, persist_hybrid_v1) <int64> n);
// %cell = SHIFTIREF %varpart %i
ssa! ((vm, persist_hybrid_v1) <iref_ref_int64> cell);
inst! ((vm, persist_hybrid_v1) blk_loop_body_shiftiref:
cell = SHIFTIREF varpart i (is_ptr: false)
);
// %int_obj = LOAD %cell
ssa! ((vm, persist_hybrid_v1) <ref_int64> int_obj);
inst! ((vm, persist_hybrid_v1) blk_loop_body_load_obj:
int_obj = LOAD cell (is_ptr: false, order: MemoryOrder::SeqCst)
);
// %iref_int_obj = GETIREF %int_obj
ssa! ((vm, persist_hybrid_v1) <iref_int64> iref_int_obj);
inst! ((vm, persist_hybrid_v1) blk_loop_body_getiref:
iref_int_obj = GETIREF int_obj
);
// %val = LOAD %iref_int_obj
ssa! ((vm, persist_hybrid_v1) <int64> val);
inst! ((vm, persist_hybrid_v1) blk_loop_body_load_val:
val = LOAD iref_int_obj (is_ptr: false, order: MemoryOrder::SeqCst)
);
// %sum2 = BINOP ADD sum val
ssa! ((vm, persist_hybrid_v1) <int64> sum2);
inst! ((vm, persist_hybrid_v1) blk_loop_body_add:
sum2 = BINOP (BinOp::Add) sum val
);
// %i2 = BINOP ADD %i 1
ssa! ((vm, persist_hybrid_v1) <int64> i2);
consta! ((vm, persist_hybrid_v1) int64_1_local = int64_1);
inst! ((vm, persist_hybrid_v1) blk_loop_body_add2:
i2 = BINOP (BinOp::Add) i int64_1_local
);
// BRANCH loop_head (%varpart, %sum2, %i2, %n)
inst! ((vm, persist_hybrid_v1) blk_loop_body_branch:
BRANCH blk_loop_head (varpart, sum2, i2, n)
);
define_block! ((vm, persist_hybrid_v1) blk_loop_body(varpart, sum, i, n) {
blk_loop_body_shiftiref,
blk_loop_body_load_obj,
blk_loop_body_getiref,
blk_loop_body_load_val,
blk_loop_body_add,
blk_loop_body_add2,
blk_loop_body_branch
});
// --- blk exit ---
ssa! ((vm, persist_hybrid_v1) <int64> res);
let blk_exit_exit = gen_ccall_exit(res.clone(), &mut persist_hybrid_v1, &vm);
inst! ((vm, persist_hybrid_v1) blk_exit_ret:
RET (res)
);
define_block! ((vm, persist_hybrid_v1) blk_exit(res) {
blk_exit_exit, blk_exit_ret
});
define_func_ver! ((vm) persist_hybrid_v1 (entry: blk_entry) {
blk_entry, blk_loop_head, blk_loop_body, blk_exit
});
}
\ No newline at end of file
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