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.

types.rs 17.1 KB
Newer Older
qinsoon's avatar
qinsoon committed
1 2 3
use ptr::P;
use ir::*;

qinsoon's avatar
qinsoon committed
4
use utils::POINTER_SIZE;
qinsoon's avatar
qinsoon committed
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
        }
    }
qinsoon's avatar
qinsoon committed
81

qinsoon's avatar
qinsoon committed
82 83 84 85 86 87 88 89 90 91 92 93 94 95
    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
96 97 98 99 100 101 102
    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
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
    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
121 122 123 124 125 126 127 128 129 130 131 132
    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
        }
    }

qinsoon's avatar
qinsoon committed
133 134 135 136 137 138 139 140 141 142
    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
        }
    }
qinsoon's avatar
qinsoon committed
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159

    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
160
}
qinsoon's avatar
qinsoon committed
161

162 163
pub type StructTag = MuName;
pub type HybridTag = MuName;
qinsoon's avatar
qinsoon committed
164
#[derive(PartialEq, Debug, RustcEncodable, RustcDecodable)]
qinsoon's avatar
qinsoon committed
165
pub enum MuType_ {
qinsoon's avatar
qinsoon committed
166
    /// int <length>
qinsoon's avatar
qinsoon committed
167
    Int          (usize),
qinsoon's avatar
qinsoon committed
168
    /// float
qinsoon's avatar
qinsoon committed
169
    Float,
qinsoon's avatar
qinsoon committed
170
    /// double
qinsoon's avatar
qinsoon committed
171
    Double,
172

qinsoon's avatar
qinsoon committed
173
    /// ref<T>
qinsoon's avatar
qinsoon committed
174
    Ref          (P<MuType>),    // Box is needed for non-recursive enum
qinsoon's avatar
qinsoon committed
175
    /// iref<T>: internal reference
qinsoon's avatar
qinsoon committed
176
    IRef         (P<MuType>),
qinsoon's avatar
qinsoon committed
177
    /// weakref<T>
qinsoon's avatar
qinsoon committed
178
    WeakRef      (P<MuType>),
179

qinsoon's avatar
qinsoon committed
180
    /// uptr<T>: unsafe pointer
qinsoon's avatar
qinsoon committed
181
    UPtr         (P<MuType>),
182

qinsoon's avatar
qinsoon committed
183
    /// struct<T1 T2 ...>
184
    Struct       (StructTag),
185

qinsoon's avatar
qinsoon committed
186
    /// array<T length>
qinsoon's avatar
qinsoon committed
187
    Array        (P<MuType>, usize),
188

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

qinsoon's avatar
qinsoon committed
192
    /// void
qinsoon's avatar
qinsoon committed
193
    Void,
194

qinsoon's avatar
qinsoon committed
195
    /// threadref
qinsoon's avatar
qinsoon committed
196
    ThreadRef,
qinsoon's avatar
qinsoon committed
197
    /// stackref
qinsoon's avatar
qinsoon committed
198
    StackRef,
199

qinsoon's avatar
qinsoon committed
200
    /// tagref64: hold a double or an int or an ref<void>
qinsoon's avatar
qinsoon committed
201
    Tagref64,
202

qinsoon's avatar
qinsoon committed
203
    /// vector<T length>
qinsoon's avatar
qinsoon committed
204
    Vector       (P<MuType>, usize),
205

qinsoon's avatar
qinsoon committed
206
    /// funcref<@sig>
207
    FuncRef      (P<MuFuncSig>),
208

qinsoon's avatar
qinsoon committed
209
    /// ufuncptr<@sig>
210
    UFuncPtr     (P<MuFuncSig>),
qinsoon's avatar
qinsoon committed
211 212
}

qinsoon's avatar
qinsoon committed
213 214 215 216 217 218
impl fmt::Display for MuType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.v)        
    }
}

219
impl fmt::Display for MuType_ {
220 221
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
qinsoon's avatar
qinsoon committed
222 223 224
            &MuType_::Int(n)                          => write!(f, "int<{}>", n),
            &MuType_::Float                           => write!(f, "float"),
            &MuType_::Double                          => write!(f, "double"),
225 226 227 228 229
            &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
230 231 232 233
            &MuType_::Void                            => write!(f, "void"),
            &MuType_::ThreadRef                       => write!(f, "threadref"),
            &MuType_::StackRef                        => write!(f, "stackref"),
            &MuType_::Tagref64                        => write!(f, "tagref64"),
234 235 236
            &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),
