types.rs 17.6 KB
Newer Older
1 2 3
use ptr::P;
use ir::*;

qinsoon's avatar
qinsoon committed
4
use utils::POINTER_SIZE;
5
use utils::vec_utils;
6 7

use std::fmt;
qinsoon's avatar
qinsoon committed
8 9
use std::collections::HashMap;
use std::sync::RwLock;
qinsoon's avatar
qinsoon committed
10

qinsoon's avatar
qinsoon committed
11 12 13 14
lazy_static! {
    pub static ref ADDRESS_TYPE : P<MuType> = P(
        MuType::new(new_internal_id(), MuType_::int(POINTER_SIZE * 8))
    );
15

16 17 18 19
    pub static ref UINT1_TYPE : P<MuType> = P(
        MuType::new(new_internal_id(), MuType_::int(1))
    );

20 21 22 23 24 25 26
    pub static ref UINT8_TYPE : P<MuType> = P(
        MuType::new(new_internal_id(), MuType_::int(8))
    );

    pub static ref UINT16_TYPE : P<MuType> = P(
        MuType::new(new_internal_id(), MuType_::int(16))
    );
qinsoon's avatar
qinsoon committed
27 28 29 30 31 32 33 34 35 36 37 38
    
    pub static ref UINT32_TYPE : P<MuType> = P(
        MuType::new(new_internal_id(), MuType_::int(32))
    );
    
    pub static ref UINT64_TYPE : P<MuType> = P(
        MuType::new(new_internal_id(), MuType_::int(64))
    );
    
    pub static ref DOUBLE_TYPE : P<MuType> = P(
        MuType::new(new_internal_id(), MuType_::double())
    );
39 40 41 42

    pub static ref VOID_TYPE : P<MuType> = P(
        MuType::new(new_internal_id(), MuType_::void())
    );
qinsoon's avatar
qinsoon committed
43 44 45
    
    pub static ref INTERNAL_TYPES : Vec<P<MuType>> = vec![
        ADDRESS_TYPE.clone(),
46
        UINT1_TYPE.clone(),
qinsoon's avatar
qinsoon committed
47 48
        UINT8_TYPE.clone(),
        UINT16_TYPE.clone(),
qinsoon's avatar
qinsoon committed
49 50
        UINT32_TYPE.clone(),
        UINT64_TYPE.clone(),
qinsoon's avatar
qinsoon committed
51 52
        DOUBLE_TYPE.clone(),
        VOID_TYPE.clone()
qinsoon's avatar
qinsoon committed
53 54 55
    ];    
}

56 57 58 59 60 61 62 63 64 65 66 67
pub fn init_types() {
    {
        let mut map_lock = STRUCT_TAG_MAP.write().unwrap();
        map_lock.clear();
    }

    {
        let mut map_lock = HYBRID_TAG_MAP.write().unwrap();
        map_lock.clear();
    }
}

qinsoon's avatar
qinsoon committed
68
#[derive(PartialEq, Debug, RustcEncodable, RustcDecodable)]
qinsoon's avatar
qinsoon committed
69
pub struct MuType {
70
    pub hdr: MuEntityHeader,
qinsoon's avatar
qinsoon committed
71 72 73 74 75 76
    pub v: MuType_
}

impl MuType {
    pub fn new(id: MuID, v: MuType_) -> MuType {
        MuType {
77
            hdr: MuEntityHeader::unnamed(id),
qinsoon's avatar
qinsoon committed
78 79 80
            v: v
        }
    }
81

qinsoon's avatar
qinsoon committed
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
    pub fn is_struct(&self) -> bool {
        match self.v {
            MuType_::Struct(_) => true,
            _ => false
        }
    }

    pub fn is_hybrid(&self) -> bool {
        match self.v {
            MuType_::Hybrid(_) => true,
            _ => false
        }
    }

    pub fn get_struct_hybrid_tag(&self) -> Option<MuName> {
        match self.v {
            MuType_::Hybrid(ref name)
            | MuType_::Struct(ref name) => Some(name.clone()),
            _ => None
        }
    }

qinsoon's avatar
qinsoon committed
104 105 106 107 108 109 110 111 112 113 114 115 116 117
    pub fn is_ref(&self) -> bool {
        match self.v {
            MuType_::Ref(_) => true,
            _ => false
        }
    }

    pub fn is_iref(&self) -> bool {
        match self.v {
            MuType_::IRef(_) => true,
            _ => false
        }
    }

qinsoon's avatar
qinsoon committed
118 119 120 121 122 123 124
    pub fn get_elem_ty(&self) -> Option<P<MuType>> {
        match self.v {
            MuType_::Array(ref elem_ty, _) => Some(elem_ty.clone()),
            _ => None
        }
    }

qinsoon's avatar
qinsoon committed
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
    pub fn get_field_ty(&self, index: usize) -> Option<P<MuType>> {
        match self.v {
            MuType_::Struct(ref tag) => {
                let map_lock = STRUCT_TAG_MAP.read().unwrap();
                let struct_inner = map_lock.get(tag).unwrap();

                Some(struct_inner.tys[index].clone())
            },
            MuType_::Hybrid(ref tag) => {
                let map_lock = HYBRID_TAG_MAP.read().unwrap();
                let hybrid_inner = map_lock.get(tag).unwrap();

                Some(hybrid_inner.fix_tys[index].clone())
            },
            _ => None
        }
    }

qinsoon's avatar
qinsoon committed
143 144 145 146 147 148 149 150 151 152 153 154
    pub fn get_hybrid_varpart_ty(&self) -> Option<P<MuType>> {
        match self.v {
            MuType_::Hybrid(ref tag) => {
                let map_lock = HYBRID_TAG_MAP.read().unwrap();
                let hybrid_inner = map_lock.get(tag).unwrap();

                Some(hybrid_inner.var_ty.clone())
            },
            _ => None
        }
    }

155 156 157 158 159 160 161 162 163 164
    pub fn get_referenced_ty(&self) -> Option<P<MuType>> {
        use types::MuType_::*;
        match self.v {
            Ref(ref ty)
            | IRef(ref ty)
            | WeakRef(ref ty)
            | UPtr(ref ty) => Some(ty.clone()),
            _ => None
        }
    }
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181

    pub fn get_int_length(&self) -> Option<usize> {
        use types::MuType_::*;
        match self.v {
            Int(len) => Some(len),
            Ref(_)
            | IRef(_)
            | WeakRef(_)
            | UPtr(_)
            | ThreadRef
            | StackRef
            | Tagref64
            | FuncRef(_)
            | UFuncPtr(_) => Some(64),
            _ => None
        }
    }
qinsoon's avatar
qinsoon committed
182
}
qinsoon's avatar
qinsoon committed
183

184 185
pub type StructTag = MuName;
pub type HybridTag = MuName;
qinsoon's avatar
qinsoon committed
186
#[derive(PartialEq, Debug, RustcEncodable, RustcDecodable)]
qinsoon's avatar
qinsoon committed
187
pub enum MuType_ {
qinsoon's avatar
qinsoon committed
188
    /// int <length>
qinsoon's avatar
qinsoon committed
189
    Int          (usize),
qinsoon's avatar
qinsoon committed
190
    /// float
qinsoon's avatar
qinsoon committed
191
    Float,
qinsoon's avatar
qinsoon committed
192
    /// double
qinsoon's avatar
qinsoon committed
193
    Double,
194

qinsoon's avatar
qinsoon committed
195
    /// ref<T>
qinsoon's avatar
qinsoon committed
196
    Ref          (P<MuType>),    // Box is needed for non-recursive enum
qinsoon's avatar
qinsoon committed
197
    /// iref<T>: internal reference
qinsoon's avatar
qinsoon committed
198
    IRef         (P<MuType>),
qinsoon's avatar
qinsoon committed
199
    /// weakref<T>
qinsoon's avatar
qinsoon committed
200
    WeakRef      (P<MuType>),
201

qinsoon's avatar
qinsoon committed
202
    /// uptr<T>: unsafe pointer
qinsoon's avatar
qinsoon committed
203
    UPtr         (P<MuType>),
204

qinsoon's avatar
qinsoon committed
205
    /// struct<T1 T2 ...>
206
    Struct       (StructTag),
207

qinsoon's avatar
qinsoon committed
208
    /// array<T length>
qinsoon's avatar
qinsoon committed
209
    Array        (P<MuType>, usize),
210

qinsoon's avatar
qinsoon committed
211
    /// hybrid<F1 F2 ... V>: a hybrid of fixed length parts and a variable length part
212
    Hybrid       (HybridTag),
213

qinsoon's avatar
qinsoon committed
214
    /// void
qinsoon's avatar
qinsoon committed
215
    Void,
216

qinsoon's avatar
qinsoon committed
217
    /// threadref
qinsoon's avatar
qinsoon committed
218
    ThreadRef,
qinsoon's avatar
qinsoon committed
219
    /// stackref
qinsoon's avatar
qinsoon committed
220
    StackRef,
221

qinsoon's avatar
qinsoon committed
222
    /// tagref64: hold a double or an int or an ref<void>
qinsoon's avatar
qinsoon committed
223
    Tagref64,
224

qinsoon's avatar
qinsoon committed
225
    /// vector<T length>
qinsoon's avatar
qinsoon committed
226
    Vector       (P<MuType>, usize),
227

qinsoon's avatar
qinsoon committed
228
    /// funcref<@sig>
229
    FuncRef      (P<MuFuncSig>),
230

qinsoon's avatar
qinsoon committed
231
    /// ufuncptr<@sig>
232
    UFuncPtr     (P<MuFuncSig>),
qinsoon's avatar
qinsoon committed
233 234
}

