To protect your data, the CISO officer has suggested users to enable 2FA as soon as possible.
Currently 2.7% of users enabled 2FA.

types.rs 22 KB
Newer Older
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1
// Copyright 2017 The Australian National University
2
//
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
3
4
5
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
6
//
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
7
//     http://www.apache.org/licenses/LICENSE-2.0
8
//
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
9
10
11
12
13
14
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

qinsoon's avatar
qinsoon committed
15
16
17
use ptr::P;
use ir::*;

qinsoon's avatar
qinsoon committed
18
use utils::POINTER_SIZE;
qinsoon's avatar
qinsoon committed
19
use utils::vec_utils;
20

21
22
use std;
use rodal;
23
use std::fmt;
24
use std::collections::HashMap;
qinsoon's avatar
qinsoon committed
25
use std::sync::RwLock;
qinsoon's avatar
qinsoon committed
26

27
// some common types that the compiler may use internally
qinsoon's avatar
qinsoon committed
28
29
30
31
lazy_static! {
    pub static ref ADDRESS_TYPE : P<MuType> = P(
        MuType::new(new_internal_id(), MuType_::int(POINTER_SIZE * 8))
    );
qinsoon's avatar
qinsoon committed
32

33
34
35
36
    pub static ref UINT1_TYPE : P<MuType> = P(
        MuType::new(new_internal_id(), MuType_::int(1))
    );

qinsoon's avatar
qinsoon committed
37
38
39
40
41
42
43
    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
44
45
46
47
48
49
50
51
    
    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))
    );
52
53
54

    pub static ref UINT128_TYPE : P<MuType> = P(
        MuType::new(new_internal_id(), MuType_::int(128))
qinsoon's avatar
qinsoon committed
55
    );
56

57
    pub static ref FLOAT_TYPE : P<MuType> = P(
58
59
60
        MuType::new(new_internal_id(), MuType_::float())
    );

qinsoon's avatar
qinsoon committed
61
62
63
    pub static ref DOUBLE_TYPE : P<MuType> = P(
        MuType::new(new_internal_id(), MuType_::double())
    );
64
65
66
67

    pub static ref VOID_TYPE : P<MuType> = P(
        MuType::new(new_internal_id(), MuType_::void())
    );
68
69
70
71
72

    pub static ref REF_VOID_TYPE : P<MuType> = P(
        MuType::new(new_internal_id(), MuType_::muref(VOID_TYPE.clone()))
    );

73
74
75
76
    pub static ref IREF_VOID_TYPE : P<MuType> = P(
        MuType::new(new_internal_id(), MuType_::iref(VOID_TYPE.clone()))
    );

qinsoon's avatar
qinsoon committed
77
78
    pub static ref INTERNAL_TYPES : Vec<P<MuType>> = vec![
        ADDRESS_TYPE.clone(),
79
        UINT1_TYPE.clone(),
qinsoon's avatar
qinsoon committed
80
81
        UINT8_TYPE.clone(),
        UINT16_TYPE.clone(),
qinsoon's avatar
qinsoon committed
82
83
        UINT32_TYPE.clone(),
        UINT64_TYPE.clone(),
84
85
        UINT128_TYPE.clone(),
        FLOAT_TYPE.clone(),
qinsoon's avatar
qinsoon committed
86
        DOUBLE_TYPE.clone(),
87
        FLOAT_TYPE.clone(),
88
89
        VOID_TYPE.clone(),
        REF_VOID_TYPE.clone(),
90
        IREF_VOID_TYPE.clone(),
91
    ];
qinsoon's avatar
qinsoon committed
92
93
}

94
/// clear struct/hybrid maps, called when creating new VM
95
96
97
98
99
100
101
102
103
104
105
106
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();
    }
}

107
/// MuType represents a Mu type
108
#[derive(PartialEq, Debug)]
qinsoon's avatar
qinsoon committed
109
pub struct MuType {
110
    pub hdr: MuEntityHeader,
qinsoon's avatar
qinsoon committed
111
112
113
    pub v: MuType_
}

114
rodal_struct!(MuType{hdr, v});
115

