Commit 55466779 authored by qinsoon's avatar qinsoon

refactoring and added time profiling

parent 250d61a8
...@@ -9,4 +9,5 @@ lazy_static = "0.1.15" ...@@ -9,4 +9,5 @@ lazy_static = "0.1.15"
log = "0.3.5" log = "0.3.5"
simple_logger = "0.4.0" simple_logger = "0.4.0"
nalgebra = "0.8.2" nalgebra = "0.8.2"
linked-hash-map = "0.0.10" linked-hash-map = "0.0.10"
\ No newline at end of file hprof = "0.1.3"
...@@ -2,7 +2,7 @@ use ast::ir::*; ...@@ -2,7 +2,7 @@ use ast::ir::*;
use ast::ptr::*; use ast::ptr::*;
use ast::types::*; use ast::types::*;
use ast::op::*; use ast::op::*;
use common::vector_as_str; use utils::vec_utils::as_str as vector_as_str;
use std::fmt; use std::fmt;
use std::cell::RefCell; use std::cell::RefCell;
...@@ -34,33 +34,33 @@ impl fmt::Display for Instruction { ...@@ -34,33 +34,33 @@ impl fmt::Display for Instruction {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Instruction_ { pub enum Instruction_ {
// non-terminal instruction // non-terminal instruction
// expressions // expressions
BinOp(BinOp, OpIndex, OpIndex), BinOp(BinOp, OpIndex, OpIndex),
CmpOp(CmpOp, OpIndex, OpIndex), CmpOp(CmpOp, OpIndex, OpIndex),
// yields a tuple of results from the call // yields a tuple of results from the call
ExprCall{ ExprCall{
data: CallData, data: CallData,
is_abort: bool, // T to abort, F to rethrow is_abort: bool, // T to abort, F to rethrow
}, },
// yields the memory value // yields the memory value
Load{ Load{
is_ptr: bool, is_ptr: bool,
order: MemoryOrder, order: MemoryOrder,
mem_loc: OpIndex mem_loc: OpIndex
}, },
// yields nothing // yields nothing
Store{ Store{
is_ptr: bool, is_ptr: bool,
order: MemoryOrder, order: MemoryOrder,
mem_loc: OpIndex, mem_loc: OpIndex,
value: OpIndex value: OpIndex
}, },
// yields pair (oldvalue, boolean (T = success, F = failure)) // yields pair (oldvalue, boolean (T = success, F = failure))
CmpXchg{ CmpXchg{
is_ptr: bool, is_ptr: bool,
...@@ -71,7 +71,7 @@ pub enum Instruction_ { ...@@ -71,7 +71,7 @@ pub enum Instruction_ {
expected_value: OpIndex, expected_value: OpIndex,
desired_value: OpIndex desired_value: OpIndex
}, },
// yields old memory value // yields old memory value
AtomicRMW{ AtomicRMW{
is_ptr: bool, // T for iref, F for ptr is_ptr: bool, // T for iref, F for ptr
...@@ -80,62 +80,62 @@ pub enum Instruction_ { ...@@ -80,62 +80,62 @@ pub enum Instruction_ {
mem_loc: OpIndex, mem_loc: OpIndex,
value: OpIndex // operand for op value: OpIndex // operand for op
}, },
// yields a reference of the type // yields a reference of the type
New(P<MuType>), New(P<MuType>),
// yields an iref of the type // yields an iref of the type
AllocA(P<MuType>), AllocA(P<MuType>),
// yields ref // yields ref
NewHybrid(P<MuType>, OpIndex), NewHybrid(P<MuType>, OpIndex),
// yields iref // yields iref
AllocAHybrid(P<MuType>, OpIndex), AllocAHybrid(P<MuType>, OpIndex),
// yields stack ref // yields stack ref
NewStack(OpIndex), // func NewStack(OpIndex), // func
// TODO: common inst // TODO: common inst
// yields thread reference // yields thread reference
NewThread(OpIndex, Vec<OpIndex>), // stack, args NewThread(OpIndex, Vec<OpIndex>), // stack, args
// yields thread reference (thread resumes with exceptional value) // yields thread reference (thread resumes with exceptional value)
NewThreadExn(OpIndex, OpIndex), // stack, exception NewThreadExn(OpIndex, OpIndex), // stack, exception
// yields frame cursor // yields frame cursor
NewFrameCursor(OpIndex), // stack NewFrameCursor(OpIndex), // stack
// ref<T> -> iref<T> // ref<T> -> iref<T>
GetIRef(OpIndex), GetIRef(OpIndex),
// iref|uptr<struct|hybrid<T>> int<M> -> iref|uptr<U> // iref|uptr<struct|hybrid<T>> int<M> -> iref|uptr<U>
GetFieldIRef{ GetFieldIRef{
is_ptr: bool, is_ptr: bool,
base: OpIndex, // iref or uptr base: OpIndex, // iref or uptr
index: OpIndex // constant index: OpIndex // constant
}, },
// iref|uptr<array<T N>> int<M> -> iref|uptr<T> // iref|uptr<array<T N>> int<M> -> iref|uptr<T>
GetElementIRef{ GetElementIRef{
is_ptr: bool, is_ptr: bool,
base: OpIndex, base: OpIndex,
index: OpIndex // can be constant or ssa var index: OpIndex // can be constant or ssa var
}, },
// iref|uptr<T> int<M> -> iref|uptr<T> // iref|uptr<T> int<M> -> iref|uptr<T>
ShiftIRef{ ShiftIRef{
is_ptr: bool, is_ptr: bool,
base: OpIndex, base: OpIndex,
offset: OpIndex offset: OpIndex
}, },
// iref|uptr<hybrid<T U>> -> iref|uptr<U> // iref|uptr<hybrid<T U>> -> iref|uptr<U>
GetVarPartIRef{ GetVarPartIRef{
is_ptr: bool, is_ptr: bool,
base: OpIndex base: OpIndex
}, },
// PushFrame{ // PushFrame{
// stack: P<Value>, // stack: P<Value>,
// func: P<Value> // func: P<Value>
...@@ -145,7 +145,7 @@ pub enum Instruction_ { ...@@ -145,7 +145,7 @@ pub enum Instruction_ {
// } // }
Fence(MemoryOrder), Fence(MemoryOrder),
// terminal instruction // terminal instruction
Return(Vec<OpIndex>), Return(Vec<OpIndex>),
ThreadExit, // TODO: common inst ThreadExit, // TODO: common inst
...@@ -166,9 +166,9 @@ pub enum Instruction_ { ...@@ -166,9 +166,9 @@ pub enum Instruction_ {
id: Option<WPID>, id: Option<WPID>,
disable_dest: Option<Destination>, disable_dest: Option<Destination>,
resume: ResumptionData resume: ResumptionData
}, },
WPBranch{ WPBranch{
wp: WPID, wp: WPID,
disable_dest: Destination, disable_dest: Destination,
enable_dest: Destination enable_dest: Destination
}, },
...@@ -204,18 +204,18 @@ impl Instruction_ { ...@@ -204,18 +204,18 @@ impl Instruction_ {
}, },
&Instruction_::Load{is_ptr, mem_loc, order} => { &Instruction_::Load{is_ptr, mem_loc, order} => {
let ptr = select_value!(is_ptr, "PTR", ""); let ptr = select_value!(is_ptr, "PTR", "");
format!("LOAD {} {:?} {}", ptr, order, ops[mem_loc]) format!("LOAD {} {:?} {}", ptr, order, ops[mem_loc])
}, },
&Instruction_::Store{value, is_ptr, mem_loc, order} => { &Instruction_::Store{value, is_ptr, mem_loc, order} => {
let ptr = select_value!(is_ptr, "PTR", ""); let ptr = select_value!(is_ptr, "PTR", "");
format!("STORE {} {:?} {} {}", ptr, order, ops[mem_loc], ops[value]) format!("STORE {} {:?} {} {}", ptr, order, ops[mem_loc], ops[value])
}, },
&Instruction_::CmpXchg{is_ptr, is_weak, success_order, fail_order, &Instruction_::CmpXchg{is_ptr, is_weak, success_order, fail_order,
mem_loc, expected_value, desired_value} => { mem_loc, expected_value, desired_value} => {
let ptr = select_value!(is_ptr, "PTR", ""); let ptr = select_value!(is_ptr, "PTR", "");
let weak = select_value!(is_weak, "WEAK", ""); let weak = select_value!(is_weak, "WEAK", "");
format!("CMPXCHG {} {} {:?} {:?} {} {} {}", format!("CMPXCHG {} {} {:?} {:?} {} {} {}",
ptr, weak, success_order, fail_order, ops[mem_loc], ops[expected_value], ops[desired_value]) ptr, weak, success_order, fail_order, ops[mem_loc], ops[expected_value], ops[desired_value])
}, },
&Instruction_::AtomicRMW{is_ptr, order, op, mem_loc, value} => { &Instruction_::AtomicRMW{is_ptr, order, op, mem_loc, value} => {
let ptr = select_value!(is_ptr, "PTR", ""); let ptr = select_value!(is_ptr, "PTR", "");
...@@ -246,11 +246,11 @@ impl Instruction_ { ...@@ -246,11 +246,11 @@ impl Instruction_ {
let ptr = select_value!(is_ptr, "PTR", ""); let ptr = select_value!(is_ptr, "PTR", "");
format!("GETVARPARTIREF {} {}", ptr, ops[base]) format!("GETVARPARTIREF {} {}", ptr, ops[base])
}, },
&Instruction_::Fence(order) => { &Instruction_::Fence(order) => {
format!("FENCE {:?}", order) format!("FENCE {:?}", order)
}, },
&Instruction_::Return(ref vals) => format!("RET {}", op_vector_str(vals, ops)), &Instruction_::Return(ref vals) => format!("RET {}", op_vector_str(vals, ops)),
&Instruction_::ThreadExit => "THREADEXIT".to_string(), &Instruction_::ThreadExit => "THREADEXIT".to_string(),
&Instruction_::Throw(ref vals) => format!("THROW {}", op_vector_str(vals, ops)), &Instruction_::Throw(ref vals) => format!("THROW {}", op_vector_str(vals, ops)),
...@@ -286,14 +286,14 @@ impl Instruction_ { ...@@ -286,14 +286,14 @@ impl Instruction_ {
} }
} }
ret.push_str("}}"); ret.push_str("}}");
ret ret
}, },
&Instruction_::ExnInstruction{ref inner, ref resume} => { &Instruction_::ExnInstruction{ref inner, ref resume} => {
format!("{} {}", inner.debug_str(ops), resume.debug_str(ops)) format!("{} {}", inner.debug_str(ops), resume.debug_str(ops))
} }
} }
} }
} }
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
...@@ -361,7 +361,7 @@ impl Destination { ...@@ -361,7 +361,7 @@ impl Destination {
} }
} }
ret.push(']'); ret.push(']');
ret ret
} }
} }
...@@ -376,7 +376,7 @@ impl DestArg { ...@@ -376,7 +376,7 @@ impl DestArg {
fn debug_str(&self, ops: &Vec<P<TreeNode>>) -> String { fn debug_str(&self, ops: &Vec<P<TreeNode>>) -> String {
match self { match self {
&DestArg::Normal(index) => format!("{}", ops[index]), &DestArg::Normal(index) => format!("{}", ops[index]),
&DestArg::Freshbound(n) => format!("${}", n) &DestArg::Freshbound(n) => format!("${}", n)
} }
} }
} }
\ No newline at end of file
...@@ -2,7 +2,7 @@ use ast::ptr::P; ...@@ -2,7 +2,7 @@ use ast::ptr::P;
use ast::types::*; use ast::types::*;
use ast::inst::*; use ast::inst::*;
use ast::op::*; use ast::op::*;
use common::vector_as_str; use utils::vec_utils::as_str as vector_as_str;
use std::collections::HashMap; use std::collections::HashMap;
use std::fmt; use std::fmt;
...@@ -19,9 +19,9 @@ pub type OpIndex = usize; ...@@ -19,9 +19,9 @@ pub type OpIndex = usize;
#[derive(Debug)] #[derive(Debug)]
pub struct MuFunction { pub struct MuFunction {
pub fn_name: MuTag, pub fn_name: MuTag,
pub next_id: MuID, pub next_id: MuID,
pub sig: P<MuFuncSig>, pub sig: P<MuFuncSig>,
pub content: Option<FunctionContent>, pub content: Option<FunctionContent>,
pub context: FunctionContext, pub context: FunctionContext,
...@@ -35,13 +35,13 @@ impl MuFunction { ...@@ -35,13 +35,13 @@ impl MuFunction {
pub fn new(fn_name: MuTag, sig: P<MuFuncSig>) -> MuFunction { pub fn new(fn_name: MuTag, sig: P<MuFuncSig>) -> MuFunction {
MuFunction{ MuFunction{
fn_name: fn_name, fn_name: fn_name,
next_id: RESERVED_NODE_IDS_FOR_MACHINE, next_id: RESERVED_NODE_IDS_FOR_MACHINE,
sig: sig, sig: sig,
content: None, content: None,
context: FunctionContext::new(), context: FunctionContext::new(),
block_trace: None} block_trace: None}
} }
fn get_id(&mut self) -> MuID { fn get_id(&mut self) -> MuID {
let ret = self.next_id; let ret = self.next_id;
self.next_id += 1; self.next_id += 1;
...@@ -54,7 +54,7 @@ impl MuFunction { ...@@ -54,7 +54,7 @@ impl MuFunction {
pub fn new_ssa(&mut self, tag: MuTag, ty: P<MuType>) -> P<TreeNode> { pub fn new_ssa(&mut self, tag: MuTag, ty: P<MuType>) -> P<TreeNode> {
let id = self.get_id(); let id = self.get_id();
self.context.value_tags.insert(tag, id); self.context.value_tags.insert(tag, id);
self.context.values.insert(id, SSAVarEntry{id: id, tag: tag, ty: ty.clone(), use_count: Cell::new(0), expr: None}); self.context.values.insert(id, SSAVarEntry{id: id, tag: tag, ty: ty.clone(), use_count: Cell::new(0), expr: None});
...@@ -76,14 +76,14 @@ impl MuFunction { ...@@ -76,14 +76,14 @@ impl MuFunction {
v: TreeNode_::Value(v) v: TreeNode_::Value(v)
}) })
} }
pub fn new_inst(&mut self, v: Instruction) -> P<TreeNode> { pub fn new_inst(&mut self, v: Instruction) -> P<TreeNode> {
P(TreeNode{ P(TreeNode{
id: self.get_id(), id: self.get_id(),
op: pick_op_code_for_inst(&v), op: pick_op_code_for_inst(&v),
v: TreeNode_::Instruction(v), v: TreeNode_::Instruction(v),
}) })
} }
} }
#[derive(Debug)] #[derive(Debug)]
...@@ -132,20 +132,20 @@ impl FunctionContext { ...@@ -132,20 +132,20 @@ impl FunctionContext {
values: HashMap::new() values: HashMap::new()
} }
} }
pub fn get_value_by_tag(&self, tag: MuTag) -> Option<&SSAVarEntry> { pub fn get_value_by_tag(&self, tag: MuTag) -> Option<&SSAVarEntry> {
match self.value_tags.get(tag) { match self.value_tags.get(tag) {
Some(id) => self.get_value(*id), Some(id) => self.get_value(*id),
None => None None => None
} }
} }
pub fn get_value_mut_by_tag(&mut self, tag: MuTag) -> Option<&mut SSAVarEntry> { pub fn get_value_mut_by_tag(&mut self, tag: MuTag) -> Option<&mut SSAVarEntry> {
let id : MuID = match self.value_tags.get(tag) { let id : MuID = match self.value_tags.get(tag) {
Some(id) => *id, Some(id) => *id,
None => return None None => return None
}; };
self.get_value_mut(id) self.get_value_mut(id)
} }
...@@ -249,11 +249,11 @@ impl TreeNode { ...@@ -249,11 +249,11 @@ impl TreeNode {
pub fn new_inst(id: MuID, v: Instruction) -> P<TreeNode> { pub fn new_inst(id: MuID, v: Instruction) -> P<TreeNode> {
P(TreeNode{ P(TreeNode{
id: id, id: id,
op: pick_op_code_for_inst(&v), op: pick_op_code_for_inst(&v),
v: TreeNode_::Instruction(v), v: TreeNode_::Instruction(v),
}) })
} }
pub fn extract_ssa_id(&self) -> Option<MuID> { pub fn extract_ssa_id(&self) -> Option<MuID> {
match self.v { match self.v {
TreeNode_::Value(ref pv) => { TreeNode_::Value(ref pv) => {
...@@ -265,18 +265,18 @@ impl TreeNode { ...@@ -265,18 +265,18 @@ impl TreeNode {
_ => None _ => None
} }
} }
pub fn clone_value(&self) -> P<Value> { pub fn clone_value(&self) -> P<Value> {
match self.v { match self.v {
TreeNode_::Value(ref val) => val.clone(), TreeNode_::Value(ref val) => val.clone(),
_ => panic!("expecting a value") _ => panic!("expecting a value")
} }
} }
pub fn into_value(self) -> Option<P<Value>> { pub fn into_value(self) -> Option<P<Value>> {
match self.v { match self.v {
TreeNode_::Value(val) => Some(val), TreeNode_::Value(val) => Some(val),
_ => None _ => None
} }
} }
} }
...@@ -329,7 +329,7 @@ impl Value { ...@@ -329,7 +329,7 @@ impl Value {
_ => false _ => false
} }
} }
pub fn is_fp_reg(&self) -> bool { pub fn is_fp_reg(&self) -> bool {
match self.v { match self.v {
Value_::SSAVar(_) => { Value_::SSAVar(_) => {
...@@ -342,7 +342,7 @@ impl Value { ...@@ -342,7 +342,7 @@ impl Value {
_ => false _ => false
} }
} }
pub fn is_int_const(&self) -> bool { pub fn is_int_const(&self) -> bool {
match self.v { match self.v {
Value_::Constant(_) => { Value_::Constant(_) => {
...@@ -355,7 +355,7 @@ impl Value { ...@@ -355,7 +355,7 @@ impl Value {
_ => false _ => false
} }
} }
pub fn extract_ssa_id(&self) -> Option<MuID> { pub fn extract_ssa_id(&self) -> Option<MuID> {
match self.v { match self.v {
Value_::SSAVar(id) => Some(id), Value_::SSAVar(id) => Some(id),
......
use ast::ptr::P; use ast::ptr::P;
use ast::ir::*; use ast::ir::*;
use common::vector_as_str; use utils::vec_utils::as_str as vector_as_str;
use std::fmt; use std::fmt;
use std::collections::HashMap; use std::collections::HashMap;
...@@ -16,43 +16,43 @@ pub enum MuType_ { ...@@ -16,43 +16,43 @@ pub enum MuType_ {
Float, Float,
/// double /// double
Double, Double,
/// ref<T> /// ref<T>
Ref (P<MuType>), // Box is needed for non-recursive enum Ref (P<MuType>), // Box is needed for non-recursive enum
/// iref<T>: internal reference /// iref<T>: internal reference
IRef (P<MuType>), IRef (P<MuType>),
/// weakref<T> /// weakref<T>
WeakRef (P<MuType>), WeakRef (P<MuType>),
/// uptr<T>: unsafe pointer /// uptr<T>: unsafe pointer
UPtr (P<MuType>), UPtr (P<MuType>),
/// struct<T1 T2 ...> /// struct<T1 T2 ...>
Struct (MuTag), Struct (MuTag),
/// array<T length> /// array<T length>
Array (P<MuType>, usize), Array (P<MuType>, usize),
/// hybrid<F1 F2 ... V>: a hybrid of fixed length parts and a variable length part /// hybrid<F1 F2 ... V>: a hybrid of fixed length parts and a variable length part
Hybrid (Vec<P<MuType>>, P<MuType>), Hybrid (Vec<P<MuType>>, P<MuType>),
/// void /// void
Void, Void,
/// threadref /// threadref
ThreadRef, ThreadRef,
/// stackref /// stackref
StackRef, StackRef,
/// tagref64: hold a double or an int or an ref<void> /// tagref64: hold a double or an int or an ref<void>
Tagref64, Tagref64,
/// vector<T length> /// vector<T length>
Vector (P<MuType>, usize), Vector (P<MuType>, usize),
/// funcref<@sig> /// funcref<@sig>
FuncRef (P<MuFuncSig>), FuncRef (P<MuFuncSig>),
/// ufuncptr<@sig> /// ufuncptr<@sig>
UFuncPtr (P<MuFuncSig>), UFuncPtr (P<MuFuncSig>),
} }
...@@ -68,7 +68,7 @@ impl fmt::Display for MuType_ { ...@@ -68,7 +68,7 @@ impl fmt::Display for MuType_ {
&MuType_::WeakRef(ref ty) => write!(f, "weakref<{}>", ty), &MuType_::WeakRef(ref ty) => write!(f, "weakref<{}>", ty),
&MuType_::UPtr(ref ty) => write!(f, "uptr<{}>", ty), &MuType_::UPtr(ref ty) => write!(f, "uptr<{}>", ty),
&MuType_::Array(ref ty, size) => write!(f, "array<{} {}>", ty, size), &MuType_::Array(ref ty, size) => write!(f, "array<{} {}>", ty, size),
&MuType_::Hybrid(ref fix_tys, ref var_ty) => write!(f, "hybrid<[{}] {}>", vector_as_str(fix_tys), var_ty), &MuType_::Hybrid(ref fix_tys, ref var_ty) => write!(f, "hybrid<[{}] {}>", vector_as_str(fix_tys), var_ty),
&MuType_::Void => write!(f, "void"), &MuType_::Void => write!(f, "void"),
&MuType_::ThreadRef => write!(f, "threadref"), &MuType_::ThreadRef => write!(f, "threadref"),
&MuType_::StackRef => write!(f, "stackref"), &MuType_::StackRef => write!(f, "stackref"),
...@@ -102,7 +102,7 @@ impl fmt::Display for StructType_ { ...@@ -102,7 +102,7 @@ impl fmt::Display for StructType_ {
} }
} }
write!(f, ">") write!(f, ">")
} }
} }
impl StructType_ { impl StructType_ {
...@@ -228,7 +228,7 @@ pub fn is_scalar(ty: &MuType) -> bool { ...@@ -228,7 +228,7 @@ pub fn is_scalar(ty: &MuType) -> bool {
} }
/// is a type traced by the garbage collector? /// is a type traced by the garbage collector?
/// Note: An aggregated type is traced if any of its part is traced. /// Note: An aggregated type is traced if any of its part is traced.
pub fn is_traced(ty: &MuType) -> bool { pub fn is_traced(ty: &MuType) -> bool {
match *ty { match *ty {
MuType_::Ref(_) => true, MuType_::Ref(_) => true,
...@@ -242,13 +242,13 @@ pub fn is_traced(ty: &MuType) -> bool { ...@@ -242,13 +242,13 @@ pub fn is_traced(ty: &MuType) -> bool {
MuType_::Hybrid(ref fix_tys, ref var_ty) => { MuType_::Hybrid(ref fix_tys, ref var_ty) => {
is_traced(var_ty) || is_traced(var_ty) ||
fix_tys.into_iter().map(|ty| is_traced(ty)) fix_tys.into_iter().map(|ty| is_traced(ty))
.fold(false, |ret, this| ret || this) .fold(false, |ret, this| ret || this)
}, },
MuType_::Struct(tag) => { MuType_::Struct(tag) => {
let map = STRUCT_TAG_MAP.read().unwrap(); let map = STRUCT_TAG_MAP.read().unwrap();
let struct_ty = map.get(tag).unwrap(); let struct_ty = map.get(tag).unwrap();
let ref field_tys = struct_ty.tys; let ref field_tys = struct_ty.tys;
field_tys.into_iter().map(|ty| is_traced(&ty)) field_tys.into_iter().map(|ty| is_traced(&ty))
.fold(false, |ret, this| ret || this) .fold(false, |ret, this| ret || this)
}, },
...@@ -269,7 +269,7 @@ pub fn is_native_safe(ty: &MuType) -> bool { ...@@ -269,7 +269,7 @@ pub fn is_native_safe(ty: &MuType) -> bool {
MuType_::UPtr(_) => true, MuType_::UPtr(_) => true,
MuType_::UFuncPtr(_) => true, MuType_::UFuncPtr(_) => true,
MuType_::Hybrid(ref fix_tys, ref var_ty) => { MuType_::Hybrid(ref fix_tys, ref var_ty) => {
is_native_safe(var_ty) && is_native_safe(var_ty) &&
fix_tys.into_iter().map(|ty| is_native_safe(&ty)) fix_tys.into_iter().map(|ty| is_native_safe(&ty))
.fold(true, |ret, this| ret && this) .fold(true, |ret, this| ret && this)
}, },
...@@ -277,7 +277,7 @@ pub fn is_native_safe(ty: &MuType) -> bool { ...@@ -277,7 +277,7 @@ pub fn is_native_safe(ty: &MuType) -> bool {
let map = STRUCT_TAG_MAP.read().unwrap(); let map = STRUCT_TAG_MAP.read().unwrap();
let struct_ty = map.get(tag).unwrap(); let struct_ty = map.get(tag).unwrap();
let ref field_tys = struct_ty.tys; let ref field_tys = struct_ty.tys;
field_tys.into_iter().map(|ty| is_native_safe(&ty)) field_tys.into_iter().map(|ty| is_native_safe(&ty))
.fold(true, |ret, this| ret && this) .fold(true, |ret, this| ret && this)
}, },
...@@ -303,5 +303,5 @@ pub struct MuFuncSig { ...@@ -303,5 +303,5 @@ pub struct MuFuncSig {
impl fmt::Display for MuFuncSig { impl fmt::Display for MuFuncSig {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {