types.rs 26 KB
Newer Older
1
// Copyright 2017 The Australian National University
2
//
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
//
7
//     http://www.apache.org/licenses/LICENSE-2.0
8
//
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.

15
use ir::*;
16
use ptr::P;
17 18

use utils::vec_utils;
19
use utils::POINTER_SIZE;
20

21 22
use std;
use std::collections::HashMap;
23 24 25
use std::fmt;
use std::ptr;
use std::sync::atomic::{AtomicPtr, Ordering};
qinsoon's avatar
qinsoon committed
26
use std::sync::RwLock;
qinsoon's avatar
qinsoon committed
27

28
// some common types that the compiler may use internally
qinsoon's avatar
qinsoon committed
29
lazy_static! {
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
    pub static ref ADDRESS_TYPE: P<MuType> = P(MuType::new(
        new_internal_id(),
        MuType_::int(POINTER_SIZE * 8)
    ));
    pub static ref UINT1_TYPE: P<MuType> = P(MuType::new(new_internal_id(), MuType_::int(1)));
    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)));
    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 UINT128_TYPE: P<MuType> = P(MuType::new(new_internal_id(), MuType_::int(128)));
    pub static ref FLOAT_TYPE: P<MuType> = P(MuType::new(new_internal_id(), MuType_::float()));
    pub static ref DOUBLE_TYPE: P<MuType> = P(MuType::new(new_internal_id(), MuType_::double()));
    pub static ref VOID_TYPE: P<MuType> = P(MuType::new(new_internal_id(), MuType_::void()));
    pub static ref REF_VOID_TYPE: P<MuType> = P(MuType::new(
        new_internal_id(),
        MuType_::muref(VOID_TYPE.clone())
    ));
    pub static ref IREF_VOID_TYPE: P<MuType> = P(MuType::new(
        new_internal_id(),
        MuType_::iref(VOID_TYPE.clone())
    ));
    pub static ref UPTR_U8_TYPE: P<MuType> = P(MuType::new(
        new_internal_id(),
        MuType_::uptr(UINT8_TYPE.clone())
    ));
    pub static ref UPTR_U64_TYPE: P<MuType> = P(MuType::new(
        new_internal_id(),
        MuType_::uptr(UINT64_TYPE.clone())
    ));
    pub static ref STACKREF_TYPE: P<MuType> = P(MuType::new(new_internal_id(), MuType_::StackRef));
    pub static ref THREADREF_TYPE: P<MuType> =
        P(MuType::new(new_internal_id(), MuType_::ThreadRef));
    pub static ref INTERNAL_TYPES: Vec<P<MuType>> = vec![
qinsoon's avatar
qinsoon committed
63
        ADDRESS_TYPE.clone(),
64
        UINT1_TYPE.clone(),
qinsoon's avatar
qinsoon committed
65 66
        UINT8_TYPE.clone(),
        UINT16_TYPE.clone(),
qinsoon's avatar
qinsoon committed
67 68
        UINT32_TYPE.clone(),
        UINT64_TYPE.clone(),
69 70
        UINT128_TYPE.clone(),
        FLOAT_TYPE.clone(),
qinsoon's avatar
qinsoon committed
71
        DOUBLE_TYPE.clone(),
72
        FLOAT_TYPE.clone(),
73 74
        VOID_TYPE.clone(),
        REF_VOID_TYPE.clone(),
75
        IREF_VOID_TYPE.clone(),
76 77
        STACKREF_TYPE.clone(),
        THREADREF_TYPE.clone(),
qinsoon's avatar
qinsoon committed
78 79
        UPTR_U8_TYPE.clone(),
        UPTR_U64_TYPE.clone()
80
    ];
qinsoon's avatar
qinsoon committed
81 82
}

83
/// clear struct/hybrid maps, called when creating new VM
84 85 86 87 88 89 90 91 92 93 94 95
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();
    }
}

96
/// MuType represents a Mu type
97
#[derive(Debug)]
qinsoon's avatar
qinsoon committed
98
pub struct MuType {
99
    pub hdr: MuEntityHeader,
100
    pub v: MuType_,
qinsoon's avatar
qinsoon committed
101 102
}

qinsoon's avatar
qinsoon committed
103
rodal_struct!(MuType { hdr, v });
104

105
impl PartialEq for MuType {
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
106 107 108 109 110 111
    fn eq(&self, other: &MuType) -> bool {
        self.v == other.v
    }
    fn ne(&self, other: &MuType) -> bool {
        self.v != other.v
    }
112 113
}

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

123 124 125
    pub fn is_tagref64(&self) -> bool {
        match self.v {
            MuType_::Tagref64 => true,
126
            _ => false,
127 128
        }
    }
129 130 131 132

    pub fn is_stackref(&self) -> bool {
        match self.v {
            MuType_::StackRef => true,
133
            _ => false,
134 135 136
        }
    }

137 138
    pub fn is_funcref(&self) -> bool {
        match self.v {
qinsoon's avatar
qinsoon committed
139
            MuType_::FuncRef(_) => true,
140
            _ => false,
141 142 143
        }
    }

144
    /// is this type struct type?
qinsoon's avatar
qinsoon committed
145 146 147
    pub fn is_struct(&self) -> bool {
        match self.v {
            MuType_::Struct(_) => true,
148
            _ => false,
qinsoon's avatar
qinsoon committed
149 150 151
        }
    }

152 153 154
    pub fn is_void(&self) -> bool {
        match self.v {
            MuType_::Void => true,
155
            _ => false,
156 157 158
        }
    }

159
    /// is this type hybrid type?
qinsoon's avatar
qinsoon committed
160 161 162
    pub fn is_hybrid(&self) -> bool {
        match self.v {
            MuType_::Hybrid(_) => true,
163
            _ => false,
qinsoon's avatar
qinsoon committed
164 165 166
        }
    }

qinsoon's avatar
qinsoon committed
167 168 169 170
    /// is this type an integer type?
    pub fn is_int(&self) -> bool {
        match self.v {
            MuType_::Int(_) => true,
171
            _ => false,
qinsoon's avatar
qinsoon committed
172 173 174
        }
    }

175 176 177 178 179 180 181 182 183
    /// is this type an integer type of certain width
    pub fn is_int_n(&self, n: usize) -> bool {
        if let Some(width) = self.get_int_length() {
            width == n
        } else {
            false
        }
    }

184 185
    /// is this type a floating point type? (float/double)
    pub fn is_fp(&self) -> bool {
qinsoon's avatar
qinsoon committed
186
        match self.v {
187
            MuType_::Float | MuType_::Double => true,
188
            _ => false,
qinsoon's avatar
qinsoon committed
189 190 191
        }
    }

192 193 194
    pub fn is_opaque_reference(&self) -> bool {
        match self.v {
            MuType_::FuncRef(_) | MuType_::StackRef | MuType_::ThreadRef => true,
195
            _ => false,
196 197 198 199
        }
    }

    pub fn is_eq_comparable(&self) -> bool {
200 201 202 203 204
        self.is_int()
            || self.is_ptr()
            || self.is_iref()
            || self.is_ref()
            || self.is_opaque_reference()
205 206 207 208 209 210
    }

    pub fn is_ult_comparable(&self) -> bool {
        self.is_int() || self.is_ptr() || self.is_iref()
    }

211 212
    /// is this type a float type (single-precision floating point)
    pub fn is_float(&self) -> bool {
qinsoon's avatar
qinsoon committed
213
        match self.v {
214
            MuType_::Float => true,
215
            _ => false,
qinsoon's avatar
qinsoon committed
216 217 218
        }
    }

219 220
    /// is this type a double type (double-precision floating point)
    pub fn is_double(&self) -> bool {
221
        match self.v {
222
            MuType_::Double => true,
223
            _ => false,
224 225 226
        }
    }

227 228
    /// is this type a scalar type?
    pub fn is_scalar(&self) -> bool {
229
        match self.v {
230 231 232 233 234 235 236 237 238 239 240 241 242
            MuType_::Int(_)
            | MuType_::Float
            | MuType_::Double
            | MuType_::Ref(_)
            | MuType_::IRef(_)
            | MuType_::WeakRef(_)
            | MuType_::FuncRef(_)
            | MuType_::UFuncPtr(_)
            | MuType_::ThreadRef
            | MuType_::StackRef
            | MuType_::Tagref64
            | MuType_::UPtr(_) => true,
            _ => false,
243 244 245
        }
    }

246 247
    /// 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
248
    pub fn get_struct_hybrid_tag(&self) -> Option<MuName> {
249
        match self.v {
qinsoon's avatar
qinsoon committed
250
            MuType_::Hybrid(ref name) | MuType_::Struct(ref name) => Some(name.clone()),
251
            _ => None,
252 253 254
        }
    }

255 256
    /// is this type a reference type?
    /// (only reference type, which does not include iref, or other opaque reference types)
qinsoon's avatar
qinsoon committed
257 258 259
    pub fn is_ref(&self) -> bool {
        match self.v {
            MuType_::Ref(_) => true,
260
            _ => false,
261 262 263
        }
    }

264 265
    /// is this type any reference type pointing to the heap? (including ref/iref/weakref)
    pub fn is_heap_reference(&self) -> bool {
266
        match self.v {
qinsoon's avatar
qinsoon committed
267
            MuType_::Ref(_) | MuType_::IRef(_) | MuType_::WeakRef(_) => true,
268
            _ => false,
269 270 271
        }
    }

272
    /// is this type an internal reference type?
qinsoon's avatar
qinsoon committed
273
    pub fn is_iref(&self) -> bool {
274
        match self.v {
qinsoon's avatar
qinsoon committed
275
            MuType_::IRef(_) => true,
276
            _ => false,
277 278 279
        }
    }

280 281
    /// is a type raw pointer?
    pub fn is_ptr(&self) -> bool {
282
        match self.v {
283
            MuType_::UPtr(_) | MuType_::UFuncPtr(_) => true,
284
            _ => false,
285 286 287
        }
    }

288 289 290
    /// is this type an aggregated type? (consisted of other types)
    pub fn is_aggregate(&self) -> bool {
        match self.v {
qinsoon's avatar
qinsoon committed
291
            MuType_::Struct(_) | MuType_::Hybrid(_) | MuType_::Array(_, _) => true,
292
            _ => false,
293 294 295
        }
    }

296
    /// is this type a type traced by the garbage collector?
297
    /// Note: An aggregated type is traced if any of its part is traced.
298
    #[allow(dead_code)]
299 300 301
    pub fn is_traced(&self) -> bool {
        match self.v {
            MuType_::Ref(_) => true,
qinsoon's avatar
qinsoon committed
302
            MuType_::IRef(_) => true,
303
            MuType_::WeakRef(_) => true,
qinsoon's avatar
qinsoon committed
304 305
            MuType_::Array(ref elem_ty, _) | MuType_::Vector(ref elem_ty, _) => elem_ty.is_traced(),
            MuType_::ThreadRef | MuType_::StackRef | MuType_::Tagref64 => true,
306 307 308 309 310
            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
311
                let ref var_ty = hybrid_ty.var_ty;
312

313 314
                var_ty.is_traced()
                    || fix_tys
qinsoon's avatar
qinsoon committed
315 316
                        .into_iter()
                        .map(|ty| ty.is_traced())
317
                        .fold(false, |ret, this| ret || this)
qinsoon's avatar
qinsoon committed
318
            }
319 320 321 322 323
            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
324 325 326
                field_tys
                    .into_iter()
                    .map(|ty| ty.is_traced())
327
                    .fold(false, |ret, this| ret || this)
qinsoon's avatar
qinsoon committed
328
            }
329
            _ => false,
330 331 332
        }
    }

333
    /// is this type native safe?
334
    /// Note: An aggregated type is native safe if all of its parts are native safe.
335
    #[allow(dead_code)]
336 337 338 339 340 341
    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
342 343 344
            MuType_::Array(ref elem_ty, _) | MuType_::Vector(ref elem_ty, _) => {
                elem_ty.is_native_safe()
            }
345 346 347 348 349 350 351
            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
352
                let ref var_ty = hybrid_ty.var_ty;
353

354 355
                var_ty.is_native_safe()
                    && fix_tys
qinsoon's avatar
qinsoon committed
356 357
                        .into_iter()
                        .map(|ty| ty.is_native_safe())
358
                        .fold(true, |ret, this| ret && this)
qinsoon's avatar
qinsoon committed
359
            }
360 361 362 363 364
            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
365 366 367
                field_tys
                    .into_iter()
                    .map(|ty| ty.is_native_safe())
368
                    .fold(true, |ret, this| ret && this)
qinsoon's avatar
qinsoon committed
369
            }
370
            _ => false,
qinsoon's avatar
qinsoon committed
371 372 373
        }
    }

374
    /// gets the element type of an array type, returns None if the type is not an array type
qinsoon's avatar
qinsoon committed
375 376 377
    pub fn get_elem_ty(&self) -> Option<P<MuType>> {
        match self.v {
            MuType_::Array(ref elem_ty, _) => Some(elem_ty.clone()),
378
            _ => None,
qinsoon's avatar
qinsoon committed
379 380 381
        }
    }

382 383 384
    /// gets the signature of a funcref or ufuncptr type
    pub fn get_sig(&self) -> Option<P<MuFuncSig>> {
        match self.v {
385
            MuType_::FuncRef(ref sig) | MuType_::UFuncPtr(ref sig) => Some(sig.clone()),
386
            _ => None,
387 388 389
        }
    }

qinsoon's avatar
qinsoon committed
390 391
    /// 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
392 393 394 395 396 397 398
    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
399
            }
qinsoon's avatar
qinsoon committed
400 401 402 403 404
            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
405
            }
406
            _ => None,
qinsoon's avatar
qinsoon committed
407 408 409
        }
    }

410
    /// gets the var part type of a hybrid type, returns None if the type is not a hybrid type
qinsoon's avatar
qinsoon committed
411 412 413 414 415 416 417
    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
418
            }
419
            _ => None,
qinsoon's avatar
qinsoon committed
420 421 422
        }
    }

423 424 425
    /// 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>> {
426 427
        use types::MuType_::*;
        match self.v {
qinsoon's avatar
qinsoon committed
428
            Ref(ref ty) | IRef(ref ty) | WeakRef(ref ty) | UPtr(ref ty) => Some(ty.clone()),
429
            _ => None,
430 431
        }
    }
432

433 434 435 436 437
    /// gets the function signature for FuncRef or UFuncPtr, return None if the type is not
    /// those two types
    pub fn get_func_sig(&self) -> Option<P<MuFuncSig>> {
        match self.v {
            MuType_::FuncRef(ref sig) | MuType_::UFuncPtr(ref sig) => Some(sig.clone()),
438
            _ => None,
439 440 441
        }
    }

442 443
    /// 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
444 445 446 447
    pub fn get_int_length(&self) -> Option<usize> {
        use types::MuType_::*;
        match self.v {
            Int(len) => Some(len),
448 449 450
            Ref(_) | IRef(_) | WeakRef(_) | UPtr(_) | ThreadRef | StackRef | Tagref64
            | FuncRef(_) | UFuncPtr(_) => Some(64),
            _ => None,
451 452
        }
    }
qinsoon's avatar
qinsoon committed
453 454 455 456 457 458 459 460 461 462 463 464

    /// prints a struct type
    pub fn print_details(&self) -> String {
        match self.v {
            MuType_::Struct(ref tag) => {
                let lock = STRUCT_TAG_MAP.read().unwrap();
                format!("{} = {}", tag, lock.get(tag).unwrap())
            }
            MuType_::Hybrid(ref tag) => {
                let lock = HYBRID_TAG_MAP.read().unwrap();
                format!("{} = {}", tag, lock.get(tag).unwrap())
            }
465
            _ => format!("{}", self),
qinsoon's avatar
qinsoon committed
466 467 468 469 470 471
        }
    }

    /// prints a struct type
    pub fn print_hybrid(&self) -> String {
        match self.v {
472
            _ => panic!(),
qinsoon's avatar
qinsoon committed
473 474
        }
    }
qinsoon's avatar
qinsoon committed
475
}
qinsoon's avatar
qinsoon committed
476

477 478
pub type StructTag = MuName;
pub type HybridTag = MuName;
479

480
/// MuType_ is used for pattern matching for MuType
481
#[derive(PartialEq, Debug, Clone)]
qinsoon's avatar
qinsoon committed
482
pub enum MuType_ {
qinsoon's avatar
qinsoon committed
483
    /// int <length>
qinsoon's avatar
qinsoon committed
484
    Int(usize),
qinsoon's avatar
qinsoon committed
485
    /// float
qinsoon's avatar
qinsoon committed
486
    Float,
qinsoon's avatar
qinsoon committed
487
    /// double
qinsoon's avatar
qinsoon committed
488
    Double,
489

qinsoon's avatar
qinsoon committed
490
    /// ref<T>
qinsoon's avatar
qinsoon committed
491
    Ref(P<MuType>), // Box is needed for non-recursive enum
qinsoon's avatar
qinsoon committed
492
    /// iref<T>: internal reference
qinsoon's avatar
qinsoon committed
493
    IRef(P<MuType>),
qinsoon's avatar
qinsoon committed
494
    /// weakref<T>
qinsoon's avatar
qinsoon committed
495
    WeakRef(P<MuType>),
496

qinsoon's avatar
qinsoon committed
497
    /// uptr<T>: unsafe pointer
qinsoon's avatar
qinsoon committed
498
    UPtr(P<MuType>),
499

qinsoon's avatar
qinsoon committed
500
    /// struct<T1 T2 ...>
qinsoon's avatar
qinsoon committed
501
    Struct(StructTag),
502

qinsoon's avatar
qinsoon committed
503
    /// array<T length>
qinsoon's avatar
qinsoon committed
504
    Array(P<MuType>, usize),
505

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

qinsoon's avatar
qinsoon committed
509
    /// void
qinsoon's avatar
qinsoon committed
510
    Void,
511

qinsoon's avatar
qinsoon committed
512
    /// threadref
qinsoon's avatar
qinsoon committed
513
    ThreadRef,
qinsoon's avatar
qinsoon committed
514
    /// stackref
qinsoon's avatar
qinsoon committed
515
    StackRef,
516

qinsoon's avatar
qinsoon committed
517
    /// tagref64: hold a double or an int or an ref<void>
qinsoon's avatar
qinsoon committed
518
    Tagref64,
519

qinsoon's avatar
qinsoon committed
520
    /// vector<T length>
qinsoon's avatar
qinsoon committed
521
    Vector(P<MuType>, usize),
522

qinsoon's avatar
qinsoon committed
523
    /// funcref<@sig>
qinsoon's avatar
qinsoon committed
524
    FuncRef(P<MuFuncSig>),
525

qinsoon's avatar
qinsoon committed
526
    /// ufuncptr<@sig>
527
    UFuncPtr(P<MuFuncSig>),
qinsoon's avatar
qinsoon committed
528
}
529 530 531 532
impl MuType_ {
    pub fn strong_variant(&self) -> MuType_ {
        match self {
            &MuType_::WeakRef(ref t) => MuType_::Ref(t.clone()),
533
            _ => self.clone(),
534 535 536
        }
    }
}
537 538 539 540
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
541 542
impl fmt::Display for MuType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
qinsoon's avatar
qinsoon committed
543
        write!(f, "{}", self.v)