qinsoon's avatar
qinsoon committed
235 236 237 238 239 240
impl fmt::Display for MuType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.v)        
    }
}

241
impl fmt::Display for MuType_ {
242 243
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
qinsoon's avatar
qinsoon committed
244 245 246
            &MuType_::Int(n)                          => write!(f, "int<{}>", n),
            &MuType_::Float                           => write!(f, "float"),
            &MuType_::Double                          => write!(f, "double"),
247 248 249 250 251
            &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),
qinsoon's avatar
qinsoon committed
252 253 254 255
            &MuType_::Void                            => write!(f, "void"),
            &MuType_::ThreadRef                       => write!(f, "threadref"),
            &MuType_::StackRef                        => write!(f, "stackref"),
            &MuType_::Tagref64                        => write!(f, "tagref64"),
256 257 258
            &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),
259 260
            &MuType_::Struct(ref tag)                 => write!(f, "{}(struct)", tag),
            &MuType_::Hybrid(ref tag)                 => write!(f, "{}(hybrid)", tag)
261 262 263 264
        }
    }
}

qinsoon's avatar
qinsoon committed
265
lazy_static! {
qinsoon's avatar
qinsoon committed
266
    /// storing a map from MuName to StructType_
267 268 269
    pub static ref STRUCT_TAG_MAP : RwLock<HashMap<StructTag, StructType_>> = RwLock::new(HashMap::new());
    /// storing a map from MuName to HybridType_
    pub static ref HYBRID_TAG_MAP : RwLock<HashMap<HybridTag, HybridType_>> = RwLock::new(HashMap::new());
qinsoon's avatar
qinsoon committed
270 271
}

qinsoon's avatar
qinsoon committed
272
#[derive(PartialEq, Debug, RustcEncodable, RustcDecodable)]
qinsoon's avatar
qinsoon committed
273
pub struct StructType_ {
qinsoon's avatar
qinsoon committed
274
    tys: Vec<P<MuType>>
qinsoon's avatar
qinsoon committed
275 276
}

277
impl fmt::Display for StructType_ {
278
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
qinsoon's avatar
qinsoon committed
279 280 281
        write!(f, "struct<").unwrap();
        for i in 0..self.tys.len() {
            let ty = &self.tys[i];
282
            write!(f, "{}", ty).unwrap();
qinsoon's avatar
qinsoon committed
283 284 285
            if i != self.tys.len() - 1 {
                write!(f, " ").unwrap();
            }
286
        }
qinsoon's avatar
qinsoon committed
287
        write!(f, ">")
288
    }
289 290
}

qinsoon's avatar
qinsoon committed
291
impl StructType_ {
292 293 294 295
    // The IR builder needs to create StructType objects, too.
    pub fn new(tys: Vec<P<MuType>>) -> StructType_ {
        StructType_ { tys: tys }
    }
qinsoon's avatar
qinsoon committed
296
    pub fn set_tys(&mut self, mut list: Vec<P<MuType>>) {
qinsoon's avatar
qinsoon committed
297
        self.tys.clear();
qinsoon's avatar
qinsoon committed
298
        self.tys.append(&mut list);
qinsoon's avatar
qinsoon committed
299
    }
qinsoon's avatar
qinsoon committed
300
    
qinsoon's avatar
qinsoon committed
301
    pub fn get_tys(&self) -> &Vec<P<MuType>> {
qinsoon's avatar
qinsoon committed
302 303
        &self.tys
    }
qinsoon's avatar
qinsoon committed
304 305
}