237 238
            &MuType_::Struct(ref tag)                 => write!(f, "{}(struct)", tag),
            &MuType_::Hybrid(ref tag)                 => write!(f, "{}(hybrid)", tag)
239 240 241 242
        }
    }
}

qinsoon's avatar
qinsoon committed
243
lazy_static! {
qinsoon's avatar
qinsoon committed
244
    /// storing a map from MuName to StructType_
245 246 247
    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
248 249
}

qinsoon's avatar
qinsoon committed
250
#[derive(PartialEq, Debug, RustcEncodable, RustcDecodable)]
qinsoon's avatar
qinsoon committed
251
pub struct StructType_ {
qinsoon's avatar
qinsoon committed
252
    tys: Vec<P<MuType>>
qinsoon's avatar
qinsoon committed
253 254
}

255
impl fmt::Display for StructType_ {
256
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
qinsoon's avatar
qinsoon committed
257 258 259
        write!(f, "struct<").unwrap();
        for i in 0..self.tys.len() {
            let ty = &self.tys[i];
260
            write!(f, "{}", ty).unwrap();
qinsoon's avatar
qinsoon committed
261 262 263
            if i != self.tys.len() - 1 {
                write!(f, " ").unwrap();
            }
264
        }
qinsoon's avatar
qinsoon committed
265
        write!(f, ">")
266
    }
267 268
}

qinsoon's avatar
qinsoon committed
269
impl StructType_ {
270 271 272 273
    // 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
274
    pub fn set_tys(&mut self, mut list: Vec<P<MuType>>) {
qinsoon's avatar
qinsoon committed
275
        self.tys.clear();
qinsoon's avatar
qinsoon committed
276
        self.tys.append(&mut list);
qinsoon's avatar
qinsoon committed
277
    }
qinsoon's avatar
qinsoon committed
278
    
qinsoon's avatar
qinsoon committed
279
    pub fn get_tys(&self) -> &Vec<P<MuType>> {
qinsoon's avatar
qinsoon committed
280 281
        &self.tys
    }
qinsoon's avatar
qinsoon committed
282 283
}

284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324
#[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
325 326 327
impl MuType_ {
    pub fn int(len: usize) -> MuType_ {
        MuType_::Int(len)
qinsoon's avatar
qinsoon committed
328
    }
qinsoon's avatar
qinsoon committed
329 330
    pub fn float() -> MuType_ {
        MuType_::Float
qinsoon's avatar
qinsoon committed
331
    }
qinsoon's avatar
qinsoon committed
332 333
    pub fn double() -> MuType_ {
        MuType_::Double
qinsoon's avatar
qinsoon committed
334
    }
qinsoon's avatar
qinsoon committed
335
    pub fn muref(referent: P<MuType>) -> MuType_ {
qinsoon's avatar
qinsoon committed
336
        MuType_::Ref(referent)
qinsoon's avatar
qinsoon committed
337
    }
qinsoon's avatar
qinsoon committed
338
    pub fn iref(referent: P<MuType>) -> MuType_ {
qinsoon's avatar
qinsoon committed
339
        MuType_::IRef(referent)
qinsoon's avatar
qinsoon committed
340
    }
qinsoon's avatar
qinsoon committed
341
    pub fn weakref(referent: P<MuType>) -> MuType_ {
qinsoon's avatar
qinsoon committed
342
        MuType_::WeakRef(referent)
qinsoon's avatar
qinsoon committed
343
    }
qinsoon's avatar
qinsoon committed
344
    pub fn uptr(referent: P<MuType>) -> MuType_ {
qinsoon's avatar
qinsoon committed
345
        MuType_::UPtr(referent)
qinsoon's avatar
qinsoon committed
346
    }
qinsoon's avatar
qinsoon committed
347
    pub fn mustruct_empty(tag: MuName) -> MuType_ {
qinsoon's avatar
qinsoon committed
348
        let struct_ty_ = StructType_{tys: vec![]};
349
        STRUCT_TAG_MAP.write().unwrap().insert(tag.clone(), struct_ty_);
qinsoon's avatar
qinsoon committed
350

qinsoon's avatar
qinsoon committed
351
        MuType_::Struct(tag)
qinsoon's avatar
qinsoon committed
352
    }
353
    pub fn mustruct_put(tag: &MuName, mut list: Vec<P<MuType>>) {
354 355
        let mut map_guard = STRUCT_TAG_MAP.write().unwrap();

356
        match map_guard.get_mut(tag) {
357 358 359 360 361 362 363 364
            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
365
        let struct_ty_ = StructType_{tys: list};
qinsoon's avatar
qinsoon committed
366 367 368

        // if there is an attempt to use a same tag for different struct,
        // we panic
369
        match STRUCT_TAG_MAP.read().unwrap().get(&tag) {
qinsoon's avatar
qinsoon committed
370 371
            Some(old_struct_ty_) => {
                if struct_ty_ != *old_struct_ty_ {
372 373
                    panic!("trying to insert {} as {}, while the old struct is defined as {}",
                            struct_ty_, tag, old_struct_ty_)
qinsoon's avatar
qinsoon committed
374 375 376 377 378
                }
            },
            None => {}
        }
        // otherwise, store the tag
379
        STRUCT_TAG_MAP.write().unwrap().insert(tag.clone(), struct_ty_);
qinsoon's avatar
qinsoon committed
380

qinsoon's avatar
qinsoon committed
381
        MuType_::Struct(tag)
qinsoon's avatar
qinsoon committed
382
    }
qinsoon's avatar
qinsoon committed
383
    pub fn array(ty: P<MuType>, len: usize) -> MuType_ {
qinsoon's avatar
qinsoon committed
384
        MuType_::Array(ty, len)
qinsoon's avatar
qinsoon committed
385
    }
386 387 388 389 390 391
    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)
    }