qinsoon's avatar
qinsoon committed
544 545 546
    }
}

547
impl fmt::Display for MuType_ {
548 549
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
qinsoon's avatar
qinsoon committed
550 551 552 553 554 555 556 557 558 559 560 561 562 563
            &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),
564 565
            &MuType_::UFuncPtr(ref sig) => write!(f, "ufuncptr<{}>", sig),
            &MuType_::Struct(ref tag) => write!(f, "{}", tag),
566
            &MuType_::Hybrid(ref tag) => write!(f, "{}", tag),
567 568 569 570
        }
    }
}

571 572 573 574 575
#[no_mangle]
pub static STRUCT_TAG_MAP_LOC: Option<AtomicPtr<RwLock<HashMap<StructTag, StructType_>>>> = None;
#[no_mangle]
pub static HYBRID_TAG_MAP_LOC: Option<AtomicPtr<RwLock<HashMap<HybridTag, HybridType_>>>> = None;

qinsoon's avatar
qinsoon committed
576
lazy_static! {
qinsoon's avatar
qinsoon committed
577
    /// storing a map from MuName to StructType_
578
    pub static ref STRUCT_TAG_MAP : RwLock<HashMap<StructTag, StructType_>> =
579 580 581 582
        match &STRUCT_TAG_MAP_LOC {
            &Some(ref ptr) => unsafe{ptr::read(ptr.load(Ordering::Relaxed))},
            &None => RwLock::new(HashMap::new())
        };
583
    /// storing a map from MuName to HybridType_
584
    pub static ref HYBRID_TAG_MAP : RwLock<HashMap<HybridTag, HybridType_>> =
585 586 587 588
        match &HYBRID_TAG_MAP_LOC {
            &Some(ref ptr) => unsafe{ptr::read(ptr.load(Ordering::Relaxed))},
            &None => RwLock::new(HashMap::new())
        };
qinsoon's avatar
qinsoon committed
589 590
}

591
rodal_struct!(StructType_ { tys });
592
#[derive(PartialEq, Debug)]
qinsoon's avatar
qinsoon committed
593
pub struct StructType_ {
594
    tys: Vec<P<MuType>>,
qinsoon's avatar
qinsoon committed
595 596
}

597
impl fmt::Display for StructType_ {
598
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
qinsoon's avatar
qinsoon committed
599 600 601
        write!(f, "struct<").unwrap();
        for i in 0..self.tys.len() {
            let ty = &self.tys[i];
602
            write!(f, "{}", ty).unwrap();
qinsoon's avatar
qinsoon committed
603 604 605
            if i != self.tys.len() - 1 {
                write!(f, " ").unwrap();
            }
606
        }
qinsoon's avatar
qinsoon committed
607
        write!(f, ">")
608
    }
609 610
}

qinsoon's avatar
qinsoon committed
611
impl StructType_ {
612 613 614 615
    // 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
616
    pub fn set_tys(&mut self, mut list: Vec<P<MuType>>) {
qinsoon's avatar
qinsoon committed
617
        self.tys.clear();
qinsoon's avatar
qinsoon committed
618
        self.tys.append(&mut list);
qinsoon's avatar
qinsoon committed
619
    }
qinsoon's avatar
qinsoon committed
620

qinsoon's avatar
qinsoon committed
621
    pub fn get_tys(&self) -> &Vec<P<MuType>> {
qinsoon's avatar
qinsoon committed
622 623
        &self.tys
    }
qinsoon's avatar
qinsoon committed
624 625
}

626
rodal_struct!(HybridType_ { fix_tys, var_ty });
627
#[derive(PartialEq, Debug)]
628 629
pub struct HybridType_ {
    fix_tys: Vec<P<MuType>>,
630
    var_ty: P<MuType>,
631 632 633 634
}

impl HybridType_ {
    pub fn new(fix_tys: Vec<P<MuType>>, var_ty: P<MuType>) -> HybridType_ {
qinsoon's avatar
qinsoon committed
635 636
        HybridType_ {
            fix_tys: fix_tys,
637
            var_ty: var_ty,
qinsoon's avatar
qinsoon committed
638
        }
639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666
    }

    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();
            }
        }
667
        write!(f, " {}>", self.var_ty)
668 669 670
    }
}

qinsoon's avatar
qinsoon committed
671 672 673
impl MuType_ {
    pub fn int(len: usize) -> MuType_ {
        MuType_::Int(len)
qinsoon's avatar
qinsoon committed
674
    }
qinsoon's avatar
qinsoon committed
675 676
    pub fn float() -> MuType_ {
        MuType_::Float
qinsoon's avatar
qinsoon committed
677
    }
qinsoon's avatar
qinsoon committed
678 679
    pub fn double() -> MuType_ {
        MuType_::Double
qinsoon's avatar
qinsoon committed
680
    }
qinsoon's avatar
qinsoon committed
681
    pub fn muref(referent: P<MuType>) -> MuType_ {
qinsoon's avatar
qinsoon committed
682
        MuType_::Ref(referent)
qinsoon's avatar
qinsoon committed
683
    }
qinsoon's avatar
qinsoon committed
684
    pub fn iref(referent: P<MuType>) -> MuType_ {
qinsoon's avatar
qinsoon committed
685
        MuType_::IRef(referent)
qinsoon's avatar
qinsoon committed
686
    }
qinsoon's avatar
qinsoon committed
687
    pub fn weakref(referent: P<MuType>) -> MuType_ {
qinsoon's avatar
qinsoon committed
688
        MuType_::WeakRef(referent)
qinsoon's avatar
qinsoon committed
689
    }
qinsoon's avatar
qinsoon committed
690
    pub fn uptr(referent: P<MuType>) -> MuType_ {
qinsoon's avatar
qinsoon committed
691
        MuType_::UPtr(referent)
qinsoon's avatar
qinsoon committed
692
    }
693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719
    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
720
    pub fn mustruct_empty(tag: MuName) -> MuType_ {
qinsoon's avatar
qinsoon committed
721 722 723 724 725
        let struct_ty_ = StructType_ { tys: vec![] };
        STRUCT_TAG_MAP
            .write()
            .unwrap()
            .insert(tag.clone(), struct_ty_);
qinsoon's avatar
qinsoon committed
726

qinsoon's avatar
qinsoon committed
727
        MuType_::Struct(tag)
qinsoon's avatar
qinsoon committed
728
    }
729
    /// puts types into an empty struct (created by mustruct_empty())
qinsoon's avatar
qinsoon committed
730 731
    /// This method will clear existing types declared with the tag,
    /// and set struct to the specified types
732
    /// This method panics if the tag does not exist
733
    pub fn mustruct_put(tag: &MuName, mut list: Vec<P<MuType>>) {
734 735
        let mut map_guard = STRUCT_TAG_MAP.write().unwrap();

736
        match map_guard.get_mut(tag) {
737 738 739
            Some(struct_ty_) => {
                struct_ty_.tys.clear();
                struct_ty_.tys.append(&mut list);
qinsoon's avatar
qinsoon committed
740
            }
741
            None => panic!("call mustruct_empty() to create an empty struct before mustruct_put()"),
742 743
        }
    }
744
    /// creates a Mu struct with specified field types
745
    pub fn mustruct(tag: StructTag, list: Vec<P<MuType>>) -> MuType_ {
qinsoon's avatar
qinsoon committed
746
        let struct_ty_ = StructType_ { tys: list };
qinsoon's avatar
qinsoon committed
747 748 749

        // if there is an attempt to use a same tag for different struct,
        // we panic
750
        match STRUCT_TAG_MAP.read().unwrap().get(&tag) {
qinsoon's avatar
qinsoon committed
751 752
            Some(old_struct_ty_) => {
                if struct_ty_ != *old_struct_ty_ {
753 754 755 756
                    panic!(
                        "trying to insert {} as {}, while the old struct is defined as {}",
                        struct_ty_, tag, old_struct_ty_
                    )
qinsoon's avatar
qinsoon committed
757
                }
qinsoon's avatar
qinsoon committed
758
            }
qinsoon's avatar
qinsoon committed
759 760 761
            None => {}
        }
        // otherwise, store the tag
qinsoon's avatar
qinsoon committed
762 763 764 765
        STRUCT_TAG_MAP
            .write()
            .unwrap()
            .insert(tag.clone(), struct_ty_);
qinsoon's avatar
qinsoon committed
766

qinsoon's avatar
qinsoon committed
767
        MuType_::Struct(tag)
qinsoon's avatar
qinsoon committed
768
    }
769 770 771