306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346
#[derive(PartialEq, Debug, RustcEncodable, RustcDecodable)]
pub struct HybridType_ {
    fix_tys: Vec<P<MuType>>,
    var_ty : P<MuType>
}

impl HybridType_ {
    pub fn new(fix_tys: Vec<P<MuType>>, var_ty: P<MuType>) -> HybridType_ {
        HybridType_ {fix_tys: fix_tys, var_ty: var_ty}
    }

    pub fn set_tys(&mut self, mut fix_tys: Vec<P<MuType>>, var_ty: P<MuType>) {
        self.fix_tys.clear();
        self.fix_tys.append(&mut fix_tys);

        self.var_ty = var_ty;
    }

    pub fn get_fix_tys(&self) -> &Vec<P<MuType>> {
        &self.fix_tys
    }

    pub fn get_var_ty(&self) -> &P<MuType> {
        &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)
    }
}

qinsoon's avatar
qinsoon committed
347 348 349
impl MuType_ {
    pub fn int(len: usize) -> MuType_ {
        MuType_::Int(len)
qinsoon's avatar
qinsoon committed
350
    }
qinsoon's avatar
qinsoon committed
351 352
    pub fn float() -> MuType_ {
        MuType_::Float
qinsoon's avatar
qinsoon committed
353
    }
qinsoon's avatar
qinsoon committed
354 355
    pub fn double() -> MuType_ {
        MuType_::Double
qinsoon's avatar
qinsoon committed
356
    }
qinsoon's avatar
qinsoon committed
357
    pub fn muref(referent: P<MuType>) -> MuType_ {
qinsoon's avatar
qinsoon committed
358
        MuType_::Ref(referent)
qinsoon's avatar
qinsoon committed
359
    }
qinsoon's avatar
qinsoon committed
360
    pub fn iref(referent: P<MuType>) -> MuType_ {
qinsoon's avatar
qinsoon committed
361
        MuType_::IRef(referent)
qinsoon's avatar
qinsoon committed
362
    }
qinsoon's avatar
qinsoon committed
363
    pub fn weakref(referent: P<MuType>) -> MuType_ {
qinsoon's avatar
qinsoon committed
364
        MuType_::WeakRef(referent)
qinsoon's avatar
qinsoon committed
365
    }
qinsoon's avatar
qinsoon committed
366
    pub fn uptr(referent: P<MuType>) -> MuType_ {
qinsoon's avatar
qinsoon committed
367
        MuType_::UPtr(referent)
qinsoon's avatar
qinsoon committed
368
    }
qinsoon's avatar
qinsoon committed
369
    pub fn mustruct_empty(tag: MuName) -> MuType_ {
qinsoon's avatar
qinsoon committed
370
        let struct_ty_ = StructType_{tys: vec![]};
371
        STRUCT_TAG_MAP.write().unwrap().insert(tag.clone(), struct_ty_);
qinsoon's avatar
qinsoon committed
372

qinsoon's avatar
qinsoon committed
373
        MuType_::Struct(tag)
qinsoon's avatar
qinsoon committed
374
    }
375
    pub fn mustruct_put(tag: &MuName, mut list: Vec<P<MuType>>) {
376 377
        let mut map_guard = STRUCT_TAG_MAP.write().unwrap();

378
        match map_guard.get_mut(tag) {
379 380 381 382 383 384 385 386
            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<P<MuType>>) -> MuType_ {
qinsoon's avatar
qinsoon committed
387
        let struct_ty_ = StructType_{tys: list};
qinsoon's avatar
qinsoon committed
388 389 390

        // if there is an attempt to use a same tag for different struct,
        // we panic
391
        match STRUCT_TAG_MAP.read().unwrap().get(&tag) {
qinsoon's avatar
qinsoon committed
392 393
            Some(old_struct_ty_) => {
                if struct_ty_ != *old_struct_ty_ {
394 395
                    panic!("trying to insert {} as {}, while the old struct is defined as {}",
                            struct_ty_, tag, old_struct_ty_)
qinsoon's avatar
qinsoon committed
396 397 398 399 400
                }
            },
            None => {}
        }
        // otherwise, store the tag
401
        STRUCT_TAG_MAP.write().unwrap().insert(tag.clone(), struct_ty_);
qinsoon's avatar
qinsoon committed
402

qinsoon's avatar
qinsoon committed
403
        MuType_::Struct(tag)
qinsoon's avatar
qinsoon committed
404
    }
qinsoon's avatar
qinsoon committed
405
    pub fn array(ty: P<MuType>, len: usize) -> MuType_ {
qinsoon's avatar
qinsoon committed
406
        MuType_::Array(ty, len)
qinsoon's avatar
qinsoon committed
407
    }
408 409 410 411 412 413
    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)
    }