392
    pub fn hybrid_put(tag: &HybridTag, mut fix_tys: Vec<P<MuType>>, var_ty: P<MuType>) {
qinsoon's avatar
qinsoon committed
393 394
        let mut map_guard = HYBRID_TAG_MAP.write().unwrap();

395
        match map_guard.get_mut(tag) {
qinsoon's avatar
qinsoon committed
396 397 398 399 400 401 402 403 404
            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()")
        }
    }
405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421
    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
422
    }
qinsoon's avatar
qinsoon committed
423 424
    pub fn void() -> MuType_ {
        MuType_::Void
qinsoon's avatar
qinsoon committed
425
    }
qinsoon's avatar
qinsoon committed
426 427
    pub fn threadref() -> MuType_ {
        MuType_::ThreadRef
qinsoon's avatar
qinsoon committed
428
    }
qinsoon's avatar
qinsoon committed
429 430
    pub fn stackref() -> MuType_ {
        MuType_::StackRef
qinsoon's avatar
qinsoon committed
431
    }
qinsoon's avatar
qinsoon committed
432 433
    pub fn tagref64() -> MuType_ {
        MuType_::Tagref64
qinsoon's avatar
qinsoon committed
434
    }
qinsoon's avatar
qinsoon committed
435
    pub fn vector(ty: P<MuType>, len: usize) -> MuType_ {
qinsoon's avatar
qinsoon committed
436
        MuType_::Vector(ty, len)
qinsoon's avatar
qinsoon committed
437
    }
438
    pub fn funcref(sig: P<MuFuncSig>) -> MuType_ {
qinsoon's avatar
qinsoon committed
439
        MuType_::FuncRef(sig)
qinsoon's avatar
qinsoon committed
440
    }
441
    pub fn ufuncptr(sig: P<MuFuncSig>) -> MuType_ {
qinsoon's avatar
qinsoon committed
442
        MuType_::UFuncPtr(sig)
qinsoon's avatar
qinsoon committed
443 444 445 446
    }
}

/// is a type floating-point type?
qinsoon's avatar
qinsoon committed
447
pub fn is_fp(ty: &MuType) -> bool {
qinsoon's avatar
qinsoon committed
448
    match ty.v {
qinsoon's avatar
qinsoon committed
449
        MuType_::Float | MuType_::Double => true,
qinsoon's avatar
qinsoon committed
450 451 452 453 454
        _ => false
    }
}

