GitLab will be upgraded to the 12.10.14-ce.0 on 28 Sept 2020 at 2.00pm (AEDT) to 2.30pm (AEDT). During the update, GitLab and Mattermost services will not be available. If you have any concerns with this, please talk to us at N110 (b) CSIT building.

Commit fe287e80 authored by Isaac Gariano's avatar Isaac Gariano

Merge branch 'master' into 'aarch64'

Merging master to aarch64

See merge request !9
parents 0ec81e6a 99a65c69
...@@ -11,8 +11,10 @@ Cargo.lock ...@@ -11,8 +11,10 @@ Cargo.lock
*.pyc *.pyc
*.o *.o
*.dylib *.dylib
mu-client-pypy **mu-client-pypy**
**RPySOM**
.gitignore .gitignore
cmake-build-debug/* cmake-build-debug/*
Notes/* Notes/*
CMakeLists.txt CMakeLists.txt
\ No newline at end of file *.iml
# This file is a template, and might need editing before it works on your project. # This file is a template, and might need editing before it works on your project.
# Unofficial language image. Look for the different tagged releases at: # Unofficial language image. Look for the different tagged releases at:
# https://hub.docker.com/r/scorpil/rust/tags/ # https://hub.docker.com/r/scorpil/rust/tags/
image: "qinsoon/ubuntu-zebu-test:lastest" image: "qinsoon/ubuntu-zebu-test:latest"
# Optional: Pick zero or more services to be used on all builds. # Optional: Pick zero or more services to be used on all builds.
# Only needed when using a docker container to run your tests in. # Only needed when using a docker container to run your tests in.
...@@ -18,36 +18,60 @@ image: "qinsoon/ubuntu-zebu-test:lastest" ...@@ -18,36 +18,60 @@ image: "qinsoon/ubuntu-zebu-test:lastest"
#- apt-get install -yqq --no-install-recommends build-essential #- apt-get install -yqq --no-install-recommends build-essential
# Use cargo to test the project # Use cargo to test the project
cache: # cache:
key: "$CI_BUILD_STAGE/$CI_BUILD_REF_NAME" # key: "$CI_BUILD_STAGE/$CI_BUILD_REF_NAME"
paths: # paths:
- .cargo/registry/cache # - .cargo/registry/cache
- .cargo/registry/index # - .cargo/registry/index
- target # - target
- Cargo.lock # - Cargo.lock
stages:
- build
- test
build_vm:
stage: build
script:
- rustc --version
- time CARGO_HOME=.cargo RUST_BACKTRACE=1 CC=clang cargo build --release
build_test:
stage: build
script:
- rustc --version
- time CARGO_HOME=.cargo RUST_BACKTRACE=1 CC=clang cargo test --release --no-run
artifacts:
paths:
- target/release/libmu.so
- target/release/libmu.a
before_script: before_script:
- time CARGO_HOME=.cargo RUST_BACKTRACE=1 CC=clang cargo test --no-run - export PATH=$PATH:/root/.cargo/bin
- export MU_ZEBU=$CI_PROJECT_DIR
- export ZEBU_BUILD=release
- export CARGO_HOME=.cargo
- export CC=clang
test:cargo:api: test:cargo:api:
stage: test stage: test
script: script:
- CARGO_HOME=.cargo RUST_BACKTRACE=1 RUST_TEST_THREADS=1 CC=clang cargo test test_api 2> /dev/null - RUST_BACKTRACE=1 RUST_TEST_THREADS=1 cargo test --release test_api 2> /dev/null
test:cargo:ir: test:cargo:ir:
stage: test stage: test
script: script:
- CARGO_HOME=.cargo RUST_BACKTRACE=1 RUST_TEST_THREADS=1 CC=clang cargo test test_ir 2> /dev/null - RUST_BACKTRACE=1 RUST_TEST_THREADS=1 cargo test --release test_ir 2> /dev/null
test:cargo:compiler: test:cargo:compiler:
stage: test stage: test
script: script:
- CARGO_HOME=.cargo RUST_BACKTRACE=1 RUST_TEST_THREADS=1 CC=clang cargo test test_compiler 2> /dev/null - RUST_BACKTRACE=1 RUST_TEST_THREADS=1 cargo test --release test_compiler 2> /dev/null
test:cargo:runtime: test:cargo:runtime:
stage: test stage: test
script: script:
- CARGO_HOME=.cargo RUST_BACKTRACE=1 RUST_TEST_THREADS=1 CC=clang cargo test test_runtime 2> /dev/null - RUST_BACKTRACE=1 RUST_TEST_THREADS=1 cargo test --release test_runtime 2> /dev/null
testjit:milestones: testjit:milestones:
stage: test stage: test
...@@ -98,17 +122,24 @@ testjit:otherops: ...@@ -98,17 +122,24 @@ testjit:otherops:
testjit:rpython: testjit:rpython:
stage: test stage: test
script: script:
- if [ -d "tests/test_jit/mu-client-pypy" ]; then rm -Rf tests/test_jit/mu-client-pypy; fi
- git clone https://gitlab.anu.edu.au/mu/mu-client-pypy.git tests/test_jit/mu-client-pypy - git clone https://gitlab.anu.edu.au/mu/mu-client-pypy.git tests/test_jit/mu-client-pypy
- cd tests/test_jit/mu-client-pypy - cd tests/test_jit/mu-client-pypy
- git checkout mu-rewrite - git checkout mu-rewrite
- git apply pypy.patch - git apply pypy.patch
- cd $CI_PROJECT_DIR/tests/test_jit - cd $CI_PROJECT_DIR/tests/test_jit
- LD_LIBRARY_PATH=. RUST_BACKTRACE=1 PYTHONPATH=mu-client-pypy MU_ZEBU=$CI_PROJECT_DIR pytest test_rpython*.py -v - MU_LOG_LEVEL=info LD_LIBRARY_PATH=. RUST_BACKTRACE=1 PYTHONPATH=mu-client-pypy pytest test_rpython*.py -v
cache:
key: "$CI_BUILD_STAGE/$CI_BUILD_REF_NAME" testjit:som:
paths: stage: test
- .cargo/registry/cache script:
- .cargo/registry/index - if [ -d "tests/test_jit/RPySOM" ]; then rm -Rf tests/test_jit/RPySOM; fi
- target - git clone https://github.com/microvm/RPySOM.git tests/test_jit/RPySOM
- Cargo.lock - cd tests/test_jit/RPySOM; git submodule init; git submodule update; cd $CI_PROJECT_DIR
- tests/test_jit/mu-client-pypy - if [ -d "tests/test_jit/mu-client-pypy" ]; then rm -Rf tests/test_jit/mu-client-pypy; fi
- git clone https://gitlab.anu.edu.au/mu/mu-client-pypy.git tests/test_jit/mu-client-pypy
- cd tests/test_jit/mu-client-pypy
- git checkout mu-rewrite
- git apply pypy.patch
- cd $CI_PROJECT_DIR/tests/test_jit
- MU_LOG_LEVEL=info LD_LIBRARY_PATH=. RUST_BACKTRACE=1 PYTHONPATH=mu-client-pypy:RPySOM/src RPYSOM=RPySOM pytest test_som.py -v
\ No newline at end of file
...@@ -33,4 +33,5 @@ rustc-serialize = "*" ...@@ -33,4 +33,5 @@ rustc-serialize = "*"
time = "0.1.34" time = "0.1.34"
maplit = "0.1.4" maplit = "0.1.4"
docopt = "0.6" docopt = "0.6"
petgraph = "0.4.1" petgraph = "0.4.1"
\ No newline at end of file extprim = "*"
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<module type="RUST_MODULE" version="4">
<component name="FacetManager">
<facet type="Python" name="Python">
<configuration sdkName="" />
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/examples" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/benches" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<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
...@@ -7,14 +7,13 @@ use ir_semantics; ...@@ -7,14 +7,13 @@ use ir_semantics;
use utils::vec_utils; use utils::vec_utils;
use std::fmt; use std::fmt;
use std::sync::RwLock;
#[derive(Debug)] #[derive(Debug)]
// this implements RustcEncodable, RustcDecodable, Clone and Display // this implements RustcEncodable, RustcDecodable, Clone and Display
pub struct Instruction { pub struct Instruction {
pub hdr: MuEntityHeader, pub hdr: MuEntityHeader,
pub value : Option<Vec<P<Value>>>, pub value : Option<Vec<P<Value>>>,
pub ops : RwLock<Vec<P<TreeNode>>>, pub ops : Vec<P<TreeNode>>,
pub v: Instruction_ pub v: Instruction_
} }
...@@ -27,7 +26,7 @@ impl Encodable for Instruction { ...@@ -27,7 +26,7 @@ impl Encodable for Instruction {
try!(s.emit_struct_field("hdr", 0, |s| self.hdr.encode(s))); try!(s.emit_struct_field("hdr", 0, |s| self.hdr.encode(s)));
try!(s.emit_struct_field("value", 1, |s| self.value.encode(s))); try!(s.emit_struct_field("value", 1, |s| self.value.encode(s)));
let ops = &self.ops.read().unwrap(); let ref ops = self.ops;
try!(s.emit_struct_field("ops", 2, |s| ops.encode(s))); try!(s.emit_struct_field("ops", 2, |s| ops.encode(s)));
try!(s.emit_struct_field("v", 3, |s| self.v.encode(s))); try!(s.emit_struct_field("v", 3, |s| self.v.encode(s)));
...@@ -50,7 +49,7 @@ impl Decodable for Instruction { ...@@ -50,7 +49,7 @@ impl Decodable for Instruction {
Ok(Instruction{ Ok(Instruction{
hdr: hdr, hdr: hdr,
value: value, value: value,
ops: RwLock::new(ops), ops: ops,
v: v v: v
}) })
}) })
...@@ -62,13 +61,20 @@ impl Clone for Instruction { ...@@ -62,13 +61,20 @@ impl Clone for Instruction {
Instruction { Instruction {
hdr: self.hdr.clone(), hdr: self.hdr.clone(),
value: self.value.clone(), value: self.value.clone(),
ops: RwLock::new(self.ops.read().unwrap().clone()), ops: self.ops.clone(),
v: self.v.clone() v: self.v.clone()
} }
} }
} }
impl Instruction { impl Instruction {
pub fn clone_with_id(&self, new_id: MuID) -> Instruction {
let mut clone = self.clone();
clone.hdr = self.hdr.clone_with_id(new_id);
clone
}
pub fn has_exception_clause(&self) -> bool { pub fn has_exception_clause(&self) -> bool {
ir_semantics::is_potentially_excepting_instruction(&self.v) ir_semantics::is_potentially_excepting_instruction(&self.v)
} }
...@@ -133,7 +139,7 @@ impl Instruction { ...@@ -133,7 +139,7 @@ impl Instruction {
impl fmt::Display for Instruction { impl fmt::Display for Instruction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let ops = &self.ops.read().unwrap(); let ref ops = self.ops;
if self.value.is_some() { if self.value.is_some() {
write!(f, "{} = {}", vec_utils::as_str(self.value.as_ref().unwrap()), self.v.debug_str(ops)) write!(f, "{} = {}", vec_utils::as_str(self.value.as_ref().unwrap()), self.v.debug_str(ops))
} else { } else {
......
...@@ -242,7 +242,7 @@ impl MuFunctionVersion { ...@@ -242,7 +242,7 @@ impl MuFunctionVersion {
for inst in block_content.body.iter() { for inst in block_content.body.iter() {
match inst.v { match inst.v {
TreeNode_::Instruction(ref inst) => { TreeNode_::Instruction(ref inst) => {
let ops = inst.ops.read().unwrap(); let ref ops = inst.ops;
match inst.v { match inst.v {
Instruction_::ExprCall{ref data, ..} Instruction_::ExprCall{ref data, ..}
...@@ -358,6 +358,16 @@ impl FunctionContent { ...@@ -358,6 +358,16 @@ impl FunctionContent {
None => panic!("cannot find block #{}", id) None => panic!("cannot find block #{}", id)
} }
} }
pub fn get_block_by_name(&self, name: String) -> &Block {
for block in self.blocks.values() {
if block.name().unwrap() == name {
return block;
}
}
panic!("cannot find block {}", name)
}
} }
#[derive(Default, Debug, RustcEncodable, RustcDecodable)] #[derive(Default, Debug, RustcEncodable, RustcDecodable)]
...@@ -535,7 +545,7 @@ impl BlockContent { ...@@ -535,7 +545,7 @@ impl BlockContent {
match last_inst.v { match last_inst.v {
TreeNode_::Instruction(ref inst) => { TreeNode_::Instruction(ref inst) => {
let ops = inst.ops.read().unwrap(); let ref ops = inst.ops;
match inst.v { match inst.v {
Instruction_::Return(_) Instruction_::Return(_)
| Instruction_::ThreadExit | Instruction_::ThreadExit
...@@ -702,16 +712,17 @@ impl Value { ...@@ -702,16 +712,17 @@ impl Value {
_ => false _ => false
} }
} }
pub fn is_int_reg(&self) -> bool { pub fn is_reg(&self) -> bool {
match self.v { match self.v {
Value_::SSAVar(_) => { Value_::SSAVar(_) => true,
if is_scalar(&self.ty) && !is_fp(&self.ty) { _ => false
true }
} else { }
false
} pub fn is_const(&self) -> bool {
} match self.v {
Value_::Constant(_) => true,
_ => false _ => false
} }
} }
...@@ -724,21 +735,6 @@ impl Value { ...@@ -724,21 +735,6 @@ impl Value {
}) })
} }
pub fn is_fp_reg(&self) -> bool {
match self.v {
Value_::SSAVar(_) => {
if is_scalar(&self.ty) && is_fp(&self.ty) {
true
} else {
false
}
},
Value_::Constant(Constant::Double(_)) => true,
Value_::Constant(Constant::Float(_)) => true,
_ => false
}
}
pub fn is_int_const(&self) -> bool { pub fn is_int_const(&self) -> bool {
match self.v { match self.v {
Value_::Constant(Constant::Int(_)) => true, Value_::Constant(Constant::Int(_)) => true,
...@@ -761,6 +757,13 @@ impl Value { ...@@ -761,6 +757,13 @@ impl Value {
_ => None _ => None
} }
} }
pub fn extract_memory_location(&self) -> Option<MemoryLocation> {
match self.v {
Value_::Memory(ref loc) => Some(loc.clone()),
_ => None
}
}
} }
const DISPLAY_ID : bool = true; const DISPLAY_ID : bool = true;
...@@ -826,7 +829,10 @@ pub struct SSAVarEntry { ...@@ -826,7 +829,10 @@ pub struct SSAVarEntry {
use_count: AtomicUsize, use_count: AtomicUsize,
// this field is only used during TreeGeneration pass // this field is only used during TreeGeneration pass
expr: Option<Instruction> expr: Option<Instruction>,
// some ssa vars (such as int128) needs to be split into smaller vars
split: Option<Vec<P<Value>>>
} }
impl Encodable for SSAVarEntry { impl Encodable for SSAVarEntry {
...@@ -836,6 +842,7 @@ impl Encodable for SSAVarEntry { ...@@ -836,6 +842,7 @@ impl Encodable for SSAVarEntry {
let count = self.use_count.load(Ordering::SeqCst); let count = self.use_count.load(Ordering::SeqCst);
try!(s.emit_struct_field("use_count", 1, |s| s.emit_usize(count))); try!(s.emit_struct_field("use_count", 1, |s| s.emit_usize(count)));
try!(s.emit_struct_field("expr", 2, |s| self.expr.encode(s))); try!(s.emit_struct_field("expr", 2, |s| self.expr.encode(s)));
try!(s.emit_struct_field("split", 3, |s| self.split.encode(s)));
Ok(()) Ok(())
}) })
} }
...@@ -844,14 +851,16 @@ impl Encodable for SSAVarEntry { ...@@ -844,14 +851,16 @@ impl Encodable for SSAVarEntry {
impl Decodable for SSAVarEntry { impl Decodable for SSAVarEntry {
fn decode<D: Decoder>(d: &mut D) -> Result<SSAVarEntry, D::Error> { fn decode<D: Decoder>(d: &mut D) -> Result<SSAVarEntry, D::Error> {
d.read_struct("SSAVarEntry", 3, |d| { d.read_struct("SSAVarEntry", 3, |d| {
let val = try!(d.read_struct_field("val", 0, |d| Decodable::decode(d))); let val = try!(d.read_struct_field("val", 0, |d| Decodable::decode(d)));
let count = try!(d.read_struct_field("use_count", 1, |d| d.read_usize())); let count = try!(d.read_struct_field("use_count", 1, |d| d.read_usize()));
let expr = try!(d.read_struct_field("expr", 2, |d| Decodable::decode(d))); let expr = try!(d.read_struct_field("expr", 2, |d| Decodable::decode(d)));
let split = try!(d.read_struct_field("split", 3, |d| Decodable::decode(d)));
let ret = SSAVarEntry { let ret = SSAVarEntry {
val: val, val: val,
use_count: ATOMIC_USIZE_INIT, use_count: ATOMIC_USIZE_INIT,
expr: expr expr: expr,
split: split
}; };
ret.use_count.store(count, Ordering::SeqCst); ret.use_count.store(count, Ordering::SeqCst);
...@@ -866,7 +875,8 @@ impl SSAVarEntry { ...@@ -866,7 +875,8 @@ impl SSAVarEntry {
let ret = SSAVarEntry { let ret = SSAVarEntry {
val: val, val: val,
use_count: ATOMIC_USIZE_INIT, use_count: ATOMIC_USIZE_INIT,
expr: None expr: None,
split: None
}; };
ret.use_count.store(0, Ordering::SeqCst); ret.use_count.store(0, Ordering::SeqCst);
...@@ -902,6 +912,16 @@ impl SSAVarEntry { ...@@ -902,6 +912,16 @@ impl SSAVarEntry {
debug_assert!(self.has_expr()); debug_assert!(self.has_expr());
self.expr.take().unwrap() self.expr.take().unwrap()
} }
pub fn has_split(&self) -> bool {
self.split.is_some()
}
pub fn set_split(&mut self, vec: Vec<P<Value>>) {
self.split = Some(vec);
}
pub fn get_split(&self) -> &Option<Vec<P<Value>>> {
&self.split
}
} }
impl fmt::Display for SSAVarEntry { impl fmt::Display for SSAVarEntry {
...@@ -913,6 +933,7 @@ impl fmt::Display for SSAVarEntry { ...@@ -913,6 +933,7 @@ impl fmt::Display for SSAVarEntry {
#[derive(Debug, Clone, PartialEq, RustcEncodable, RustcDecodable)] #[derive(Debug, Clone, PartialEq, RustcEncodable, RustcDecodable)]
pub enum Constant { pub enum Constant {
Int(u64), Int(u64),
IntEx(Vec<u64>),
Float(f32), Float(f32),
Double(f64), Double(f64),
// IRef(Address), // IRef(Address),
...@@ -929,6 +950,7 @@ impl fmt::Display for Constant { ...@@ -929,6 +950,7 @@ impl fmt::Display for Constant {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
&Constant::Int(v) => write!(f, "{}", v as i64), &Constant::Int(v) => write!(f, "{}", v as i64),
&Constant::IntEx(ref v) => write!(f, "IntEx {:?}", v),
&Constant::Float(v) => write!(f, "{}", v), &Constant::Float(v) => write!(f, "{}", v),
&Constant::Double(v) => write!(f, "{}", v), &Constant::Double(v) => write!(f, "{}", v),
// &Constant::IRef(v) => write!(f, "{}", v), // &Constant::IRef(v) => write!(f, "{}", v),
...@@ -1163,6 +1185,13 @@ impl MuEntityHeader { ...@@ -1163,6 +1185,13 @@ impl MuEntityHeader {
None => None None => None
} }
} }
pub fn clone_with_id(&self, new_id: MuID) -> MuEntityHeader {
let mut clone = self.clone();
clone.id = new_id;
clone
}
} }
impl PartialEq for MuEntityHeader { impl PartialEq for MuEntityHeader {
......
...@@ -59,6 +59,7 @@ lazy_static! { ...@@ -59,6 +59,7 @@ lazy_static! {
UINT128_TYPE.clone(), UINT128_TYPE.clone(),
FLOAT_TYPE.clone(), FLOAT_TYPE.clone(),
DOUBLE_TYPE.clone(), DOUBLE_TYPE.clone(),
FLOAT_TYPE.clone(),
VOID_TYPE.clone() VOID_TYPE.clone()
]; ];
} }
...@@ -103,28 +104,166 @@ impl MuType { ...@@ -103,28 +104,166 @@ impl MuType {
} }
} }
pub fn get_struct_hybrid_tag(&self) -> Option<MuName> { pub fn is_ref(&self) -> bool {
match self.v { match self.v {
MuType_::Hybrid(ref name) MuType_::Ref(_) => true,
| MuType_::Struct(ref name) => Some(name.clone()), _ => false
_ => None
} }
} }
pub fn is_ref(&self) -> bool { pub fn is_iref(&self) -> bool {
match self.v { match self.v {
MuType_::Ref(_) => true, MuType_::IRef(_) => true,
_ => false _ => false
} }
} }
pub fn is_iref(&self) -> bool { pub fn is_fp(&self) -> bool {
match self.v {
MuType_::Float | MuType_::Double => true,
_ => false
}
}
pub fn is_float(&self) -> bool {
match self.v {
MuType_::Float => true,
_ => false
}
}
pub fn is_double(&self) -> bool {
match self.v {
MuType_::Double => true,
_ => false
}
}
/// is a type raw pointer?
pub fn is_ptr(&self) -> bool {
match self.v {
MuType_::UPtr(_) | MuType_::UFuncPtr(_) => true,
_ => false
}
}
/// this a type reference type (located in heap)?
pub fn is_reference(&self) -> bool {
match self.v {
MuType_::Ref(_)
| MuType_::IRef(_)
| MuType_::WeakRef(_) => true,
_ => false
}
}
/// this is a aggregated type (consited of other types)
pub fn is_aggregate(&self) -> bool {
match self.v { match self.v {
MuType_::Struct(_)
| MuType_::Hybrid(_)
| MuType_::Array(_, _) => true,
_ => false
}
}
/// is a type scalar type?
pub fn is_scalar(&self) -> bool {
match self.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(&self) -> bool {
match self.v {
MuType_::Ref(_) => true,
MuType_::IRef(_) => true, MuType_::IRef(_) => true,
MuType_::WeakRef(_) => true,
MuType_::Array(ref elem_ty, _)
| MuType_::Vector(ref elem_ty, _) => elem_ty.is_traced(),
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;
var_ty.is_traced() ||
fix_tys.into_iter().map(|ty| ty.is_traced())
.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| ty.is_traced())
.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(&self) -> bool {
match self.v {
MuType_::Int(_) => true,
MuType_::Float => true,
MuType_::Double => true,
MuType_::Void => true,
MuType_::Array(ref elem_ty, _)
| MuType_::Vector(ref elem_ty, _) => elem_ty.is_native_safe(),
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;
var_ty.is_native_safe() &&
fix_tys.into_iter().map(|ty| ty.is_native_safe())
.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;