WARNING! Access to this system is limited to authorised users only.
Unauthorised users may be subject to prosecution.
Unauthorised access to this system is a criminal offence under Australian law (Federal Crimes Act 1914 Part VIA)
It is a criminal offence to:
(1) Obtain access to data without authority. -Penalty 2 years imprisonment.
(2) Damage, delete, alter or insert data without authority. -Penalty 10 years imprisonment.
User activity is monitored and recorded. Anyone using this system expressly consents to such monitoring and recording.

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 21.9 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

qinsoon's avatar
qinsoon committed
45
46
47
    pub static ref UINT32_TYPE : P<MuType> = P(
        MuType::new(new_internal_id(), MuType_::int(32))
    );
qinsoon's avatar
qinsoon committed
48

qinsoon's avatar
qinsoon committed
49
50
51
    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,
111
    pub v: MuType_
qinsoon's avatar
qinsoon committed
112
113
}

qinsoon's avatar
qinsoon committed
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),
121
            v: v
qinsoon's avatar
qinsoon committed
122
123
        }
    }
qinsoon's avatar
qinsoon committed
124

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

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

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,
153
            _ => false
qinsoon's avatar
qinsoon committed
154
155
156
        }
    }

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
            _ => false
162
163
164
        }
    }

165
166
    /// is this type a scalar type?
    pub fn is_scalar(&self) -> bool {
167
        match self.v {
qinsoon's avatar
qinsoon committed
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
            _ => false
181
182
183
        }
    }

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
            MuType_::Hybrid(ref name) | MuType_::Struct(ref name) => Some(name.clone()),
189
            _ => None
190
191
192
        }
    }

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

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

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

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

226
227
228
    /// is this type an aggregated type? (consisted of other types)
    pub fn is_aggregate(&self) -> bool {
        match self.v {
qinsoon's avatar
qinsoon committed
229
            MuType_::Struct(_) | MuType_::Hybrid(_) | MuType_::Array(_, _) => true,
230
            _ => false
231
232
233
        }
    }

234
    /// is this type a type traced by the garbage collector?
235
    /// Note: An aggregated type is traced if any of its part is traced.
236
    #[allow(dead_code)]
237
238
239
    pub fn is_traced(&self) -> bool {
        match self.v {
            MuType_::Ref(_) => true,
qinsoon's avatar
qinsoon committed
240
            MuType_::IRef(_) => true,
241
            MuType_::WeakRef(_) => true,
qinsoon's avatar
qinsoon committed
242
243
            MuType_::Array(ref elem_ty, _) | MuType_::Vector(ref elem_ty, _) => elem_ty.is_traced(),
            MuType_::ThreadRef | MuType_::StackRef | MuType_::Tagref64 => true,
244
245
246
247
248
            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;
qinsoon's avatar
qinsoon committed
249
                let ref var_ty = hybrid_ty.var_ty;
250

qinsoon's avatar
qinsoon committed
251
252
253
254
                var_ty.is_traced() ||
                    fix_tys
                        .into_iter()
                        .map(|ty| ty.is_traced())
255
                        .fold(false, |ret, this| ret || this)
qinsoon's avatar
qinsoon committed
256
            }
257
258
259
260
261
            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;

qinsoon's avatar
qinsoon committed
262
263
264
                field_tys
                    .into_iter()
                    .map(|ty| ty.is_traced())
265
                    .fold(false, |ret, this| ret || this)
qinsoon's avatar
qinsoon committed
266
            }
267
            _ => false
268
269
270
        }
    }

271
    /// is this type native safe?
272
    /// Note: An aggregated type is native safe if all of its parts are native safe.
273
    #[allow(dead_code)]
274
275
276
277
278
279
    pub fn is_native_safe(&self) -> bool {
        match self.v {
            MuType_::Int(_) => true,
            MuType_::Float => true,
            MuType_::Double => true,
            MuType_::Void => true,
qinsoon's avatar
qinsoon committed
280
281
282
            MuType_::Array(ref elem_ty, _) | MuType_::Vector(ref elem_ty, _) => {
                elem_ty.is_native_safe()
            }
283
284
285
286
287
288
289
            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;
qinsoon's avatar
qinsoon committed
290
                let ref var_ty = hybrid_ty.var_ty;
291

qinsoon's avatar
qinsoon committed
292
293
294
295
                var_ty.is_native_safe() &&
                    fix_tys
                        .into_iter()
                        .map(|ty| ty.is_native_safe())
296
                        .fold(true, |ret, this| ret && this)
qinsoon's avatar
qinsoon committed
297
            }
298
299
300
301
302
            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;

qinsoon's avatar
qinsoon committed
303
304
305
                field_tys
                    .into_iter()
                    .map(|ty| ty.is_native_safe())
306
                    .fold(true, |ret, this| ret && this)
qinsoon's avatar
qinsoon committed
307
            }
308
            _ => false
qinsoon's avatar
qinsoon committed
309
310
311
        }
    }

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

qinsoon's avatar
qinsoon committed
320
321
    /// 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
322
323
324
325
326
327
328
    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())
qinsoon's avatar
qinsoon committed
329
            }
qinsoon's avatar
qinsoon committed
330
331
332
333
334
            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())
qinsoon's avatar
qinsoon committed
335
            }
336
            _ => None
qinsoon's avatar
qinsoon committed
337
338
339
        }
    }

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

353
354
355
    /// 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
356
357
        use types::MuType_::*;
        match self.v {
qinsoon's avatar
qinsoon committed
358
            Ref(ref ty) | IRef(ref ty) | WeakRef(ref ty) | UPtr(ref ty) => Some(ty.clone()),
359
            _ => None
qinsoon's avatar
qinsoon committed
360
361
        }
    }
qinsoon's avatar
qinsoon committed
362

363
364
    /// 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
365
366
367
368
    pub fn get_int_length(&self) -> Option<usize> {
        use types::MuType_::*;
        match self.v {
            Int(len) => Some(len),
qinsoon's avatar
qinsoon committed
369
370
371
372
373
374
375
376
377
            Ref(_) |
            IRef(_) |
            WeakRef(_) |
            UPtr(_) |
            ThreadRef |
            StackRef |
            Tagref64 |
            FuncRef(_) |
            UFuncPtr(_) => Some(64),
378
            _ => None
qinsoon's avatar
qinsoon committed
379
380
        }
    }
qinsoon's avatar
qinsoon committed
381
}
qinsoon's avatar
qinsoon committed
382

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

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

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

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

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

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

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

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

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

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

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

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

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

436
437
438
439
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
440
441
impl fmt::Display for MuType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
qinsoon's avatar
qinsoon committed
442
        write!(f, "{}", self.v)
qinsoon's avatar
qinsoon committed
443
444
445
    }
}

446
impl fmt::Display for MuType_ {
447
448
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
qinsoon's avatar
qinsoon committed
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
            &MuType_::Int(n) => write!(f, "int<{}>", n),
            &MuType_::Float => write!(f, "float"),
            &MuType_::Double => write!(f, "double"),
            &MuType_::Ref(ref ty) => write!(f, "ref<{}>", ty),
            &MuType_::IRef(ref ty) => write!(f, "iref<{}>", ty),
            &MuType_::WeakRef(ref ty) => write!(f, "weakref<{}>", ty),
            &MuType_::UPtr(ref ty) => write!(f, "uptr<{}>", ty),
            &MuType_::Array(ref ty, size) => write!(f, "array<{} {}>", ty, size),
            &MuType_::Void => write!(f, "void"),
            &MuType_::ThreadRef => write!(f, "threadref"),
            &MuType_::StackRef => write!(f, "stackref"),
            &MuType_::Tagref64 => write!(f, "tagref64"),
            &MuType_::Vector(ref ty, size) => write!(f, "vector<{} {}>", ty, size),
            &MuType_::FuncRef(ref sig) => write!(f, "funcref<{}>", sig),
            &MuType_::UFuncPtr(ref sig) => write!(f, "ufuncref<{}>", sig),
            &MuType_::Struct(ref tag) => write!(f, "{}(struct)", tag),
465
            &MuType_::Hybrid(ref tag) => write!(f, "{}(hybrid)", tag)
466
467
468
469
        }
    }
}

qinsoon's avatar
qinsoon committed
470
lazy_static! {
qinsoon's avatar
qinsoon committed
471
    /// storing a map from MuName to StructType_
472
473
    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()));
474
    /// storing a map from MuName to HybridType_
475
476
    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
477
478
}

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

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

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

qinsoon's avatar
qinsoon committed
509
    pub fn get_tys(&self) -> &Vec<P<MuType>> {
qinsoon's avatar
qinsoon committed
510
511
        &self.tys
    }
qinsoon's avatar
qinsoon committed
512
513
}

514
515
rodal_struct!(HybridType_{fix_tys, var_ty});
#[derive(PartialEq, Debug)]
516
517
pub struct HybridType_ {
    fix_tys: Vec<P<MuType>>,
518
    var_ty: P<MuType>
519
520
521
522
}

impl HybridType_ {
    pub fn new(fix_tys: Vec<P<MuType>>, var_ty: P<MuType>) -> HybridType_ {
qinsoon's avatar
qinsoon committed
523
524
        HybridType_ {
            fix_tys: fix_tys,
525
            var_ty: var_ty
qinsoon's avatar
qinsoon committed
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
557
558
    }

    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
559
560
561
impl MuType_ {
    pub fn int(len: usize) -> MuType_ {
        MuType_::Int(len)
qinsoon's avatar
qinsoon committed
562
    }
qinsoon's avatar
qinsoon committed
563
564
    pub fn float() -> MuType_ {
        MuType_::Float
qinsoon's avatar
qinsoon committed
565
    }
qinsoon's avatar
qinsoon committed
566
567
    pub fn double() -> MuType_ {
        MuType_::Double
qinsoon's avatar
qinsoon committed
568
    }
qinsoon's avatar
qinsoon committed
569
    pub fn muref(referent: P<MuType>) -> MuType_ {
qinsoon's avatar
qinsoon committed
570
        MuType_::Ref(referent)
qinsoon's avatar
qinsoon committed
571
    }
qinsoon's avatar
qinsoon committed
572
    pub fn iref(referent: P<MuType>) -> MuType_ {
qinsoon's avatar
qinsoon committed
573
        MuType_::IRef(referent)
qinsoon's avatar
qinsoon committed
574
    }
qinsoon's avatar
qinsoon committed
575
    pub fn weakref(referent: P<MuType>) -> MuType_ {
qinsoon's avatar
qinsoon committed
576
        MuType_::WeakRef(referent)
qinsoon's avatar
qinsoon committed
577
    }
qinsoon's avatar
qinsoon committed
578
    pub fn uptr(referent: P<MuType>) -> MuType_ {
qinsoon's avatar
qinsoon committed
579
        MuType_::UPtr(referent)
qinsoon's avatar
qinsoon committed
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
606
607
    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
608
    pub fn mustruct_empty(tag: MuName) -> MuType_ {
qinsoon's avatar
qinsoon committed
609
610
611
612
613
        let struct_ty_ = StructType_ { tys: vec![] };
        STRUCT_TAG_MAP
            .write()
            .unwrap()
            .insert(tag.clone(), struct_ty_);
qinsoon's avatar
qinsoon committed
614

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

624
        match map_guard.get_mut(tag) {
625
626
627
            Some(struct_ty_) => {
                struct_ty_.tys.clear();
                struct_ty_.tys.append(&mut list);
qinsoon's avatar
qinsoon committed
628
            }
629
            None => panic!("call mustruct_empty() to create an empty struct before mustruct_put()")
630
631
        }
    }
632
    /// creates a Mu struct with specified field types
633
    pub fn mustruct(tag: StructTag, list: Vec<P<MuType>>) -> MuType_ {
qinsoon's avatar
qinsoon committed
634
        let struct_ty_ = StructType_ { tys: list };
qinsoon's avatar
qinsoon committed
635
636
637

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

qinsoon's avatar
qinsoon committed
653
        MuType_::Struct(tag)
qinsoon's avatar
qinsoon committed
654
    }
655
656
657

    /// 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> }
658
    pub fn hybrid_empty(tag: HybridTag) -> MuType_ {
qinsoon's avatar
qinsoon committed
659
660
        let hybrid_ty_ = HybridType_ {
            fix_tys: vec![],
661
            var_ty: VOID_TYPE.clone()
qinsoon's avatar
qinsoon committed
662
663
664
665
666
        };
        HYBRID_TAG_MAP
            .write()
            .unwrap()
            .insert(tag.clone(), hybrid_ty_);
667
668
669

        MuType_::Hybrid(tag)
    }
qinsoon's avatar
qinsoon committed
670

671
    /// puts types into an empty hybrid (created by muhybrid_empty())
qinsoon's avatar
qinsoon committed
672
673
    /// This method will clear existing types declared with the tag,
    /// and set hybrid to the specified types
674
    /// This method panics if the tag does not exist
675
    pub fn hybrid_put(tag: &HybridTag, mut fix_tys: Vec<P<MuType>>, var_ty: P<MuType>) {
qinsoon's avatar
qinsoon committed
676
677
        let mut map_guard = HYBRID_TAG_MAP.write().unwrap();

678
        match map_guard.get_mut(tag) {
qinsoon's avatar
qinsoon committed
679
680
681
682
683
            Some(hybrid_ty_) => {
                hybrid_ty_.fix_tys.clear();
                hybrid_ty_.fix_tys.append(&mut fix_tys);

                hybrid_ty_.var_ty = var_ty;
qinsoon's avatar
qinsoon committed
684
            }
685
            None => panic!("call hybrid_empty() to create an empty struct before hybrid_put()")
qinsoon's avatar
qinsoon committed
686
687
        }
    }
688
    /// creates a Mu hybrid with specified fix part and var part types
689
    pub fn hybrid(tag: HybridTag, fix_tys: Vec<P<MuType>>, var_ty: P<MuType>) -> MuType_ {
qinsoon's avatar
qinsoon committed
690
691
        let hybrid_ty_ = HybridType_ {
            fix_tys: fix_tys,
692
            var_ty: var_ty
qinsoon's avatar
qinsoon committed
693
        };
694
695
696
697
698
699
700
701


        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_);
                }
qinsoon's avatar
qinsoon committed
702
            }
703
704
705
            None => {}
        }

qinsoon's avatar
qinsoon committed
706
707
708
709
        HYBRID_TAG_MAP
            .write()
            .unwrap()
            .insert(tag.clone(), hybrid_ty_);
710
711

        MuType_::Hybrid(tag)
qinsoon's avatar
qinsoon committed
712
    }
qinsoon's avatar
qinsoon committed
713
714
}

715
/// MuFuncSig represents a Mu function signature
716
#[derive(PartialEq, Debug)]
qinsoon's avatar
qinsoon committed
717
pub struct MuFuncSig {
718
    pub hdr: MuEntityHeader,
qinsoon's avatar
qinsoon committed
719
    pub ret_tys: Vec<P<MuType>>,
720
    pub arg_tys: Vec<P<MuType>>
721
722
}

723
724
rodal_struct!(MuFuncSig{hdr, ret_tys, arg_tys});

725
impl fmt::Display for MuFuncSig {
726
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
qinsoon's avatar
qinsoon committed
727
728
        write!(f, "[{}] -> [{}]",
               vec_utils::as_str(&self.arg_tys), vec_utils::as_str(&self.ret_tys))
qinsoon's avatar
qinsoon committed
729
730
    }
}
731

732
pub type CFuncSig = MuFuncSig;