RTMu NEWTHREAD and NOTIFYThread are tested now

parent b8e09a51
Pipeline #3759 failed with stages
in 38 minutes and 22 seconds
#trailing_comma = "Never"
......@@ -84,7 +84,7 @@ impl Instruction {
| AllocAHybrid(_, _)
| NewStack(_)
| NewThread { .. }
| NewThreadRT { .. }
| NotifyThread(_)
| NewFrameCursor(_)
| GetIRef(_)
| GetFieldIRef { .. }
......@@ -143,7 +143,7 @@ impl Instruction {
| AllocAHybrid(_, _)
| NewStack(_)
| NewThread { .. }
| NewThreadRT { .. }
| NotifyThread(_)
| NewFrameCursor(_)
| Fence(_)
| Return(_)
......@@ -222,7 +222,7 @@ impl Instruction {
| AllocAHybrid(_, _)
| NewStack(_)
| NewThread { .. }
| NewThreadRT { .. }
| NotifyThread(_)
| NewFrameCursor(_)
| GetIRef(_)
| GetFieldIRef { .. }
......@@ -296,7 +296,7 @@ impl Instruction {
| AllocAHybrid(_, _)
| NewStack(_)
| NewThread { .. }
| NewThreadRT { .. }
| NotifyThread(_)
| NewFrameCursor(_)
| GetIRef(_)
| GetFieldIRef { .. }
......@@ -372,7 +372,7 @@ impl Instruction {
AllocAHybrid(_, _) |
NewStack(_) |
NewThread { .. } |
NewThreadRT { .. } |
NotifyThread(_) |
NewFrameCursor(_) |
GetIRef(_) |
GetFieldIRef { .. } |
......@@ -548,22 +548,8 @@ impl Instruction {
ops[stack], thread_local, new_stack_clause,
)
}
// Fixme write a better debug-str
&Instruction_::NewThreadRT {
attr,
stack,
thread_local,
is_exception,
ref args,
} => {
let new_stack_clause = format_new_stack_clause(is_exception, args, ops);
let thread_local = thread_local
.map(|t| format!(" THREADLOCAL({})", ops[t]))
.unwrap_or("".to_string());
format!(
"NEWTHREADRT {}{}{} {}",
ops[attr], ops[stack], thread_local, new_stack_clause,
)
&Instruction_::NotifyThread(thread) => {
format!("COMMINST @uvm.notifythread({})", ops[thread])
}
&Instruction_::NewFrameCursor(stack) => {
format!("COMMINST @uvm.meta.new_cursor({})", ops[stack])
......@@ -882,7 +868,10 @@ pub enum Instruction_ {
/// a non-terminating CCall instruction (the call does not have an exceptional branch)
/// This instruction is not in the Mu spec, but is documented in the HOL formal spec
ExprCCall { data: CallData, is_abort: bool },
ExprCCall {
data: CallData,
is_abort: bool,
},
/// load instruction
Load {
......@@ -952,15 +941,8 @@ pub enum Instruction_ {
args: Vec<OpIndex>,
},
/// create a new Mu thread, yields thread reference
/// args: stackref of a Mu stack, a list of arguments
NewThreadRT {
attr: OpIndex,
stack: OpIndex,
thread_local: Option<OpIndex>,
is_exception: bool,
args: Vec<OpIndex>,
},
// #[cfg(feature = "realtime")]
NotifyThread(OpIndex),
/// create a frame cursor reference
/// args: stackref of a Mu stack
......@@ -992,7 +974,10 @@ pub enum Instruction_ {
},
/// get internal reference to an element in hybrid var part
GetVarPartIRef { is_ptr: bool, base: OpIndex },
GetVarPartIRef {
is_ptr: bool,
base: OpIndex,
},
/// a fence of certain memory order
Fence(MemoryOrder),
......
......@@ -1396,7 +1396,7 @@ impl<'a> InstructionSelection {
| MemoryOrder::Acquire
| MemoryOrder::SeqCst
| MemoryOrder::NotAtomic => {}
_ => panic!("unsupported order {:?} for LOAD", order),
_ => panic!("unsupported ofrder {:?} for LOAD", order),
}
let resolved_loc =
......@@ -1989,6 +1989,26 @@ impl<'a> InstructionSelection {
}
}
#[cfg(feature = "realtime")]
Instruction_::NotifyThread(thread) => {
trace!("instsel on NotifyThread");
let ref ops = inst.ops;
let ref thread = ops[thread];
let tmp_thread = self.emit_ireg(thread, f_content, f_context, vm);
self.emit_runtime_entry(
&entrypoints::NOTIFY_THREAD,
vec![tmp_thread],
None,
Some(node),
f_content,
f_context,
vm,
);
}
Instruction_::CurrentStack => {
trace!("instsel on CURRENT_STACK");
......
......@@ -685,7 +685,7 @@ pub fn estimate_insts_for_ir(inst: &Instruction) -> usize {
// runtime call
New(_) | NewHybrid(_, _) => 10,
NewStack(_) | NewThread { .. } | NewThreadRT { .. } | NewFrameCursor(_) => 10,
NewStack(_) | NewThread { .. } | NotifyThread(_) | NewFrameCursor(_) => 10,
ThreadExit => 10,
CurrentStack => 10,
KillStack(_) => 10,
......
......@@ -79,7 +79,7 @@ fn is_suitable_child(inst: &Instruction) -> bool {
| AllocAHybrid(_, _)
| NewStack(_)
| NewThread { .. }
| NewThreadRT { .. }
| NotifyThread(_)
| NewFrameCursor(_)
| Select { .. }
| Fence(_)
......
......@@ -79,7 +79,10 @@ pub fn exec_path_nocheck(executable: PathBuf) -> Output {
fn exec_cmd(cmd: Command) -> Output {
let output = exec_cmd_nocheck(cmd);
if !output.status.success() {
println!("{}", String::from_utf8(output.stderr.clone()).unwrap());
info!(
"Failure: {}",
String::from_utf8(output.stderr.clone()).unwrap()
);
}
assert!(output.status.success());
output
......
......@@ -86,7 +86,11 @@ lazy_static! {
// decl: thread/mod.rs
#[cfg(feature = "realtime")]
lazy_static! {
;
pub static ref NOTIFY_THREAD: RuntimeEntrypoint = RuntimeEntrypoint::new(
"muentry_notify_to_run",
vec![THREADREF_TYPE.clone()],
vec![]
);
}
// impl/decl: gc/lib.rs
......
......@@ -313,7 +313,7 @@ pub extern "C" fn mu_main(
thread.unwrap().join().unwrap();
}
trace!("All threads have exited, quiting...");
info!("All threads have exited, quiting...");
}
}
......
......@@ -783,3 +783,8 @@ pub unsafe extern "C" fn muentry_new_thread_normal(
vm.push_join_handle(join_handle);
muthread
}
#[no_mangle]
pub unsafe extern "C" fn muentry_notify_to_run(thread: *const MuThread) {
MuThread::notify_to_run(thread);
}
......@@ -3604,62 +3604,62 @@ impl<'lb, 'lvm> BundleLoader<'lb, 'lvm> {
}
}
NodeInst::NodeNewThreadRT {
id: _,
result_id,
attr,
stack,
threadlocal,
new_stack_clause,
exc_clause
} => {
if exc_clause.is_some() {
unimplemented!();
}
let mut ops: Vec<P<TreeNode>> = vec![self.get_treenode(fcb, stack)];
assert_ir!(ops[0].ty().is_stackref());
let new_stack_clause = self.b.bundle.ns_clauses.get(&new_stack_clause).unwrap();
let impl_threadref = self.ensure_threadref();
let impl_rv = self.new_ssa(fcb, result_id, impl_threadref).clone_value();
let threadlocal = match threadlocal {
Some(tl) => {
let index = ops.len();
let tl = self.add_opnd(fcb, &mut ops, tl);
assert_ir!(tl.ty().is_ref() &&
tl.ty().get_referent_ty().unwrap().is_void());
Some(index)
}
None => None,
};
let attr = {
let index = ops.len();
let attr = self.add_opnd(fcb, &mut ops, attr);
assert_ir!(attr.ty().is_ref() &&
attr.ty().get_referent_ty().unwrap().is_void());
index
};
let (is_exception, args) =
self.build_new_stack_clause(new_stack_clause, fcb, &mut ops);
Instruction {
hdr: hdr,
value: Some(vec![impl_rv]),
ops: ops,
v: Instruction_::NewThreadRT {
attr: attr,
stack: 0,
thread_local: threadlocal,
is_exception: is_exception,
args: args
}
}
}
// NodeInst::NodeNewThreadRT {
// id: _,
// result_id,
// attr,
// stack,
// threadlocal,
// new_stack_clause,
// exc_clause
// } => {
// if exc_clause.is_some() {
// unimplemented!();
// }
//
// let mut ops: Vec<P<TreeNode>> = vec![self.get_treenode(fcb, stack)];
// assert_ir!(ops[0].ty().is_stackref());
// let new_stack_clause = self.b.bundle.ns_clauses.get(&new_stack_clause).unwrap();
//
// let impl_threadref = self.ensure_threadref();
// let impl_rv = self.new_ssa(fcb, result_id, impl_threadref).clone_value();
//
// let threadlocal = match threadlocal {
// Some(tl) => {
// let index = ops.len();
// let tl = self.add_opnd(fcb, &mut ops, tl);
// assert_ir!(tl.ty().is_ref() &&
// tl.ty().get_referent_ty().unwrap().is_void());
// Some(index)
// }
// None => None,
// };
//
// let attr = {
// let index = ops.len();
// let attr = self.add_opnd(fcb, &mut ops, attr);
// assert_ir!(attr.ty().is_ref() &&
// attr.ty().get_referent_ty().unwrap().is_void());
// index
// };
//
// let (is_exception, args) =
// self.build_new_stack_clause(new_stack_clause, fcb, &mut ops);
//
//
// Instruction {
// hdr: hdr,
// value: Some(vec![impl_rv]),
// ops: ops,
// v: Instruction_::NewThreadRT {
// attr: attr,
// stack: 0,
// thread_local: threadlocal,
// is_exception: is_exception,
// args: args
// }
// }
// }
NodeInst::NodeCommInst {
id,
......
......@@ -163,7 +163,8 @@ impl VMOptions {
}
}
// ret.flag_aot_link_static = true;
// FIXME - temporary, for debugging
ret.flag_aot_link_static = true;
ret
}
......
......@@ -105,6 +105,20 @@ macro_rules! typedef {
MuType_::rtattr());
$vm.set_name($name.as_entity());
};
// stackref
(($vm: expr) $name: ident = mu_stackref) => {
let $name = $vm.declare_type(MuEntityHeader::named($vm.next_id(), Mu(stringify!($name))),
MuType_::StackRef);
$vm.set_name($name.as_entity());
};
// threadref
(($vm: expr) $name: ident = mu_threadref) => {
let $name = $vm.declare_type(MuEntityHeader::named($vm.next_id(), Mu(stringify!($name))),
MuType_::ThreadRef);
$vm.set_name($name.as_entity());
};
}
macro_rules! constdef {
......@@ -649,7 +663,7 @@ macro_rules! inst {
// RET
(($vm: expr, $fv: ident) $name: ident: RET ($($val: ident), +)) => {
(($vm: expr, $fv: ident) $name: ident: RET ($($val: ident), *)) => {
let $name = $fv.new_inst(Instruction{
hdr: MuEntityHeader::unnamed($vm.next_id()),
value: None,
......@@ -719,6 +733,72 @@ macro_rules! inst {
v: Instruction_::Move(0)
});
};
// NEWSTACK
(($vm: expr, $fv: ident) $name: ident: $res: ident =
NEWSTACK $func: ident) => {
let $name = $fv.new_inst(Instruction {
hdr: MuEntityHeader::unnamed($vm.next_id()),
value: Some(vec![$res.clone_value()]),
ops: vec![$func.clone()],
v: Instruction_::NewStack(0)
});
};
// NEWTHREAD with no args, no thread local and no exception
(($vm: expr, $fv: ident) $name: ident:
$res: ident =
NEWTHREAD STACK: $stack: ident
) => {
let ops = vec![$stack.clone()];
let ops_len = ops.len();
let $name = $fv.new_inst(
Instruction {
hdr: MuEntityHeader::unnamed($vm.next_id()),
value: Some(vec![$res.clone_value()]),
ops: ops,
v: Instruction_::NewThread {
stack: 0,
thread_local: None,
is_exception: false,
args: vec![],
}
}
);
};
// NEWTHREAD with no thread local and no exception
(($vm: expr, $fv: ident) $name: ident:
$res: ident =
NEWTHREAD STACK: $stack: ident, ARGS: ($($arg: ident), *)
) => {
let ops = vec![$stack.clone(), $($arg.clone()), *];
let ops_len = ops.len();
let $name = $fv.new_inst(
Instruction {
hdr: MuEntityHeader::unnamed($vm.next_id()),
value: Some(vec![$res.clone_value()]),
ops: ops,
v: Instruction_::NewThread {
stack: 0,
thread_local: None,
is_exception: false,
args: (1..ops_len).collect(),
}
}
);
};
// NOTIFYTHREAD
(($vm: expr, $fv: ident) $name: ident:
NOTIFYTHREAD $thread: ident) => {
let $name = $fv.new_inst(Instruction {
hdr: MuEntityHeader::unnamed($vm.next_id()),
value: None,
ops: vec![$thread.clone()],
v: Instruction_::NotifyThread(0)
});
};
}
/**************************************
......
......@@ -12,4 +12,5 @@
// See the License for the specific language governing permissions and
// limitations under the License.
mod test_new_rt_thread;
mod test_rtattr;
// Copyright 2019 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.
extern crate libloading;
extern crate log;
extern crate mu;
use self::mu::ast::inst::*;
use self::mu::ast::ir::*;
use self::mu::ast::types::*;
use self::mu::compiler::*;
use self::mu::runtime::thread::MuThread;
use self::mu::utils::Address;
use self::mu::utils::LinkedHashMap;
use self::mu::vm::*;
use self::mu::linkutils;
use self::mu::linkutils::aot;
use std::sync::Arc;
#[test]
fn test_new_rt_thread() {
VM::start_logging_trace();
let vm = Arc::new(create_thread());
let compiler = Compiler::new(CompilerPolicy::default(), &vm);
let func_id = vm.id_of("the_func");
{
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);
}
let func_id = vm.id_of("create_thread_func");
{
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.set_primordial_thread(func_id, true, vec![]);
backend::emit_context(&vm);
let executable = aot::link_primordial(
vec![
Arc::new("create_thread_func".to_string()),
Arc::new("the_func".to_string()),
],
"create_thread_func_test",
&vm,
);
linkutils::exec_path(executable);
}
//fn empty_function() -> VM {
// let vm = VM::new_with_opts("--aot-link-static");
//
// typedef! ((vm) int64 = mu_int(64));
//
// constdef! ((vm) <int64> int64_0 = Constant::Int(0));
//
// funcsig! ((vm) sig = () -> (int64));
// funcdecl! ((vm) <sig> the_func);
// funcdef! ((vm) <sig> the_func VERSION the_func_v1);
//
// block! ((vm, the_func_v1) blk_entry);
//
// inst!((vm, the_func_v1) blk_entry_ret:
// RET (int64_0)
// );
//
// define_block! ((vm, the_func_v1) blk_entry() {
// blk_entry_ret
// });
//
// define_func_ver!((vm) the_func_v1 (entry: blk_entry) {
// blk_entry
// });
//
// vm
//}
fn create_thread() -> VM {
let vm = VM::new_with_opts("--aot-link-static");
typedef! ((vm) int64 = mu_int(64));
constdef! ((vm) <int64> int64_0 = Constant::Int(0));
funcsig! ((vm) sig = () -> ());
funcdecl! ((vm) <sig> the_func);
funcdef! ((vm) <sig> the_func VERSION the_func_v1);
consta! ((vm, the_func_v1) int64_0_local = int64_0);
block! ((vm, the_func_v1) blk_entry);
inst!((vm, the_func_v1) blk_entry_print:
PRINTHEX int64_0_local
);
inst!((vm, the_func_v1) blk_entry_ret:
THREADEXIT
);
define_block! ((vm, the_func_v1) blk_entry() {
blk_entry_print,
blk_entry_ret
});
define_func_ver!((vm) the_func_v1 (entry: blk_entry) {
blk_entry
});
typedef! ((vm) func_ref = mu_funcref(sig));
typedef! ((vm) stack_ref = mu_stackref);
typedef! ((vm) thread_ref = mu_threadref);
constdef! ((vm) <func_ref> const_funcref = Constant::FuncRef(the_func));
funcsig! ((vm) create_thread_sig = () -> ());
funcdecl! ((vm) <create_thread_sig> create_thread_func);
funcdef! ((vm) <create_thread_sig> create_thread_func VERSION create_thread_func_v1);
ssa! ((vm, create_thread_func_v1) <stack_ref> the_stack_ref);
ssa! ((vm, create_thread_func_v1) <thread_ref> the_thread_ref);
consta! ((vm, create_thread_func_v1) const_funcref_local = const_funcref);
// blk_entry
block! ((vm, create_thread_func_v1) blk_entry);
inst!((vm, create_thread_func_v1) blk_entry_create_stack:
the_stack_ref = NEWSTACK const_funcref_local
);
inst!((vm, create_thread_func_v1) blk_entry_create_stack_print:
PRINTHEX the_stack_ref
);
inst!((vm, create_thread_func_v1) blk_entry_create_thread:
the_thread_ref = NEWTHREAD STACK: the_stack_ref
);
inst!((vm, create_thread_func_v1) blk_entry_create_thread_print:
PRINTHEX the_thread_ref
);
inst!((vm, create_thread_func_v1) blk_entry_start_thread:
NOTIFYTHREAD the_thread_ref
);
inst!((vm, create_thread_func_v1) blk_entry_ret:
THREADEXIT
);
define_block!((vm, create_thread_func_v1) blk_entry() {
blk_entry_create_stack,
blk_entry_create_stack_print,
blk_entry_create_thread,
blk_entry_create_thread_print,
blk_entry_start_thread,
blk_entry_ret
});
define_func_ver!((vm) create_thread_func_v1 (entry: blk_entry) {
blk_entry
});
vm
}
......@@ -152,3 +152,170 @@ fn main_with_retval() -> VM {
vm
}
#[test]
fn test_new_thread() {
VM::start_logging_trace();
let vm = Arc::new(create_thread());
let compiler = Compiler::new(CompilerPolicy::default(), &vm);
let func_id = vm.id_of("the_func");
{
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);
}
let func_id = vm.id_of("create_thread_func");
{
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.set_primordial_thread(func_id, true, vec![]);
backend::emit_context(&vm);
let executable = aot::link_primordial(
vec![
Arc::new("create_thread_func".to_string()),
Arc::new("the_func".to_string()),
],
"create_thread_func_test",
&vm,
);
linkutils::exec_path(executable);
}
//fn empty_function() -> VM {
// let vm = VM::new_with_opts("--aot-link-static");
//
// typedef! ((vm) int64 = mu_int(64));
//
// constdef! ((vm) <int64> int64_0 = Constant::Int(0));