414
    pub fn hybrid_put(tag: &HybridTag, mut fix_tys: Vec<P<MuType>>, var_ty: P<MuType>) {
qinsoon's avatar
qinsoon committed
415 416
        let mut map_guard = HYBRID_TAG_MAP.write().unwrap();

417
        match map_guard.get_mut(tag) {
qinsoon's avatar
qinsoon committed
418 419 420 421 422 423 424 425 426
            Some(hybrid_ty_) => {
                hybrid_ty_.fix_tys.clear();
                hybrid_ty_.fix_tys.append(&mut fix_tys);

                hybrid_ty_.var_ty = var_ty;
            },
            None => panic!("call hybrid_empty() to create an empty struct before hybrid_put()")
        }
    }
427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443
    pub fn hybrid(tag: HybridTag, fix_tys: Vec<P<MuType>>, var_ty: P<MuType>) -> 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)
qinsoon's avatar
qinsoon committed
444
    }
qinsoon's avatar
qinsoon committed
445 446
    pub fn void() -> MuType_ {
        MuType_::Void
qinsoon's avatar
qinsoon committed
447
    }
qinsoon's avatar
qinsoon committed
448 449
    pub fn threadref() -> MuType_ {
        MuType_::ThreadRef
qinsoon's avatar
qinsoon committed
450
    }
qinsoon's avatar
qinsoon committed
451 452
    pub fn stackref() -> MuType_ {
        MuType_::StackRef
qinsoon's avatar
qinsoon committed
453
    }
qinsoon's avatar
qinsoon committed
454 455
    pub fn tagref64() -> MuType_ {
        MuType_::Tagref64
qinsoon's avatar
qinsoon committed
456
    }
qinsoon's avatar
qinsoon committed
457
    pub fn vector(ty: P<MuType>, len: usize) -> MuType_ {
qinsoon's avatar
qinsoon committed
458
        MuType_::Vector(ty, len)
qinsoon's avatar
qinsoon committed
459
    }
460
    pub fn funcref(sig: P<MuFuncSig>) -> MuType_ {
qinsoon's avatar
qinsoon committed
461
        MuType_::FuncRef(sig)
qinsoon's avatar
qinsoon committed
462
    }
463
    pub fn ufuncptr(sig: P<MuFuncSig>) -> MuType_ {
qinsoon's avatar
qinsoon committed
464
        MuType_::UFuncPtr(sig)
qinsoon's avatar
qinsoon committed
465 466 467 468
    }
}

/// is a type floating-point type?
qinsoon's avatar
qinsoon committed
469
pub fn is_fp(ty: &MuType) -> bool {
qinsoon's avatar
qinsoon committed
470
    match ty.v {
qinsoon's avatar
qinsoon committed
471
        MuType_::Float | MuType_::Double => true,
qinsoon's avatar
qinsoon committed
472 473 474 475 476
        _ => false
    }
}

/// is a type raw pointer?
qinsoon's avatar
qinsoon committed
477
pub fn is_ptr(ty: &MuType) -> bool {
qinsoon's avatar
qinsoon committed
478
    match ty.v {
qinsoon's avatar
qinsoon committed
479
        MuType_::UPtr(_) | MuType_::UFuncPtr(_) => true,
qinsoon's avatar
qinsoon committed
480 481 482 483
        _ => false
    }
}

484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503
/// this a type reference type (located in heap)?
pub fn is_reference(ty: &MuType) -> bool {
    match ty.v {
        MuType_::Ref(_)
        | MuType_::IRef(_)
        | MuType_::WeakRef(_) => true,
        _ => false
    }
}