    /// 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> }
772
    pub fn hybrid_empty(tag: HybridTag) -> MuType_ {
qinsoon's avatar
qinsoon committed
773 774
        let hybrid_ty_ = HybridType_ {
            fix_tys: vec![],
775
            var_ty: VOID_TYPE.clone(),
qinsoon's avatar
qinsoon committed
776 777 778 779 780
        };
        HYBRID_TAG_MAP
            .write()
            .unwrap()
            .insert(tag.clone(), hybrid_ty_);
781 782 783

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

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

792
        match map_guard.get_mut(tag) {
qinsoon's avatar
qinsoon committed
793 794 795 796 797
            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
798
            }
799
            None => panic!("call hybrid_empty() to create an empty struct before hybrid_put()"),
qinsoon's avatar
qinsoon committed
800 801
        }
    }
802
    /// creates a Mu hybrid with specified fix part and var part types
803
    pub fn hybrid(tag: HybridTag, fix_tys: Vec<P<MuType>>, var_ty: P<MuType>) -> MuType_ {
qinsoon's avatar
qinsoon committed
804 805
        let hybrid_ty_ = HybridType_ {
            fix_tys: fix_tys,
806
            var_ty: var_ty,
qinsoon's avatar
qinsoon committed
807
        };
808 809 810 811

        match HYBRID_TAG_MAP.read().unwrap().get(&tag) {
            Some(old_hybrid_ty_) => {
                if hybrid_ty_ != *old_hybrid_ty_ {
812 813 814 815
                    panic!(
                        "trying to insert {} as {}, while the old hybrid is defined as {}",
                        hybrid_ty_, tag, old_hybrid_ty_
                    );
816
                }
qinsoon's avatar
qinsoon committed
817
            }
818 819 820
            None => {}
        }

qinsoon's avatar
qinsoon committed
821 822 823 824
        HYBRID_TAG_MAP
            .write()
            .unwrap()
            .insert(tag.clone(), hybrid_ty_);
825 826

        MuType_::Hybrid(tag)
qinsoon's avatar
qinsoon committed
827
    }
qinsoon's avatar
qinsoon committed
828 829
}

830
/// MuFuncSig represents a Mu function signature
831
#[derive(Debug)]
qinsoon's avatar
qinsoon committed
832
pub struct MuFuncSig {
833
    pub hdr: MuEntityHeader,
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
834
    pub ret_tys: Vec<P<MuType>>,
835
    pub arg_tys: Vec<P<MuType>>,
836 837
}

838 839 840 841 842
impl PartialEq for MuFuncSig {
    fn eq(&self, other: &MuFuncSig) -> bool {
        self.ret_tys == other.ret_tys && self.arg_tys == other.arg_tys
    }
}
843 844 845 846 847
rodal_struct!(MuFuncSig {
    hdr,
    ret_tys,
    arg_tys
});
848

849
impl fmt::Display for MuFuncSig {
850
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
851 852 853 854 855 856
        write!(
            f,
            "({})->({})",
            vec_utils::as_str_sp(&self.arg_tys),
            vec_utils::as_str_sp(&self.ret_tys)
        )
857 858
    }
}
859

860
pub type CFuncSig = MuFuncSig;