qinsoon's avatar
qinsoon committed
116
impl MuType {
117
    /// creates a new Mu type
qinsoon's avatar
qinsoon committed
118
119
    pub fn new(id: MuID, v: MuType_) -> MuType {
        MuType {
120
            hdr: MuEntityHeader::unnamed(id),
qinsoon's avatar
qinsoon committed
121
122
123
            v: v
        }
    }
qinsoon's avatar
qinsoon committed
124

125
    /// is this type struct type?
qinsoon's avatar
qinsoon committed
126
127
128
129
130
131
132
    pub fn is_struct(&self) -> bool {
        match self.v {
            MuType_::Struct(_) => true,
            _ => false
        }
    }

133
    /// is this type hybrid type?
qinsoon's avatar
qinsoon committed
134
135
136
137
138
139
140
    pub fn is_hybrid(&self) -> bool {
        match self.v {
            MuType_::Hybrid(_) => true,
            _ => false
        }
    }

141
142
    /// is this type a floating point type? (float/double)
    pub fn is_fp(&self) -> bool {
qinsoon's avatar
qinsoon committed
143
        match self.v {
144
            MuType_::Float | MuType_::Double => true,
145
            _ => false
qinsoon's avatar
qinsoon committed
146
147
148
        }
    }

149
150
    /// is this type a float type (single-precision floating point)
    pub fn is_float(&self) -> bool {
qinsoon's avatar
qinsoon committed
151
        match self.v {
152
            MuType_::Float => true,
qinsoon's avatar
qinsoon committed
153
154
155
156
            _ => false
        }
    }

157
158
    /// is this type a double type (double-precision floating point)
    pub fn is_double(&self) -> bool {
159
        match self.v {
160
            MuType_::Double => true,
161
162
163
164
            _ => false
        }
    }

165
166
    /// is this type a scalar type?
    pub fn is_scalar(&self) -> bool {
167
        match self.v {
168
169
170
171
172
173
174
175
176
177
178
179
            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,
180
181
182
183
            _ => false
        }
    }

184
185
    /// gets the tag of a struct/hybrid type, returns None if the type is not hybrid/struct
    /// We use tag to resolve recursive types, and maintains a map between tag and struct types
qinsoon's avatar
qinsoon committed
186
    pub fn get_struct_hybrid_tag(&self) -> Option<MuName> {
187
        match self.v {
qinsoon's avatar
qinsoon committed
188
189
190
            MuType_::Hybrid(ref name)
            | MuType_::Struct(ref name) => Some(name.clone()),
            _ => None
191
192
193
        }
    }

194
195
    /// is this type a reference type?
    /// (only reference type, which does not include iref, or other opaque reference types)
qinsoon's avatar
qinsoon committed
196
197
198
    pub fn is_ref(&self) -> bool {
        match self.v {
            MuType_::Ref(_) => true,
199
200
201
202
            _ => false
        }
    }

203
204
    /// is this type any reference type pointing to the heap? (including ref/iref/weakref)
    pub fn is_heap_reference(&self) -> bool {
205
206
207
208
209
210
211
212
        match self.v {
            MuType_::Ref(_)
            | MuType_::IRef(_)
            | MuType_::WeakRef(_) => true,
            _ => false
        }
    }

213
    /// is this type an internal reference type?
qinsoon's avatar
qinsoon committed
214
    pub fn is_iref(&self) -> bool {
215
        match self.v {
qinsoon's avatar
qinsoon committed
216
            MuType_::IRef(_) => true,
217
218
219
220
            _ => false
        }
    }

221
222
    /// is a type raw pointer?
    pub fn is_ptr(&self) -> bool {
223
        match self.v {
224
225
226
227
228
            MuType_::UPtr(_) | MuType_::UFuncPtr(_) => true,
            _ => false
        }
    }

229
230
231
232
233
234
    /// is this type an aggregated type? (consisted of other types)
    pub fn is_aggregate(&self) -> bool {
        match self.v {
            MuType_::Struct(_)
            | MuType_::Hybrid(_)
            | MuType_::Array(_, _) => true,
235
236
237
238
            _ => false
        }
    }

239
    /// is this type a type traced by the garbage collector?
240
    /// Note: An aggregated type is traced if any of its part is traced.
241
    #[allow(dead_code)]
242
243
244
    pub fn is_traced(&self) -> bool {
        match self.v {
            MuType_::Ref(_) => true,
qinsoon's avatar
qinsoon committed
245
            MuType_::IRef(_) => true,
246
247
248
249
250
251
252
253
254
255
256
257
258
            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;

259
260
                var_ty.is_traced()
                || fix_tys.into_iter().map(|ty| ty.is_traced())
261
262
263
264
265
266
267
268
269
270
271
272
273
274
                        .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
        }
    }

275
    /// is this type native safe?
276
    /// Note: An aggregated type is native safe if all of its parts are native safe.
277
    #[allow(dead_code)]
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
    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;

295
296
                var_ty.is_native_safe()
                && fix_tys.into_iter().map(|ty| ty.is_native_safe())
297
298
299
300
301
302
303
304
305
306
                        .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| ty.is_native_safe())
                    .fold(true, |ret, this| ret && this)
            },
qinsoon's avatar
qinsoon committed
307
308
309
310
            _ => false
        }
    }

311
    /// gets the element type of an array type, returns None if the type is not an array type
qinsoon's avatar
qinsoon committed
312
313
314
315
316
317
318
    pub fn get_elem_ty(&self) -> Option<P<MuType>> {
        match self.v {
            MuType_::Array(ref elem_ty, _) => Some(elem_ty.clone()),
            _ => None
        }
    }

319
    /// gets a field's type of a struct type, returns None if the type is not a struct or hybrid type
qinsoon's avatar
qinsoon committed
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
    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
        }
    }

338
    /// gets the var part type of a hybrid type, returns None if the type is not a hybrid type
qinsoon's avatar
qinsoon committed
339
340
341
342
343
344
345
346
347
348
349
350
    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
        }
    }

351
352
353
    /// gets the referent type for Ref/IRef/WeakRef/UPtr, returns None if the type is
    /// not any mentioned type.
    pub fn get_referent_ty(&self) -> Option<P<MuType>> {
qinsoon's avatar
qinsoon committed
354
355
356
357
358
359
360
361
362
        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
363

364
365
    /// gets the length (in bit) of a integer/pointer type (assume pointer types are always 64 bits)
    // FIXME: should deprecate this function, and get the length from BackendType
qinsoon's avatar
qinsoon committed
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
    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
382
}
qinsoon's avatar
qinsoon committed
383

384
385
pub type StructTag = MuName;
pub type HybridTag = MuName;
386

387
/// MuType_ is used for pattern matching for MuType
388
#[derive(PartialEq, Debug)]
qinsoon's avatar
qinsoon committed
389
pub enum MuType_ {
qinsoon's avatar
qinsoon committed
390
    /// int <length>
qinsoon's avatar
qinsoon committed
391
    Int          (usize),
qinsoon's avatar
qinsoon committed
392
    /// float
qinsoon's avatar
qinsoon committed
393
    Float,
qinsoon's avatar
qinsoon committed
394
    /// double
qinsoon's avatar
qinsoon committed
395
    Double,
qinsoon's avatar
qinsoon committed
396

qinsoon's avatar
qinsoon committed
397
    /// ref<T>
qinsoon's avatar
qinsoon committed
398
    Ref          (P<MuType>),    // Box is needed for non-recursive enum
qinsoon's avatar
qinsoon committed
399
    /// iref<T>: internal reference
qinsoon's avatar
qinsoon committed
400
    IRef         (P<MuType>),
qinsoon's avatar
qinsoon committed
401
    /// weakref<T>
qinsoon's avatar
qinsoon committed
402
    WeakRef      (P<MuType>),
qinsoon's avatar
qinsoon committed
403

qinsoon's avatar
qinsoon committed
404
    /// uptr<T>: unsafe pointer
qinsoon's avatar
qinsoon committed
405
    UPtr         (P<MuType>),
qinsoon's avatar
qinsoon committed
406

qinsoon's avatar
qinsoon committed
407
    /// struct<T1 T2 ...>
408
    Struct       (StructTag),
qinsoon's avatar
qinsoon committed
409

qinsoon's avatar
qinsoon committed
410
    /// array<T length>
qinsoon's avatar
qinsoon committed
411
    Array        (P<MuType>, usize),
qinsoon's avatar
qinsoon committed
412

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

qinsoon's avatar
qinsoon committed
416
    /// void
qinsoon's avatar
qinsoon committed
417
    Void,
qinsoon's avatar
qinsoon committed
418

qinsoon's avatar
qinsoon committed
419
    /// threadref
qinsoon's avatar
qinsoon committed
420
    ThreadRef,
qinsoon's avatar
qinsoon committed
421
    /// stackref
qinsoon's avatar
qinsoon committed
422
    StackRef,
qinsoon's avatar
qinsoon committed
423

qinsoon's avatar
qinsoon committed
424
    /// tagref64: hold a double or an int or an ref<void>
qinsoon's avatar
qinsoon committed
425
    Tagref64,
qinsoon's avatar
qinsoon committed
426

qinsoon's avatar
qinsoon committed
427
    /// vector<T length>
qinsoon's avatar
qinsoon committed
428
    Vector       (P<MuType>, usize),
qinsoon's avatar
qinsoon committed
429

qinsoon's avatar
qinsoon committed
430
    /// funcref<@sig>
431
    FuncRef      (P<MuFuncSig>),
qinsoon's avatar
qinsoon committed
432

qinsoon's avatar
qinsoon committed
433
    /// ufuncptr<@sig>
434
    UFuncPtr     (P<MuFuncSig>),
qinsoon's avatar
qinsoon committed
435
436
}

437
438
439
440
rodal_enum!(MuType_{(Int: size), Float, Double, (Ref: ty), (IRef: ty), (WeakRef: ty), (UPtr: ty),
    (Struct: tag), (Array: ty, size), (Hybrid: tag), Void, ThreadRef, StackRef, Tagref64,
    (Vector: ty, size), (FuncRef: ty), (UFuncPtr: ty)});

qinsoon's avatar
qinsoon committed
441
442
443
444
445
446
impl fmt::Display for MuType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.v)        
    }
}

447
impl fmt::Display for MuType_ {
448
449
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
qinsoon's avatar
qinsoon committed
450
451
452
            &MuType_::Int(n)                          => write!(f, "int<{}>", n),
            &MuType_::Float                           => write!(f, "float"),
            &MuType_::Double                          => write!(f, "double"),
453
454
455
456
457
            &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
458
459
460
461
            &MuType_::Void                            => write!(f, "void"),
            &MuType_::ThreadRef                       => write!(f, "threadref"),
            &MuType_::StackRef                        => write!(f, "stackref"),
            &MuType_::Tagref64                        => write!(f, "tagref64"),
462
463
464
            &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),
465
466
            &MuType_::Struct(ref tag)                 => write!(f, "{}(struct)", tag),
            &MuType_::Hybrid(ref tag)                 => write!(f, "{}(hybrid)", tag)
467
468
469
470
        }
    }
}

qinsoon's avatar
qinsoon committed
471
lazy_static! {
qinsoon's avatar
qinsoon committed
472
    /// storing a map from MuName to StructType_
473
474
    pub static ref STRUCT_TAG_MAP : RwLock<HashMap<StructTag, StructType_>> =
        rodal::try_load_asm_name_move("STRUCT_TAG_MAP").unwrap_or(RwLock::new(HashMap::new()));
475
    /// storing a map from MuName to HybridType_
476
477
    pub static ref HYBRID_TAG_MAP : RwLock<HashMap<HybridTag, HybridType_>> =
        rodal::try_load_asm_name_move("HYBRID_TAG_MAP").unwrap_or(RwLock::new(HashMap::new()));
qinsoon's avatar
qinsoon committed
478
479
}

480
481
rodal_struct!(StructType_{tys});
#[derive(PartialEq, Debug)]
qinsoon's avatar
qinsoon committed
482
pub struct StructType_ {
qinsoon's avatar
qinsoon committed
483
    tys: Vec<P<MuType>>
qinsoon's avatar
qinsoon committed
484
485
}

486
impl fmt::Display for StructType_ {
487
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
qinsoon's avatar
qinsoon committed
488
489
490
        write!(f, "struct<").unwrap();
        for i in 0..self.tys.len() {
            let ty = &self.tys[i];
491
            write!(f, "{}", ty).unwrap();
qinsoon's avatar
qinsoon committed
492
493
494
            if i != self.tys.len() - 1 {
                write!(f, " ").unwrap();
            }
495
        }
qinsoon's avatar
qinsoon committed
496
        write!(f, ">")
qinsoon's avatar
qinsoon committed
497
    }
498
499
}

qinsoon's avatar
qinsoon committed
500
impl StructType_ {
501
502
503
504
    // 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
505
    pub fn set_tys(&mut self, mut list: Vec<P<MuType>>) {
qinsoon's avatar
qinsoon committed
506
        self.tys.clear();
qinsoon's avatar
qinsoon committed
507
        self.tys.append(&mut list);
qinsoon's avatar
qinsoon committed
508
    }
qinsoon's avatar
qinsoon committed
509
    
qinsoon's avatar
qinsoon committed
510
    pub fn get_tys(&self) -> &Vec<P<MuType>> {
qinsoon's avatar
qinsoon committed
511
512
        &self.tys
    }
qinsoon's avatar
qinsoon committed
513
514
}

515
516
rodal_struct!(HybridType_{fix_tys, var_ty});
#[derive(PartialEq, Debug)]
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
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
557
558
559
impl MuType_ {
    pub fn int(len: usize) -> MuType_ {
        MuType_::Int(len)
qinsoon's avatar
qinsoon committed
560
    }
qinsoon's avatar
qinsoon committed
561
562
    pub fn float() -> MuType_ {
        MuType_::Float
qinsoon's avatar
qinsoon committed
563
    }
qinsoon's avatar
qinsoon committed
564
565
    pub fn double() -> MuType_ {
        MuType_::Double
qinsoon's avatar
qinsoon committed
566
    }
qinsoon's avatar
qinsoon committed
567
    pub fn muref(referent: P<MuType>) -> MuType_ {
qinsoon's avatar
qinsoon committed
568
        MuType_::Ref(referent)
qinsoon's avatar
qinsoon committed
569
    }
qinsoon's avatar
qinsoon committed
570
    pub fn iref(referent: P<MuType>) -> MuType_ {
qinsoon's avatar
qinsoon committed
571
        MuType_::IRef(referent)
qinsoon's avatar
qinsoon committed
572
    }
qinsoon's avatar
qinsoon committed
573
    pub fn weakref(referent: P<MuType>) -> MuType_ {
qinsoon's avatar
qinsoon committed
574
        MuType_::WeakRef(referent)
qinsoon's avatar
qinsoon committed
575
    }
qinsoon's avatar
qinsoon committed
576
    pub fn uptr(referent: P<MuType>) -> MuType_ {
qinsoon's avatar
qinsoon committed
577
        MuType_::UPtr(referent)
qinsoon's avatar
qinsoon committed
578
    }
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
    pub fn array(ty: P<MuType>, len: usize) -> MuType_ {
        MuType_::Array(ty, len)
    }
    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<MuType>, len: usize) -> MuType_ {
        MuType_::Vector(ty, len)
    }
    pub fn funcref(sig: P<MuFuncSig>) -> MuType_ {
        MuType_::FuncRef(sig)
    }
    pub fn ufuncptr(sig: P<MuFuncSig>) -> MuType_ {
        MuType_::UFuncPtr(sig)
    }

    /// creates an empty struct type with a tag (we can later put types into the struct)
    /// This is used to create a recursive struct type, e.g. T = struct { ref<T> }
qinsoon's avatar
qinsoon committed
606
    pub fn mustruct_empty(tag: MuName) -> MuType_ {
qinsoon's avatar
qinsoon committed
607
        let struct_ty_ = StructType_{tys: vec![]};
608
        STRUCT_TAG_MAP.write().unwrap().insert(tag.clone(), struct_ty_);
qinsoon's avatar
qinsoon committed
609

qinsoon's avatar
qinsoon committed
610
        MuType_::Struct(tag)
qinsoon's avatar
qinsoon committed
611
    }
612
613
614
    /// puts types into an empty struct (created by mustruct_empty())
    /// This method will clear existing types declared with the tag, and set struct to the specified types
    /// This method panics if the tag does not exist
615
    pub fn mustruct_put(tag: &MuName, mut list: Vec<P<MuType>>) {
616
617
        let mut map_guard = STRUCT_TAG_MAP.write().unwrap();

618
        match map_guard.get_mut(tag) {
619
620
621
622
623
624
625
            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()")
        }
    }
626
    /// creates a Mu struct with specified field types
627
    pub fn mustruct(tag: StructTag, list: Vec<P<MuType>>) -> MuType_ {
qinsoon's avatar
qinsoon committed
628
        let struct_ty_ = StructType_{tys: list};
qinsoon's avatar
qinsoon committed
629
630
631

        // if there is an attempt to use a same tag for different struct,
        // we panic
632
        match STRUCT_TAG_MAP.read().unwrap().get(&tag) {
qinsoon's avatar
qinsoon committed
633
634
            Some(old_struct_ty_) => {
                if struct_ty_ != *old_struct_ty_ {
635
636
                    panic!("trying to insert {} as {}, while the old struct is defined as {}",
                            struct_ty_, tag, old_struct_ty_)
qinsoon's avatar
qinsoon committed
637
638
639
640
641
                }
            },
            None => {}
        }
        // otherwise, store the tag
642
        STRUCT_TAG_MAP.write().unwrap().insert(tag.clone(), struct_ty_);
qinsoon's avatar
qinsoon committed
643

qinsoon's avatar
qinsoon committed
644
        MuType_::Struct(tag)
qinsoon's avatar
qinsoon committed
645
    }
646
647
648

    /// creates an empty hybrid type with a tag (we can later put types into the hybrid)
    /// This is used to create a recursive hybrid type, e.g. T = hybrid { ref<T>, ... | ref<T> }
649
650
651
652
653
654
    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)
    }
655
656
657
    /// puts types into an empty hybrid (created by muhybrid_empty())
    /// This method will clear existing types declared with the tag, and set hybrid to the specified types
    /// This method panics if the tag does not exist
658
    pub fn hybrid_put(tag: &HybridTag, mut fix_tys: Vec<P<MuType>>, var_ty: P<MuType>) {
qinsoon's avatar
qinsoon committed
659
660
        let mut map_guard = HYBRID_TAG_MAP.write().unwrap();

661
        match map_guard.get_mut(tag) {
qinsoon's avatar
qinsoon committed
662
663
664
665
666
667
668
669
670
            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()")
        }
    }
671
    /// creates a Mu hybrid with specified fix part and var part types
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
    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
689
    }
qinsoon's avatar
qinsoon committed
690
691
}

692
/// MuFuncSig represents a Mu function signature
693
#[derive(PartialEq, Debug)]
qinsoon's avatar
qinsoon committed
694
pub struct MuFuncSig {
695
    pub hdr: MuEntityHeader,
qinsoon's avatar
qinsoon committed
696
697
    pub ret_tys : Vec<P<MuType>>,
    pub arg_tys: Vec<P<MuType>>
698
699
}

700
701
rodal_struct!(MuFuncSig{hdr, ret_tys, arg_tys});

702
impl fmt::Display for MuFuncSig {
703
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
qinsoon's avatar
qinsoon committed
704
        write!(f, "[{}] -> [{}]", vec_utils::as_str(&self.arg_tys), vec_utils::as_str(&self.ret_tys))
qinsoon's avatar
qinsoon committed
705
706
    }
}
707

708
pub type CFuncSig = MuFuncSig;