/// is a type raw pointer?
qinsoon's avatar
qinsoon committed
455
pub fn is_ptr(ty: &MuType) -> bool {
qinsoon's avatar
qinsoon committed
456
    match ty.v {
qinsoon's avatar
qinsoon committed
457
        MuType_::UPtr(_) | MuType_::UFuncPtr(_) => true,
qinsoon's avatar
qinsoon committed
458 459 460 461
        _ => false
    }
}

462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481
/// 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
482
/// is a type scalar type?
qinsoon's avatar
qinsoon committed
483
pub fn is_scalar(ty: &MuType) -> bool {
qinsoon's avatar
qinsoon committed
484
    match ty.v {
qinsoon's avatar
qinsoon committed
485 486 487 488 489 490 491 492 493 494 495 496
        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
497 498 499 500 501
        _ => false
    }
}

/// is a type traced by the garbage collector?
502
/// Note: An aggregated type is traced if any of its part is traced.
qinsoon's avatar
qinsoon committed
503
pub fn is_traced(ty: &MuType) -> bool {
qinsoon's avatar
qinsoon committed
504
    match ty.v {
qinsoon's avatar
qinsoon committed
505 506 507 508 509 510 511 512
        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,
513 514 515 516 517 518 519
        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
520 521
            is_traced(var_ty) ||
            fix_tys.into_iter().map(|ty| is_traced(ty))
522
                .fold(false, |ret, this| ret || this)
qinsoon's avatar
qinsoon committed
523
            },
524
        MuType_::Struct(ref tag) => {
qinsoon's avatar
qinsoon committed
525 526 527
            let map = STRUCT_TAG_MAP.read().unwrap();
            let struct_ty = map.get(tag).unwrap();
            let ref field_tys = struct_ty.tys;
528

qinsoon's avatar
qinsoon committed
529 530 531 532 533 534 535 536 537
            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
538
pub fn is_native_safe(ty: &MuType) -> bool {
qinsoon's avatar
qinsoon committed
539
    match ty.v {
qinsoon's avatar
qinsoon committed
540 541 542 543 544 545 546 547
        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,
548 549 550 551 552 553 554
        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;

555
            is_native_safe(var_ty) &&
qinsoon's avatar
qinsoon committed
556 557 558
            fix_tys.into_iter().map(|ty| is_native_safe(&ty))
                .fold(true, |ret, this| ret && this)
        },
559
        MuType_::Struct(ref tag) => {
qinsoon's avatar
qinsoon committed
560 561 562
            let map = STRUCT_TAG_MAP.read().unwrap();
            let struct_ty = map.get(tag).unwrap();
            let ref field_tys = struct_ty.tys;
563

qinsoon's avatar
qinsoon committed
564 565 566 567
            field_tys.into_iter().map(|ty| is_native_safe(&ty))
                .fold(true, |ret, this| ret && this)
        },
        _ => false
qinsoon's avatar
qinsoon committed
568 569 570
    }
}

571
pub fn get_referent_ty(ty: &MuType) -> Option<P<MuType>> {
qinsoon's avatar
qinsoon committed
572 573 574
    match ty.v {
        MuType_::Ref(ref referent)
        | MuType_::IRef(ref referent)
575 576
        | MuType_::WeakRef(ref referent)
        | MuType_::UPtr(ref referent) => Some(referent.clone()),
577 578 579 580
        _ => None
    }
}

qinsoon's avatar
qinsoon committed
581 582 583 584 585 586 587 588 589
macro_rules! is_type (
    ($e:expr, $p:pat) => (
        match $e {
            $p => true,
            _ => false
        }
    )
);

590 591
pub type CFuncSig = MuFuncSig;

qinsoon's avatar
qinsoon committed
592
#[derive(PartialEq, Debug, RustcEncodable, RustcDecodable)]
qinsoon's avatar
qinsoon committed
593
pub struct MuFuncSig {
594
    pub hdr: MuEntityHeader,
qinsoon's avatar
qinsoon committed
595 596
    pub ret_tys : Vec<P<MuType>>,
    pub arg_tys: Vec<P<MuType>>
597 598
}

599
impl fmt::Display for MuFuncSig {
600
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
qinsoon's avatar
qinsoon committed
601
        write!(f, "[{}] -> [{}]", vec_utils::as_str(&self.arg_tys), vec_utils::as_str(&self.ret_tys))
602 603
    }
}