GitLab will continue to be upgraded from 11.4.5-ce.0 on November 25th 2019 at 4.00pm (AEDT) to 5.00pm (AEDT) due to Critical Security Patch Availability. During the update, GitLab and Mattermost services will not be available.

Commit 83c457ab authored by qinsoon's avatar qinsoon

fix bugs about allocation (wrong field offsets, forgot to add header

size, etc). add PRINTHEX instruction to print a number (for debugging use)
parent d152c68c
......@@ -277,7 +277,9 @@ pub enum Instruction_ {
CommonInst_Unpin(OpIndex),
// internal use: mov from ops[0] to value
Move(OpIndex)
Move(OpIndex),
// internal use: print op as hex value
PrintHex(OpIndex)
}
impl Instruction_ {
......@@ -402,7 +404,9 @@ impl Instruction_ {
&Instruction_::CommonInst_Unpin(op) => format!("COMMONINST Unpin {}", ops[op]),
// move
&Instruction_::Move(from) => format!("MOVE {}", ops[from])
&Instruction_::Move(from) => format!("MOVE {}", ops[from]),
// print hex
&Instruction_::PrintHex(i) => format!("PRINTHEX {}", ops[i])
}
}
}
......
......@@ -32,7 +32,8 @@ pub fn is_terminal_inst(inst: &Instruction_) -> bool {
| &CommonInst_SetThreadLocal(_)
| &CommonInst_Pin(_)
| &CommonInst_Unpin(_)
| &Move(_) => false,
| &Move(_)
| &PrintHex(_) => false,
&Return(_)
| &ThreadExit
| &Throw(_)
......@@ -99,5 +100,6 @@ pub fn has_side_effect(inst: &Instruction_) -> bool {
&CommonInst_Pin(_) => true,
&CommonInst_Unpin(_) => true,
&Move(_) => false,
&PrintHex(_) => true
}
}
......@@ -65,7 +65,8 @@ pub enum OpCode {
CommonInst_Pin,
CommonInst_Unpin,
Move
Move,
PrintHex
}
pub fn pick_op_code_for_ssa(ty: &P<MuType>) -> OpCode {
......@@ -296,5 +297,6 @@ pub fn pick_op_code_for_inst(inst: &Instruction) -> OpCode {
Instruction_::CommonInst_Pin(_) => OpCode::CommonInst_Pin,
Instruction_::CommonInst_Unpin(_) => OpCode::CommonInst_Unpin,
Instruction_::Move(_) => OpCode::Move,
Instruction_::PrintHex(_) => OpCode::PrintHex,
}
}
......@@ -7,6 +7,8 @@ use ast::types;
use ast::types::*;
use vm::VM;
use runtime::mm;
use runtime::mm::objectmodel::OBJECT_HEADER_SIZE;
use runtime::mm::objectmodel::OBJECT_HEADER_OFFSET;
use runtime::ValueLocation;
use runtime::thread;
use runtime::entrypoints;
......@@ -1153,6 +1155,20 @@ impl <'a> InstructionSelection {
None,
Some(node), f_content, f_context, vm);
}
Instruction_::PrintHex(index) => {
trace!("instsel on PRINTHEX");
let ops = inst.ops.read().unwrap();
let ref op = ops[index];
self.emit_runtime_entry(
&entrypoints::PRINT_HEX,
vec![op.clone_value()],
None,
Some(node), f_content, f_context, vm
);
}
_ => unimplemented!()
} // main switch
......@@ -1859,6 +1875,8 @@ impl <'a> InstructionSelection {
tmp_res
}
// this function needs to generate exact same code as alloc() in immix_mutator.rs in GC
// FIXME: currently it is slightly different
fn emit_alloc_sequence_small (&mut self, tmp_allocator: P<Value>, size: P<Value>, align: usize, node: &TreeNode, f_content: &FunctionContent, f_context: &mut FunctionContext, vm: &VM) -> P<Value> {
// emit immix allocation fast path
......@@ -1883,10 +1901,19 @@ impl <'a> InstructionSelection {
// or lea size(%start) -> %end
let tmp_end = self.make_temporary(f_context, ADDRESS_TYPE.clone(), vm);
if size.is_int_const() {
let offset = size.extract_int_const() as i32;
let mut offset = size.extract_int_const() as i32;
if OBJECT_HEADER_SIZE != 0 {
offset += OBJECT_HEADER_SIZE as i32;
}
self.emit_lea_base_immoffset(&tmp_end, &tmp_start, offset, vm);
} else {
self.backend.emit_mov_r_r(&tmp_end, &tmp_start);
if OBJECT_HEADER_SIZE != 0 {
// ASM: add %size, HEADER_SIZE -> %size
self.backend.emit_add_r_imm(&size, OBJECT_HEADER_SIZE as i32);
}
self.backend.emit_add_r_r(&tmp_end, &size);
}
......@@ -1910,9 +1937,14 @@ impl <'a> InstructionSelection {
self.emit_store_base_offset(&tmp_tl, cursor_offset as i32, &tmp_end, vm);
// put start as result
// ASM: mov %start -> %result
let tmp_res = self.get_result_value(node);
self.backend.emit_mov_r_r(&tmp_res, &tmp_start);
if OBJECT_HEADER_OFFSET != 0 {
// ASM: lea -HEADER_OFFSET(%start) -> %result
self.emit_lea_base_immoffset(&tmp_res, &tmp_start, - OBJECT_HEADER_OFFSET as i32, vm);
} else {
// ASM: mov %start -> %result
self.backend.emit_mov_r_r(&tmp_res, &tmp_start);
}
// ASM jmp alloc_end
let allocend = format!("{}_alloc_small_end", node.id());
......
......@@ -519,6 +519,7 @@ pub fn estimate_insts_for_ir(inst: &Instruction) -> usize {
// others
Move(_) => 0,
PrintHex(_) => 10,
ExnInstruction{ref inner, ..} => estimate_insts_for_ir(&inner)
}
}
......@@ -23,6 +23,8 @@ lazy_static! {
pub static ref N_MUTATORS : RwLock<usize> = RwLock::new(0);
}
const TRACE_ALLOC_FASTPATH : bool = true;
#[repr(C)]
// do not change the layout (unless change the offset of fields correspondingly)
pub struct ImmixMutatorLocal {
......@@ -52,7 +54,7 @@ pub struct ImmixMutatorLocal {
lazy_static! {
pub static ref CURSOR_OFFSET : usize = mem::size_of::<usize>()
+ mem::size_of::<*mut u8>()
+ mem::size_of::<*mut u8>() * 2
+ mem::size_of::<Address>();
pub static ref LIMIT_OFFSET : usize = *CURSOR_OFFSET
......@@ -145,11 +147,22 @@ impl ImmixMutatorLocal {
let size = size + objectmodel::OBJECT_HEADER_SIZE;
// end
if TRACE_ALLOC_FASTPATH {
trace!("Mutator{}: fastpath alloc: size={}, align={}", self.id, size, align);
}
let start = self.cursor.align_up(align);
let end = start.plus(size);
if TRACE_ALLOC_FASTPATH {
trace!("Mutator{}: fastpath alloc: start=0x{:x}, end=0x{:x}", self.id, start, end);
}
if end > self.limit {
let ret = self.try_alloc_from_local(size, align);
if TRACE_ALLOC_FASTPATH {
trace!("Mutator{}: fastpath alloc: try_alloc_from_local()=0x{:x}", self.id, ret);
}
if cfg!(debug_assertions) {
if !ret.is_aligned_to(align) {
......@@ -229,8 +242,13 @@ impl ImmixMutatorLocal {
for line in next_available_line..end_line {
self.block().line_mark_table_mut().set(line, immix::LineMark::FreshAlloc);
}
self.alloc(size, align)
// allocate fast path
let start = self.cursor.align_up(align);
let end = start.plus(size);
self.cursor = end;
start
},
None => {
self.alloc_from_global(size, align)
......@@ -263,6 +281,8 @@ impl ImmixMutatorLocal {
self.cursor = self.block().start();
self.limit = self.block().start();
self.line = 0;
trace!("Mutator{}: slowpath: new block starting from 0x{:x}", self.id, self.cursor);
return self.alloc(size, align);
},
......
......@@ -106,4 +106,15 @@ lazy_static! {
aot: ValueLocation::Relocatable(RegGroup::GPR, String::from("muentry_frem")),
jit: RwLock::new(None)
};
// impl/decl: mod.rs
pub static ref PRINT_HEX : RuntimeEntrypoint = RuntimeEntrypoint {
sig: P(MuFuncSig {
hdr: MuEntityHeader::unnamed(ir::new_internal_id()),
ret_tys: vec![],
arg_tys: vec![UINT64_TYPE.clone()]
}),
aot: ValueLocation::Relocatable(RegGroup::GPR, String::from("muentry_print_hex")),
jit: RwLock::new(None)
};
}
......@@ -234,3 +234,9 @@ pub extern fn mu_main(serialized_vm : *const c_char, argc: c_int, argv: *const *
thread.join().unwrap();
}
}
#[no_mangle]
#[allow(unreachable_code)]
pub extern fn muentry_print_hex(x: u64) {
println!("0x{:x}", x);
}
\ No newline at end of file
......@@ -139,6 +139,28 @@ impl fmt::Debug for Address {
}
}
#[cfg(test)]
mod addr_tests {
use super::*;
#[test]
fn test_align_up() {
let addr = Address(0);
let aligned = addr.align_up(8);
assert!(addr == aligned);
}
#[test]
fn test_is_aligned() {
let addr = Address(0);
assert!(addr.is_aligned_to(8));
let addr = Address(8);
assert!(addr.is_aligned_to(8));
}
}
#[derive(Copy, Clone, Eq, Hash)]
pub struct ObjectReference (usize);
......
......@@ -30,7 +30,7 @@ mod tests {
pub fn test_u8_bits() {
let value : u8 = 0b1100_0011;
assert_eq!(test_nth_bit_u8(value, 6), true);
assert_eq!(test_nth_bit_u8(value, 6, 1), true);
assert_eq!(lower_bits_u8(value, 6), 0b00_0011);
}
......
......@@ -436,4 +436,24 @@ macro_rules! inst {
v: Instruction_::Return(vec![])
});
};
// THREADEXIT
(($vm: expr, $fv: ident) $name: ident: THREADEXIT) => {
let $name = $fv.new_inst(Instruction{
hdr: MuEntityHeader::unnamed($vm.next_id()),
value: None,
ops: RwLock::new(vec![]),
v: Instruction_::ThreadExit
});
};
// PRINTHEX
(($vm: expr, $fv: ident) $name: ident: PRINTHEX $val: ident) => {
let $name = $fv.new_inst(Instruction{
hdr: MuEntityHeader::unnamed($vm.next_id()),
value: None,
ops: RwLock::new(vec![$val.clone()]),
v: Instruction_::PrintHex(0)
});
}
}
......@@ -16,6 +16,80 @@ use std::sync::RwLock;
use self::mu::testutil;
use self::mu::testutil::aot;
#[test]
fn test_allocation_fastpath() {
VM::start_logging_trace();
let vm = Arc::new(allocation_fastpath());
let compiler = Compiler::new(CompilerPolicy::default(), &vm);
let func_id = vm.id_of("allocation_fastpath");
{
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);
}
vm.make_primordial_thread(func_id, true, vec![]);
backend::emit_context(&vm);
let executable = aot::link_primordial(vec!["allocation_fastpath".to_string()], "allocation_fastpath_test", &vm);
aot::execute(executable);
}
fn allocation_fastpath() -> VM {
let vm = VM::new();
typedef! ((vm) int1 = mu_int(1));
typedef! ((vm) int64 = mu_int(64));
typedef! ((vm) ref_int64 = mu_ref(int64));
typedef! ((vm) struct_t = mu_struct(int64, int64, ref_int64));
typedef! ((vm) ref_struct_t = mu_ref(struct_t));
funcsig! ((vm) sig = () -> ());
funcdecl! ((vm) <sig> allocation_fastpath);
funcdef! ((vm) <sig> allocation_fastpath VERSION allocation_fastpath_v1);
block! ((vm, allocation_fastpath_v1) blk_entry);
// a = NEW <struct_t>
ssa! ((vm, allocation_fastpath_v1) <ref_struct_t> a);
inst! ((vm, allocation_fastpath_v1) blk_entry_new1:
a = NEW <struct_t>
);
inst! ((vm, allocation_fastpath_v1) blk_entry_print1:
PRINTHEX a
);
ssa! ((vm, allocation_fastpath_v1) <ref_struct_t> b);
inst! ((vm, allocation_fastpath_v1) blk_entry_new2:
b = NEW <struct_t>
);
inst! ((vm, allocation_fastpath_v1) blk_entry_print2:
PRINTHEX b
);
inst! ((vm, allocation_fastpath_v1) blk_entry_threadexit:
THREADEXIT
);
define_block! ((vm, allocation_fastpath_v1) blk_entry() {
blk_entry_new1, blk_entry_print1,
blk_entry_new2, blk_entry_print2,
blk_entry_threadexit
});
define_func_ver!((vm) allocation_fastpath_v1 (entry: blk_entry) {blk_entry});
vm
}
#[test]
fn test_instruction_new() {
VM::start_logging_trace();
......
......@@ -997,7 +997,12 @@ def run_boot_image(entry, output, has_c_main_sig = False, args = [], impl=os.get
t.driver.standalone = True # force standalone
t.driver.exe_name = output
#t.backendopt(inline=True, mallocs=True)
#t.view()
#t.mutype()
#t.view()
db, mugen, epf_name = t.compile_mu()
exe = py.path.local(output)
......
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