/// this is a aggregated type (consited of other types)
pub fn is_aggregate(ty: &MuType) -> bool {
    match ty.v {
        MuType_::Struct(_)
        | MuType_::Hybrid(_)
        | MuType_::Array(_, _) => true,
        _ => false
    }
}

qinsoon's avatar
qinsoon committed
504
/// is a type scalar type?
qinsoon's avatar
qinsoon committed
505
pub fn is_scalar(ty: &MuType) -> bool {
qinsoon's avatar
qinsoon committed
506
    match ty.v {
qinsoon's avatar
qinsoon committed
507 508 509 510 511 512 513 514 515 516 517 518
        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,
qinsoon's avatar
qinsoon committed
519 520 521 522 523
        _ => false
    }
}

/// is a type traced by the garbage collector?
524
/// Note: An aggregated type is traced if any of its part is traced.
qinsoon's avatar
qinsoon committed
525
pub fn is_traced(ty: &MuType) -> bool {
qinsoon's avatar
qinsoon committed
526
    match ty.v {
qinsoon's avatar
qinsoon committed
527 528 529 530 531 532 533 534
        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,
535 536 537 538 539 540 541
        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;

qinsoon's avatar
qinsoon committed
542 543
            is_traced(var_ty) ||
            fix_tys.into_iter().map(|ty| is_traced(ty))
544
                .fold(false, |ret, this| ret || this)
qinsoon's avatar
qinsoon committed
545
            },
546
        MuType_::Struct(ref tag) => {
qinsoon's avatar
qinsoon committed
547 548 549
            let map = STRUCT_TAG_MAP.read().unwrap();
            let struct_ty = map.get(tag).unwrap();
            let ref field_tys = struct_ty.tys;
550

qinsoon's avatar
qinsoon committed
551 552 553 554 555 556 557 558 559
            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.
qinsoon's avatar
qinsoon committed
560
pub fn is_native_safe(ty: &MuType) -> bool {
qinsoon's avatar
qinsoon committed
561
    match ty.v {
qinsoon's avatar
qinsoon committed
562 563 564 565 566 567 568 569
        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,
570 571 572 573 574 575 576
        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;

577
            is_native_safe(var_ty) &&
qinsoon's avatar
qinsoon committed
578 579 580
            fix_tys.into_iter().map(|ty| is_native_safe(&ty))
                .fold(true, |ret, this| ret && this)
        },
581
        MuType_::Struct(ref tag) => {
qinsoon's avatar
qinsoon committed
582 583 584
            let map = STRUCT_TAG_MAP.read().unwrap();
            let struct_ty = map.get(tag).unwrap();
            let ref field_tys = struct_ty.tys;
585

qinsoon's avatar
qinsoon committed
586 587 588 589
            field_tys.into_iter().map(|ty| is_native_safe(&ty))
                .fold(true, |ret, this| ret && this)
        },
        _ => false
qinsoon's avatar
qinsoon committed
590 591 592
    }
}

593
pub fn get_referent_ty(ty: &MuType) -> Option<P<MuType>> {
qinsoon's avatar
qinsoon committed
594 595 596
    match ty.v {
        MuType_::Ref(ref referent)
        | MuType_::IRef(ref referent)
597 598
        | MuType_::WeakRef(ref referent)
        | MuType_::UPtr(ref referent) => Some(referent.clone()),
599 600 601 602
        _ => None
    }
}

qinsoon's avatar
qinsoon committed
603 604 605 606 607 608 609 610 611
macro_rules! is_type (
    ($e:expr, $p:pat) => (
        match $e {
            $p => true,
            _ => false
        }
    )
);

612 613
pub type CFuncSig = MuFuncSig;

qinsoon's avatar
qinsoon committed
614
#[derive(PartialEq, Debug, RustcEncodable, RustcDecodable)]
qinsoon's avatar
qinsoon committed
615
pub struct MuFuncSig {
616
    pub hdr: MuEntityHeader,
qinsoon's avatar
qinsoon committed
617 618
    pub ret_tys : Vec<P<MuType>>,
    pub arg_tys: Vec<P<MuType>>
619 620
}

621
impl fmt::Display for MuFuncSig {
622
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
623
        write!(f, "[{}] -> [{}]", vec_utils::as_str(&self.arg_tys), vec_utils::as_str(&self.ret_tys))
624 625
    }
}