use ptr::P; use ir::*; use utils::POINTER_SIZE; use utils::vec_utils; use std::fmt; use std::collections::HashMap; use std::sync::RwLock; lazy_static! { pub static ref ADDRESS_TYPE : P = P( MuType::new(new_internal_id(), MuType_::int(POINTER_SIZE * 8)) ); pub static ref UINT8_TYPE : P = P( MuType::new(new_internal_id(), MuType_::int(8)) ); pub static ref UINT16_TYPE : P = P( MuType::new(new_internal_id(), MuType_::int(16)) ); pub static ref UINT32_TYPE : P = P( MuType::new(new_internal_id(), MuType_::int(32)) ); pub static ref UINT64_TYPE : P = P( MuType::new(new_internal_id(), MuType_::int(64)) ); pub static ref DOUBLE_TYPE : P = P( MuType::new(new_internal_id(), MuType_::double()) ); pub static ref VOID_TYPE : P = P( MuType::new(new_internal_id(), MuType_::void()) ); pub static ref INTERNAL_TYPES : Vec> = vec![ ADDRESS_TYPE.clone(), UINT8_TYPE.clone(), UINT16_TYPE.clone(), UINT32_TYPE.clone(), UINT64_TYPE.clone(), DOUBLE_TYPE.clone() ]; } #[derive(PartialEq, Debug, RustcEncodable, RustcDecodable)] pub struct MuType { pub hdr: MuEntityHeader, pub v: MuType_ } impl MuType { pub fn new(id: MuID, v: MuType_) -> MuType { MuType { hdr: MuEntityHeader::unnamed(id), v: v } } } pub type StructTag = MuName; pub type HybridTag = MuName; #[derive(PartialEq, Debug, RustcEncodable, RustcDecodable)] pub enum MuType_ { /// int Int (usize), /// float Float, /// double Double, /// ref Ref (P), // Box is needed for non-recursive enum /// iref: internal reference IRef (P), /// weakref WeakRef (P), /// uptr: unsafe pointer UPtr (P), /// struct Struct (StructTag), /// array Array (P, usize), /// hybrid: a hybrid of fixed length parts and a variable length part Hybrid (HybridTag), /// void Void, /// threadref ThreadRef, /// stackref StackRef, /// tagref64: hold a double or an int or an ref Tagref64, /// vector Vector (P, usize), /// funcref<@sig> FuncRef (P), /// ufuncptr<@sig> UFuncPtr (P), } impl fmt::Display for MuType { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.v) } } impl fmt::Display for MuType_ { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { &MuType_::Int(n) => write!(f, "int<{}>", n), &MuType_::Float => write!(f, "float"), &MuType_::Double => write!(f, "double"), &MuType_::Ref(ref ty) => write!(f, "ref<{}>", ty), &MuType_::IRef(ref ty) => write!(f, "iref<{}>", ty), &MuType_::WeakRef(ref ty) => write!(f, "weakref<{}>", ty), &MuType_::UPtr(ref ty) => write!(f, "uptr<{}>", ty), &MuType_::Array(ref ty, size) => write!(f, "array<{} {}>", ty, size), &MuType_::Void => write!(f, "void"), &MuType_::ThreadRef => write!(f, "threadref"), &MuType_::StackRef => write!(f, "stackref"), &MuType_::Tagref64 => write!(f, "tagref64"), &MuType_::Vector(ref ty, size) => write!(f, "vector<{} {}>", ty, size), &MuType_::FuncRef(ref sig) => write!(f, "funcref<{}>", sig), &MuType_::UFuncPtr(ref sig) => write!(f, "ufuncref<{}>", sig), &MuType_::Struct(ref tag) => write!(f, "{}(struct)", tag), &MuType_::Hybrid(ref tag) => write!(f, "{}(hybrid)", tag) } } } lazy_static! { /// storing a map from MuName to StructType_ pub static ref STRUCT_TAG_MAP : RwLock> = RwLock::new(HashMap::new()); /// storing a map from MuName to HybridType_ pub static ref HYBRID_TAG_MAP : RwLock> = RwLock::new(HashMap::new()); } #[derive(PartialEq, Debug, RustcEncodable, RustcDecodable)] pub struct StructType_ { tys: Vec> } impl fmt::Display for StructType_ { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "struct<").unwrap(); for i in 0..self.tys.len() { let ty = &self.tys[i]; write!(f, "{}", ty).unwrap(); if i != self.tys.len() - 1 { write!(f, " ").unwrap(); } } write!(f, ">") } } impl StructType_ { // The IR builder needs to create StructType objects, too. pub fn new(tys: Vec>) -> StructType_ { StructType_ { tys: tys } } pub fn set_tys(&mut self, mut list: Vec>) { self.tys.clear(); self.tys.append(&mut list); } pub fn get_tys(&self) -> &Vec> { &self.tys } } #[derive(PartialEq, Debug, RustcEncodable, RustcDecodable)] pub struct HybridType_ { fix_tys: Vec>, var_ty : P } impl HybridType_ { pub fn new(fix_tys: Vec>, var_ty: P) -> HybridType_ { HybridType_ {fix_tys: fix_tys, var_ty: var_ty} } pub fn set_tys(&mut self, mut fix_tys: Vec>, var_ty: P) { self.fix_tys.clear(); self.fix_tys.append(&mut fix_tys); self.var_ty = var_ty; } pub fn get_fix_tys(&self) -> &Vec> { &self.fix_tys } pub fn get_var_ty(&self) -> &P { &self.var_ty } } impl fmt::Display for HybridType_ { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "hybrid<").unwrap(); for i in 0..self.fix_tys.len() { let ty = &self.fix_tys[i]; write!(f, "{}", ty).unwrap(); if i != self.fix_tys.len() - 1 { write!(f, " ").unwrap(); } } write!(f, "|{}>", self.var_ty) } } impl MuType_ { pub fn int(len: usize) -> MuType_ { MuType_::Int(len) } pub fn float() -> MuType_ { MuType_::Float } pub fn double() -> MuType_ { MuType_::Double } pub fn muref(referent: P) -> MuType_ { MuType_::Ref(referent) } pub fn iref(referent: P) -> MuType_ { MuType_::IRef(referent) } pub fn weakref(referent: P) -> MuType_ { MuType_::WeakRef(referent) } pub fn uptr(referent: P) -> MuType_ { MuType_::UPtr(referent) } pub fn mustruct_empty(tag: MuName) -> MuType_ { let struct_ty_ = StructType_{tys: vec![]}; STRUCT_TAG_MAP.write().unwrap().insert(tag.clone(), struct_ty_); MuType_::Struct(tag) } pub fn mustruct_put(tag: MuName, mut list: Vec>) { let mut map_guard = STRUCT_TAG_MAP.write().unwrap(); match map_guard.get_mut(&tag) { Some(struct_ty_) => { struct_ty_.tys.clear(); struct_ty_.tys.append(&mut list); }, None => panic!("call mustruct_empty() to create an empty struct before mustruct_put()") } } pub fn mustruct(tag: StructTag, list: Vec>) -> MuType_ { let struct_ty_ = StructType_{tys: list}; // if there is an attempt to use a same tag for different struct, // we panic match STRUCT_TAG_MAP.read().unwrap().get(&tag) { Some(old_struct_ty_) => { if struct_ty_ != *old_struct_ty_ { panic!("trying to insert {} as {}, while the old struct is defined as {}", struct_ty_, tag, old_struct_ty_) } }, None => {} } // otherwise, store the tag STRUCT_TAG_MAP.write().unwrap().insert(tag.clone(), struct_ty_); MuType_::Struct(tag) } pub fn array(ty: P, len: usize) -> MuType_ { MuType_::Array(ty, len) } pub fn hybrid_empty(tag: HybridTag) -> MuType_ { let hybrid_ty_ = HybridType_{fix_tys: vec![], var_ty: VOID_TYPE.clone()}; HYBRID_TAG_MAP.write().unwrap().insert(tag.clone(), hybrid_ty_); MuType_::Hybrid(tag) } pub fn hybrid(tag: HybridTag, fix_tys: Vec>, var_ty: P) -> MuType_ { let hybrid_ty_ = HybridType_{fix_tys: fix_tys, var_ty: var_ty}; match HYBRID_TAG_MAP.read().unwrap().get(&tag) { Some(old_hybrid_ty_) => { if hybrid_ty_ != *old_hybrid_ty_ { panic!("trying to insert {} as {}, while the old hybrid is defined as {}", hybrid_ty_, tag, old_hybrid_ty_); } }, None => {} } HYBRID_TAG_MAP.write().unwrap().insert(tag.clone(), hybrid_ty_); MuType_::Hybrid(tag) } pub fn void() -> MuType_ { MuType_::Void } pub fn threadref() -> MuType_ { MuType_::ThreadRef } pub fn stackref() -> MuType_ { MuType_::StackRef } pub fn tagref64() -> MuType_ { MuType_::Tagref64 } pub fn vector(ty: P, len: usize) -> MuType_ { MuType_::Vector(ty, len) } pub fn funcref(sig: P) -> MuType_ { MuType_::FuncRef(sig) } pub fn ufuncptr(sig: P) -> MuType_ { MuType_::UFuncPtr(sig) } } /// is a type floating-point type? pub fn is_fp(ty: &MuType) -> bool { match ty.v { MuType_::Float | MuType_::Double => true, _ => false } } /// is a type raw pointer? pub fn is_ptr(ty: &MuType) -> bool { match ty.v { MuType_::UPtr(_) | MuType_::UFuncPtr(_) => true, _ => false } } /// is a type scalar type? pub fn is_scalar(ty: &MuType) -> bool { match ty.v { MuType_::Int(_) | MuType_::Float | MuType_::Double | MuType_::Ref(_) | MuType_::IRef(_) | MuType_::WeakRef(_) | MuType_::FuncRef(_) | MuType_::UFuncPtr(_) | MuType_::ThreadRef | MuType_::StackRef | MuType_::Tagref64 | MuType_::UPtr(_) => true, _ => false } } /// is a type traced by the garbage collector? /// Note: An aggregated type is traced if any of its part is traced. pub fn is_traced(ty: &MuType) -> bool { match ty.v { MuType_::Ref(_) => true, MuType_::IRef(_) => true, MuType_::WeakRef(_) => true, MuType_::Array(ref elem_ty, _) | MuType_::Vector(ref elem_ty, _) => is_traced(elem_ty), MuType_::ThreadRef | MuType_::StackRef | MuType_::Tagref64 => true, MuType_::Hybrid(ref tag) => { let map = HYBRID_TAG_MAP.read().unwrap(); let hybrid_ty = map.get(tag).unwrap(); let ref fix_tys = hybrid_ty.fix_tys; let ref var_ty = hybrid_ty.var_ty; is_traced(var_ty) || fix_tys.into_iter().map(|ty| is_traced(ty)) .fold(false, |ret, this| ret || this) }, MuType_::Struct(ref tag) => { let map = STRUCT_TAG_MAP.read().unwrap(); let struct_ty = map.get(tag).unwrap(); let ref field_tys = struct_ty.tys; field_tys.into_iter().map(|ty| is_traced(&ty)) .fold(false, |ret, this| ret || this) }, _ => false } } /// is a type native safe? /// Note: An aggregated type is native safe if all of its parts are native safe. pub fn is_native_safe(ty: &MuType) -> bool { match ty.v { MuType_::Int(_) => true, MuType_::Float => true, MuType_::Double => true, MuType_::Void => true, MuType_::Array(ref elem_ty, _) | MuType_::Vector(ref elem_ty, _) => is_native_safe(elem_ty), MuType_::UPtr(_) => true, MuType_::UFuncPtr(_) => true, MuType_::Hybrid(ref tag) => { let map = HYBRID_TAG_MAP.read().unwrap(); let hybrid_ty = map.get(tag).unwrap(); let ref fix_tys = hybrid_ty.fix_tys; let ref var_ty = hybrid_ty.var_ty; is_native_safe(var_ty) && fix_tys.into_iter().map(|ty| is_native_safe(&ty)) .fold(true, |ret, this| ret && this) }, MuType_::Struct(ref tag) => { let map = STRUCT_TAG_MAP.read().unwrap(); let struct_ty = map.get(tag).unwrap(); let ref field_tys = struct_ty.tys; field_tys.into_iter().map(|ty| is_native_safe(&ty)) .fold(true, |ret, this| ret && this) }, _ => false } } pub fn get_referent_ty(ty: &MuType) -> Option> { match ty.v { MuType_::Ref(ref referent) | MuType_::IRef(ref referent) | MuType_::WeakRef(ref referent) => Some(referent.clone()), _ => None } } macro_rules! is_type ( ($e:expr, $p:pat) => ( match $e { $p => true, _ => false } ) ); pub type CFuncSig = MuFuncSig; #[derive(PartialEq, Debug, RustcEncodable, RustcDecodable)] pub struct MuFuncSig { pub hdr: MuEntityHeader, pub ret_tys : Vec>, pub arg_tys: Vec> } impl fmt::Display for MuFuncSig { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "[{}] -> [{}]", vec_utils::as_str(&self.ret_tys), vec_utils::as_str(&self.arg_tys)) } }