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 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(),
blocks: {
func_ver.define(FunctionContent::new(
blk_entry.id(),