Commit cd5da56f authored by qinsoon's avatar qinsoon

[wip] allow exception block without actually using/mentioning exception

argument
we need to know whether a block is an exception block by looking at all
the exceptional clauses.
parent c00adcf3
......@@ -16,7 +16,7 @@
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Cargo &lt;mu&gt;" level="project" />
<orderEntry type="library" name="Rust &lt;mu&gt;" level="project" />
<orderEntry type="library" name="Cargo &lt;mu&gt;" level="project" />
</component>
</module>
\ No newline at end of file
......@@ -5,6 +5,7 @@ use op::*;
use utils::vec_utils;
use utils::LinkedHashMap;
use utils::LinkedHashSet;
use std::fmt;
use std::default;
......@@ -300,10 +301,13 @@ impl MuFunctionVersion {
}
}
#[derive(RustcEncodable, RustcDecodable)]
#[derive(Clone, RustcEncodable, RustcDecodable)]
pub struct FunctionContent {
pub entry: MuID,
pub blocks: LinkedHashMap<MuID, Block>
pub blocks: LinkedHashMap<MuID, Block>,
// this field only valid after control flow analysis
pub exception_blocks: LinkedHashSet<MuID>
}
impl fmt::Debug for FunctionContent {
......@@ -321,22 +325,15 @@ impl fmt::Debug for FunctionContent {
}
}
impl Clone for FunctionContent {
fn clone(&self) -> Self {
let mut new_blocks = LinkedHashMap::new();
for (id, block) in self.blocks.iter() {
new_blocks.insert(*id, block.clone());
}
impl FunctionContent {
pub fn new(entry: MuID, blocks: LinkedHashMap<MuID, Block>) -> FunctionContent {
FunctionContent {
entry: self.entry,
blocks: new_blocks
entry: entry,
blocks: blocks,
exception_blocks: LinkedHashSet::new()
}
}
}
impl FunctionContent {
pub fn get_entry_block(&self) -> &Block {
self.get_block(self.entry)
}
......@@ -432,7 +429,7 @@ impl Block {
Block{hdr: MuEntityHeader::unnamed(id), content: None, control_flow: ControlFlow::default()}
}
pub fn is_exception_block(&self) -> bool {
pub fn is_receiving_exception_arg(&self) -> bool {
return self.content.as_ref().unwrap().exn_arg.is_some()
}
......
......@@ -3646,16 +3646,30 @@ impl CompilerPass for InstructionSelection {
let f_content = func.content.as_ref().unwrap();
for block_id in func.block_trace.as_ref().unwrap() {
// is this block an exception block?
let is_exception_block = f_content.exception_blocks.contains(&block_id);
let block = f_content.get_block(*block_id);
let block_label = block.name().unwrap();
self.current_block = Some(block_label.clone());
let block_content = block.content.as_ref().unwrap();
if block.is_exception_block() {
if is_exception_block {
// exception block
// we need to be aware of exception blocks so that we can emit information to catch exceptions
let loc = self.backend.start_exception_block(block_label.clone());
self.current_exn_blocks.insert(block.id(), loc);
} else {
// normal block
self.backend.start_block(block_label.clone());
}
if block.is_receiving_exception_arg() {
// this block uses exception arguments
// we need to add it to livein, and also emit landingpad for it
let exception_arg = block_content.exn_arg.as_ref().unwrap();
// live in is args of the block + exception arg
......@@ -3666,8 +3680,6 @@ impl CompilerPass for InstructionSelection {
// need to insert a landing pad
self.emit_landingpad(&exception_arg, f_content, &mut func.context, vm);
} else {
self.backend.start_block(block_label.clone());
// live in is args of the block
self.backend.set_block_livein(block_label.clone(), &block_content.args);
}
......@@ -3675,6 +3687,7 @@ impl CompilerPass for InstructionSelection {
// live out is the union of all branch args of this block
let live_out = block_content.get_out_arguments();
// doing the actual instruction selection
for inst in block_content.body.iter() {
self.instruction_select(&inst, f_content, &mut func.context, vm);
}
......
......@@ -32,6 +32,14 @@ impl CodeEmission {
use std::io::prelude::*;
use std::fs::File;
let func_name = match func.name() {
Some(name) => name,
None => {
// use func name
vm.name_of(func.func_id)
}
};
// create emit directory
create_emit_directory(vm);
......@@ -39,7 +47,7 @@ impl CodeEmission {
{
let mut file_path = path::PathBuf::new();
file_path.push(&vm.vm_options.flag_aot_emit_dir);
file_path.push(func.name().unwrap().to_string() + ".muir");
file_path.push(func_name.clone() + ".muir");
let mut file = match File::create(file_path.as_path()) {
Err(why) => panic!("couldn't create muir file {}: {}", file_path.to_str().unwrap(), why),
Ok(file) => file
......@@ -52,7 +60,7 @@ impl CodeEmission {
{
let mut file_path = path::PathBuf::new();
file_path.push(&vm.vm_options.flag_aot_emit_dir);
file_path.push(func.name().unwrap().to_string() + "_orig.muir");
file_path.push(func_name.clone() + "_orig.muir");
let mut file = match File::create(file_path.as_path()) {
Err(why) => panic!("couldn't create muir file {}: {}", file_path.to_str().unwrap(), why),
Ok(file) => file
......
......@@ -4,6 +4,7 @@ use utils::vec_utils::as_str as vector_as_str;
use vm::VM;
use compiler::CompilerPass;
use utils::LinkedHashMap;
use utils::LinkedHashSet;
use std::any::Any;
pub struct ControlFlowAnalysis {
......@@ -253,6 +254,22 @@ impl CompilerPass for ControlFlowAnalysis {
#[allow(unused_variables)]
fn finish_function(&mut self, vm: &VM, func: &mut MuFunctionVersion) {
{
let mut exception_blocks = LinkedHashSet::new();
for block in func.content.as_ref().unwrap().blocks.iter() {
let ref control_flow = block.1.control_flow;
for edge in control_flow.succs.iter() {
if edge.is_exception {
exception_blocks.insert(edge.target);
}
}
}
func.content.as_mut().unwrap().exception_blocks.add_all(exception_blocks);
}
debug!("check control flow for {}", func);
for entry in func.content.as_ref().unwrap().blocks.iter() {
......
......@@ -195,7 +195,7 @@ fn print_backtrace(callsite: Address, mut cursor: FrameCursor) {
None => unsafe {Address::zero()}
}
};
let func_name = cur_thread.vm.name_of(cursor.func_ver_id);
let func_name = cur_thread.vm.name_of(cursor.func_id);
info!("frame {:2}: 0x{:x} - {} (fid: #{}, fvid: #{}) at 0x{:x}", frame_count, func_start, func_name, cursor.func_id, cursor.func_ver_id, callsite);
......
......@@ -7,6 +7,28 @@ use linked_hashmap::Keys;
pub struct LinkedHashSet<K, S = RandomState>(LinkedHashMap<K, (), S>);
use rustc_serialize::{Encodable, Encoder, Decodable, Decoder};
impl<K, S> Encodable for LinkedHashSet<K, S>
where K: Encodable + Eq + Hash,
S: BuildHasher
{
fn encode<E: Encoder> (&self, s: &mut E) -> Result<(), E::Error> {
self.0.encode(s)
}
}
impl<K> Decodable for LinkedHashSet<K>
where K: Decodable + Eq + Hash
{
fn decode<D: Decoder> (d: &mut D) -> Result<LinkedHashSet<K>, D::Error> {
match Decodable::decode(d) {
Ok(map) => Ok(LinkedHashSet(map)),
Err(e) => Err(e)
}
}
}
impl<K: Hash + Eq> LinkedHashSet<K> {
pub fn new() -> Self {
LinkedHashSet(LinkedHashMap::new())
......
......@@ -2,6 +2,7 @@ use super::common::*;
use ast::op::*;
use ast::inst::*;
use utils::LinkedHashMap;
use utils::LinkedHashSet;
use std;
pub struct MuIRBuilder {
......@@ -1225,6 +1226,7 @@ impl<'lb, 'lvm> BundleLoader<'lb, 'lvm> {
let ctn = FunctionContent {
entry: entry_id,
blocks: blocks,
exception_blocks: LinkedHashSet::new()
};
let impl_fv = MuFunctionVersion::new_(hdr, func_id, impl_sig, ctn, fcb.ctx);
......
......@@ -96,14 +96,11 @@ macro_rules! funcdef {
macro_rules! define_func_ver {
(($vm: expr) $fv: ident (entry: $entry: ident){$($blk: ident), *}) => {
$fv.define(FunctionContent{
entry: $entry.id(),
blocks: {
let mut ret = LinkedHashMap::new();
$ (ret.insert($blk.id(), $blk); )*
ret
}
});
$fv.define(FunctionContent::new($entry.id(), {
let mut ret = LinkedHashMap::new();
$ (ret.insert($blk.id(), $blk); )*
ret
}));
$vm.define_func_version($fv);
}
......
......@@ -251,14 +251,14 @@ pub fn alloc_new() -> VM {
};
blk_0.content = Some(blk_0_content);
func_ver.define(FunctionContent{
entry: blk_0.id(),
blocks: {
func_ver.define(FunctionContent::new(
blk_0.id(),
{
let mut ret = LinkedHashMap::new();
ret.insert(blk_0.id(), blk_0);
ret
}
});
));
vm.define_func_version(func_ver);
......
......@@ -80,14 +80,14 @@ fn udiv() -> VM {
keepalives: None
});
func_ver.define(FunctionContent{
entry: blk_entry.id(),
blocks: {
func_ver.define(FunctionContent::new(
blk_entry.id(),
{
let mut map = LinkedHashMap::new();
map.insert(blk_entry.id(), blk_entry);
map
}
});
));
vm.define_func_version(func_ver);
......@@ -166,14 +166,14 @@ fn sdiv() -> VM {
keepalives: None
});
func_ver.define(FunctionContent{
entry: blk_entry.id(),
blocks: {
func_ver.define(FunctionContent::new(
blk_entry.id(),
{
let mut map = LinkedHashMap::new();
map.insert(blk_entry.id(), blk_entry);
map
}
});
));
vm.define_func_version(func_ver);
......@@ -255,14 +255,14 @@ fn shl() -> VM {
keepalives: None
});
func_ver.define(FunctionContent{
entry: blk_entry.id(),
blocks: {
func_ver.define(FunctionContent::new(
blk_entry.id(),
{
let mut map = LinkedHashMap::new();
map.insert(blk_entry.id(), blk_entry);
map
}
});
));
vm.define_func_version(func_ver);
......@@ -340,14 +340,14 @@ fn lshr() -> VM {
keepalives: None
});
func_ver.define(FunctionContent{
entry: blk_entry.id(),
blocks: {
func_ver.define(FunctionContent::new(
blk_entry.id(),
{
let mut map = LinkedHashMap::new();
map.insert(blk_entry.id(), blk_entry);
map
}
});
));
vm.define_func_version(func_ver);
......
......@@ -130,14 +130,14 @@ fn ccall_exit() -> VM {
keepalives: None
});
func_ver.define(FunctionContent{
entry: blk_entry.id(),
blocks: {
func_ver.define(FunctionContent::new(
blk_entry.id(),
{
let mut map = LinkedHashMap::new();
map.insert(blk_entry.id(), blk_entry);
map
}
});
));
vm.define_func_version(func_ver);
......
......@@ -190,9 +190,9 @@ fn switch() -> VM {
keepalives: None
});
func_ver.define(FunctionContent{
entry: blk_entry.id(),
blocks: {
func_ver.define(FunctionContent::new(
blk_entry.id(),
{
let mut map = LinkedHashMap::new();
map.insert(blk_entry.id(), blk_entry);
map.insert(blk_default_id, blk_default);
......@@ -201,7 +201,7 @@ fn switch() -> VM {
map.insert(blk_ret2_id, blk_ret2);
map
}
});
));
vm.define_func_version(func_ver);
......
......@@ -15,9 +15,9 @@ use std::sync::Arc;
use std::sync::RwLock;
#[test]
fn test_exception_simple_throw_catch() {
fn test_exception_throw_catch_simple() {
VM::start_logging_trace();
let vm = Arc::new(simple_throw_catch());
let vm = Arc::new(throw_catch_simple());
let compiler = Compiler::new(CompilerPolicy::default(), &vm);
......@@ -44,11 +44,11 @@ fn test_exception_simple_throw_catch() {
vm.make_primordial_thread(func_catch, true, vec![]);
backend::emit_context(&vm);
let executable = aot::link_primordial(vec![Mu("throw_exception"), Mu("catch_exception")], "simple_throw_catch_test", &vm);
let executable = aot::link_primordial(vec![Mu("throw_exception"), Mu("catch_exception")], "throw_catch_simple_test", &vm);
aot::execute(executable);
}
fn simple_throw_catch() -> VM {
fn throw_catch_simple() -> VM {
let vm = VM::new();
// .typedef @int64 = int<64>
......@@ -69,12 +69,12 @@ fn simple_throw_catch() -> VM {
vm.set_name(const_def_int64_1.as_entity(), "int64_1".to_string());
create_throw_exception_func(&vm);
create_catch_exception_func(&vm);
create_catch_exception_func(&vm, true);
vm
}
fn create_catch_exception_func (vm: &VM) {
fn create_catch_exception_func (vm: &VM, use_exception_arg: bool) {
// .typedef @funcref_throw_exception <@throw_exception_sig>
let throw_exception_sig = vm.get_func_sig(vm.id_of("throw_exception_sig"));
let throw_exception_id = vm.id_of("throw_exception");
......@@ -164,21 +164,25 @@ fn create_catch_exception_func (vm: &VM) {
});
blk_exn_cont.content = Some(BlockContent {
args: vec![],
exn_arg: Some(blk_exn_cont_exception_arg.clone_value()),
exn_arg: if use_exception_arg {
Some(blk_exn_cont_exception_arg.clone_value())
} else {
None
},
body: vec![blk_exn_cont_thread_exit],
keepalives: None
});
func_ver.define(FunctionContent{
entry: blk_0.id(),
blocks: {
func_ver.define(FunctionContent::new(
blk_0.id(),
{
let mut ret = LinkedHashMap::new();
ret.insert(blk_0.id(), blk_0);
ret.insert(blk_normal_cont.id(), blk_normal_cont);
ret.insert(blk_exn_cont.id(), blk_exn_cont);
ret
}
});
));
vm.define_func_version(func_ver);
}
......@@ -254,14 +258,74 @@ fn create_throw_exception_func (vm: &VM) {
};
blk_0.content = Some(blk_0_content);
func_ver.define(FunctionContent {
entry: blk_0.id(),
blocks: {
func_ver.define(FunctionContent::new(
blk_0.id(),
{
let mut ret = LinkedHashMap::new();
ret.insert(blk_0.id(), blk_0);
ret
}
});
));
vm.define_func_version(func_ver);
}
#[test]
fn test_exception_throw_catch_dont_use_exception_arg() {
VM::start_logging_trace();
let vm = Arc::new(throw_catch_dont_use_exception_arg());
let compiler = Compiler::new(CompilerPolicy::default(), &vm);
let func_throw = vm.id_of("throw_exception");
let func_catch = vm.id_of("catch_exception");
{
let funcs = vm.funcs().read().unwrap();
let func_vers = vm.func_vers().read().unwrap();
{
let func = funcs.get(&func_throw).unwrap().read().unwrap();
let mut func_ver = func_vers.get(&func.cur_ver.unwrap()).unwrap().write().unwrap();
compiler.compile(&mut func_ver);
}
{
let func = funcs.get(&func_catch).unwrap().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_catch, true, vec![]);
backend::emit_context(&vm);
let executable = aot::link_primordial(vec![Mu("throw_exception"), Mu("catch_exception")], "throw_catch_simple_test", &vm);
aot::execute(executable);
}
fn throw_catch_dont_use_exception_arg() -> VM {
let vm = VM::new();
// .typedef @int64 = int<64>
// .typedef @ref_int64 = ref<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_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());
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());
// .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());
create_throw_exception_func(&vm);
create_catch_exception_func(&vm, false);
vm
}
\ No newline at end of file
......@@ -80,14 +80,14 @@ fn fp_add() -> VM {
keepalives: None
});
func_ver.define(FunctionContent{
entry: blk_entry.id(),
blocks: {
func_ver.define(FunctionContent::new(
blk_entry.id(),
{
let mut ret = LinkedHashMap::new();
ret.insert(blk_entry.id(), blk_entry);
ret
}
});
));
vm.define_func_version(func_ver);
......
......@@ -83,14 +83,14 @@ fn add_u8() -> VM {
keepalives: None
});
func_ver.define(FunctionContent{
entry: blk_entry.id(),
blocks: {
func_ver.define(FunctionContent::new(
blk_entry.id(),
{
let mut map = LinkedHashMap::new();
map.insert(blk_entry.id(), blk_entry);
map
}
});
));
vm.define_func_version(func_ver);
......@@ -222,14 +222,14 @@ fn sext() -> VM {
keepalives: None
});
func_ver.define(FunctionContent{
entry: blk_entry.id(),
blocks: {
func_ver.define(FunctionContent::new(
blk_entry.id(),
{
let mut map = LinkedHashMap::new();
map.insert(blk_entry.id(), blk_entry);
map
}
});
));
vm.define_func_version(func_ver);
......@@ -308,14 +308,14 @@ fn add_9f() -> VM {
keepalives: None
});
func_ver.define(FunctionContent{
entry: blk_entry.id(),
blocks: {
func_ver.define(FunctionContent::new(
blk_entry.id(),
{
let mut map = LinkedHashMap::new();
map.insert(blk_entry.id(), blk_entry);
map
}
});
));
vm.define_func_version(func_ver);
......
......@@ -479,15 +479,15 @@ pub fn struct_insts() -> VM {
keepalives: None
});
func_ver.define(FunctionContent{
entry: blk_entry.id(),
blocks: {
func_ver.define(FunctionContent::new(
blk_entry.id(),
{
let mut map = LinkedHashMap::new();
map.insert(blk_entry.id(), blk_entry);
map.insert(blk_check_id, blk_check);
map
}
});
));
vm.define_func_version(func_ver);
......@@ -759,15 +759,15 @@ pub fn hybrid_fix_part_insts() -> VM {
keepalives: None
});
func_ver.define(FunctionContent{
entry: blk_entry.id(),
blocks: {
func_ver.define(FunctionContent::new(
blk_entry.id(),
{
let mut map = LinkedHashMap::new();
map.insert(blk_entry.id(), blk_entry);
map.insert(blk_check_id, blk_check);
map
}
});
));
vm.define_func_version(func_ver);
......@@ -1203,9 +1203,9 @@ pub fn hybrid_var_part_insts() -> VM {
keepalives: None
});
func_ver.define(FunctionContent{
entry: blk_entry.id(),
blocks: {
func_ver.define(FunctionContent::new(
blk_entry.id(),
{
let mut map = LinkedHashMap::new();
map.insert(blk_entry.id(), blk_entry);
map.insert(blk_check.id(), blk_check);
......@@ -1214,7 +1214,7 @@ pub fn hybrid_var_part_insts() -> VM {
map.insert(blk_exit.id(), blk_exit);
map
}
});
));
vm.define_func_version(func_ver);
......
......@@ -278,14 +278,14 @@ fn create_spill1() -> VM {
keepalives: None
});
func_ver.define(FunctionContent {
entry: blk_entry.id(),
blocks: {
func_ver.define(FunctionContent::new(
blk_entry.id(),
{
let mut blocks = LinkedHashMap::new();
blocks.insert(blk_entry.id(), blk_entry);
blocks
}
});
));
vm.define_func_version(func_ver);
......@@ -568,16 +568,16 @@ fn create_simple_spill() -> VM {
keepalives: None
});
func_ver.define(FunctionContent {
entry: blk_entry.id(),