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

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

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

qinsoon's avatar
qinsoon committed
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
lazy_static! {
    pub static ref ADDRESS_TYPE : P<MuType> = P(
        MuType::new(new_internal_id(), MuType_::int(POINTER_SIZE * 8))
    );
    
    pub static ref UINT32_TYPE : P<MuType> = P(
        MuType::new(new_internal_id(), MuType_::int(32))
    );
    
    pub static ref UINT64_TYPE : P<MuType> = P(
        MuType::new(new_internal_id(), MuType_::int(64))
    );
    
    pub static ref DOUBLE_TYPE : P<MuType> = P(
        MuType::new(new_internal_id(), MuType_::double())
    );
    
    pub static ref INTERNAL_TYPES : Vec<P<MuType>> = vec![
        ADDRESS_TYPE.clone(),
        UINT32_TYPE.clone(),
        UINT64_TYPE.clone(),
        DOUBLE_TYPE.clone()
    ];    
}

qinsoon's avatar
qinsoon committed
36
#[derive(PartialEq, Debug, RustcEncodable, RustcDecodable)]
qinsoon's avatar
qinsoon committed
37
pub struct MuType {
38
    pub hdr: MuEntityHeader,
qinsoon's avatar
qinsoon committed
39 40 41 42 43 44
    pub v: MuType_
}

impl MuType {
    pub fn new(id: MuID, v: MuType_) -> MuType {
        MuType {
45
            hdr: MuEntityHeader::unnamed(id),
qinsoon's avatar
qinsoon committed
46 47 48 49
            v: v
        }
    }
}
qinsoon's avatar
qinsoon committed
50

qinsoon's avatar
qinsoon committed
51
#[derive(PartialEq, Debug, RustcEncodable, RustcDecodable)]
qinsoon's avatar
qinsoon committed
52
pub enum MuType_ {
qinsoon's avatar
qinsoon committed
53
    /// int <length>
qinsoon's avatar
qinsoon committed
54
    Int          (usize),
qinsoon's avatar
qinsoon committed
55
    /// float
qinsoon's avatar
qinsoon committed
56
    Float,
qinsoon's avatar
qinsoon committed
57
    /// double
qinsoon's avatar
qinsoon committed
58
    Double,
59

qinsoon's avatar
qinsoon committed
60
    /// ref<T>
qinsoon's avatar
qinsoon committed
61
    Ref          (P<MuType>),    // Box is needed for non-recursive enum
qinsoon's avatar
qinsoon committed
62
    /// iref<T>: internal reference
qinsoon's avatar
qinsoon committed
63
    IRef         (P<MuType>),
qinsoon's avatar
qinsoon committed
64
    /// weakref<T>
qinsoon's avatar
qinsoon committed
65
    WeakRef      (P<MuType>),
66

qinsoon's avatar
qinsoon committed
67
    /// uptr<T>: unsafe pointer
qinsoon's avatar
qinsoon committed
68
    UPtr         (P<MuType>),
69

qinsoon's avatar
qinsoon committed
70
    /// struct<T1 T2 ...>
qinsoon's avatar
qinsoon committed
71
    Struct       (MuName),
72

qinsoon's avatar
qinsoon committed
73
    /// array<T length>
qinsoon's avatar
qinsoon committed
74
    Array        (P<MuType>, usize),
75

qinsoon's avatar
qinsoon committed
76
    /// hybrid<F1 F2 ... V>: a hybrid of fixed length parts and a variable length part
qinsoon's avatar
qinsoon committed
77
    Hybrid       (Vec<P<MuType>>, P<MuType>),
78

qinsoon's avatar
qinsoon committed
79
    /// void
qinsoon's avatar
qinsoon committed
80
    Void,
81

qinsoon's avatar
qinsoon committed
82
    /// threadref
qinsoon's avatar
qinsoon committed
83
    ThreadRef,
qinsoon's avatar
qinsoon committed
84
    /// stackref
qinsoon's avatar
qinsoon committed
85
    StackRef,
86

qinsoon's avatar
qinsoon committed
87
    /// tagref64: hold a double or an int or an ref<void>
qinsoon's avatar
qinsoon committed
88
    Tagref64,
89

qinsoon's avatar
qinsoon committed
90
    /// vector<T length>
qinsoon's avatar
qinsoon committed
91
    Vector       (P<MuType>, usize),
92

qinsoon's avatar
qinsoon committed
93
    /// funcref<@sig>
94
    FuncRef      (P<MuFuncSig>),
95

qinsoon's avatar
qinsoon committed
96
    /// ufuncptr<@sig>
97
    UFuncPtr     (P<MuFuncSig>),
qinsoon's avatar
qinsoon committed
98 99
}

qinsoon's avatar
qinsoon committed
100 101 102 103 104 105
impl fmt::Display for MuType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.v)        
    }
}

106
impl fmt::Display for MuType_ {
107 108
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
qinsoon's avatar
qinsoon committed
109 110 111
            &MuType_::Int(n)                          => write!(f, "int<{}>", n),
            &MuType_::Float                           => write!(f, "float"),
            &MuType_::Double                          => write!(f, "double"),
112 113 114 115 116
            &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
117
            &MuType_::Hybrid(ref fix_tys, ref var_ty) => write!(f, "hybrid<[{}] {}>", vec_utils::as_str(fix_tys), var_ty),
qinsoon's avatar
qinsoon committed
118 119 120 121
            &MuType_::Void                            => write!(f, "void"),
            &MuType_::ThreadRef                       => write!(f, "threadref"),
            &MuType_::StackRef                        => write!(f, "stackref"),
            &MuType_::Tagref64                        => write!(f, "tagref64"),
122 123 124
            &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),
125
            &MuType_::Struct(ref tag)                     => write!(f, "{}(struct)", tag)
126 127 128 129
        }
    }
}

qinsoon's avatar
qinsoon committed
130
lazy_static! {
qinsoon's avatar
qinsoon committed
131 132
    /// storing a map from MuName to StructType_
    pub static ref STRUCT_TAG_MAP : RwLock<HashMap<MuName, StructType_>> = RwLock::new(HashMap::new());
qinsoon's avatar
qinsoon committed
133 134
}

qinsoon's avatar
qinsoon committed
135
#[derive(PartialEq, Debug, RustcEncodable, RustcDecodable)]
qinsoon's avatar
qinsoon committed
136
pub struct StructType_ {
qinsoon's avatar
qinsoon committed
137
    tys: Vec<P<MuType>>
qinsoon's avatar
qinsoon committed
138 139
}

140
impl fmt::Display for StructType_ {
141
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
qinsoon's avatar
qinsoon committed
142 143 144
        write!(f, "struct<").unwrap();
        for i in 0..self.tys.len() {
            let ty = &self.tys[i];
145
            write!(f, "{}", ty).unwrap();
qinsoon's avatar
qinsoon committed
146 147 148
            if i != self.tys.len() - 1 {
                write!(f, " ").unwrap();
            }
149
        }
qinsoon's avatar
qinsoon committed
150
        write!(f, ">")
151
    }
152 153
}

qinsoon's avatar
qinsoon committed
154
impl StructType_ {
155 156 157 158
    // 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
159
    pub fn set_tys(&mut self, mut list: Vec<P<MuType>>) {
qinsoon's avatar
qinsoon committed
160
        self.tys.clear();
qinsoon's avatar
qinsoon committed
161
        self.tys.append(&mut list);
qinsoon's avatar
qinsoon committed
162
    }
qinsoon's avatar
qinsoon committed
163
    
qinsoon's avatar
qinsoon committed
164
    pub fn get_tys(&self) -> &Vec<P<MuType>> {
qinsoon's avatar
qinsoon committed
165 166
        &self.tys
    }
qinsoon's avatar
qinsoon committed
167 168
}

qinsoon's avatar
qinsoon committed
169 170 171
impl MuType_ {
    pub fn int(len: usize) -> MuType_ {
        MuType_::Int(len)
qinsoon's avatar
qinsoon committed
172
    }
qinsoon's avatar
qinsoon committed
173 174
    pub fn float() -> MuType_ {
        MuType_::Float
qinsoon's avatar
qinsoon committed
175
    }
qinsoon's avatar
qinsoon committed
176 177
    pub fn double() -> MuType_ {
        MuType_::Double
qinsoon's avatar
qinsoon committed
178
    }
qinsoon's avatar
qinsoon committed
179
    pub fn muref(referent: P<MuType>) -> MuType_ {
qinsoon's avatar
qinsoon committed
180
        MuType_::Ref(referent)
qinsoon's avatar
qinsoon committed
181
    }
qinsoon's avatar
qinsoon committed
182
    pub fn iref(referent: P<MuType>) -> MuType_ {
qinsoon's avatar
qinsoon committed
183
        MuType_::IRef(referent)
qinsoon's avatar
qinsoon committed
184
    }
qinsoon's avatar
qinsoon committed
185
    pub fn weakref(referent: P<MuType>) -> MuType_ {
qinsoon's avatar
qinsoon committed
186
        MuType_::WeakRef(referent)
qinsoon's avatar
qinsoon committed
187
    }
qinsoon's avatar
qinsoon committed
188
    pub fn uptr(referent: P<MuType>) -> MuType_ {
qinsoon's avatar
qinsoon committed
189
        MuType_::UPtr(referent)
qinsoon's avatar
qinsoon committed
190
    }
qinsoon's avatar
qinsoon committed
191
    pub fn mustruct_empty(tag: MuName) -> MuType_ {
qinsoon's avatar
qinsoon committed
192
        let struct_ty_ = StructType_{tys: vec![]};
193
        STRUCT_TAG_MAP.write().unwrap().insert(tag.clone(), struct_ty_);
qinsoon's avatar
qinsoon committed
194

qinsoon's avatar
qinsoon committed
195
        MuType_::Struct(tag)
qinsoon's avatar
qinsoon committed
196
    }
qinsoon's avatar
qinsoon committed
197
    pub fn mustruct(tag: MuName, list: Vec<P<MuType>>) -> MuType_ {
qinsoon's avatar
qinsoon committed
198
        let struct_ty_ = StructType_{tys: list};
qinsoon's avatar
qinsoon committed
199 200 201

        // if there is an attempt to use a same tag for different struct,
        // we panic
202
        match STRUCT_TAG_MAP.read().unwrap().get(&tag) {
qinsoon's avatar
qinsoon committed
203 204 205 206 207 208 209 210 211 212
            Some(old_struct_ty_) => {
                if struct_ty_ != *old_struct_ty_ {
                    panic!(format!(
                            "trying to insert {:?} as {}, while the old struct is defined as {:?}",
                            struct_ty_, tag, old_struct_ty_))
                }
            },
            None => {}
        }
        // otherwise, store the tag
213
        STRUCT_TAG_MAP.write().unwrap().insert(tag.clone(), struct_ty_);
qinsoon's avatar
qinsoon committed
214

qinsoon's avatar
qinsoon committed
215
        MuType_::Struct(tag)
qinsoon's avatar
qinsoon committed
216
    }
qinsoon's avatar
qinsoon committed
217
    pub fn array(ty: P<MuType>, len: usize) -> MuType_ {
qinsoon's avatar
qinsoon committed
218
        MuType_::Array(ty, len)
qinsoon's avatar
qinsoon committed
219
    }
qinsoon's avatar
qinsoon committed
220
    pub fn hybrid(fix_tys: Vec<P<MuType>>, var_ty: P<MuType>) -> MuType_ {
qinsoon's avatar
qinsoon committed
221
        MuType_::Hybrid(fix_tys, var_ty)
qinsoon's avatar
qinsoon committed
222
    }
qinsoon's avatar
qinsoon committed
223 224
    pub fn void() -> MuType_ {
        MuType_::Void
qinsoon's avatar
qinsoon committed
225
    }
qinsoon's avatar
qinsoon committed
226 227
    pub fn threadref() -> MuType_ {
        MuType_::ThreadRef
qinsoon's avatar
qinsoon committed
228
    }
qinsoon's avatar
qinsoon committed
229 230
    pub fn stackref() -> MuType_ {
        MuType_::StackRef
qinsoon's avatar
qinsoon committed
231
    }
qinsoon's avatar
qinsoon committed
232 233
    pub fn tagref64() -> MuType_ {
        MuType_::Tagref64
qinsoon's avatar
qinsoon committed
234
    }
qinsoon's avatar
qinsoon committed
235
    pub fn vector(ty: P<MuType>, len: usize) -> MuType_ {
qinsoon's avatar
qinsoon committed
236
        MuType_::Vector(ty, len)
qinsoon's avatar
qinsoon committed
237
    }
238
    pub fn funcref(sig: P<MuFuncSig>) -> MuType_ {
qinsoon's avatar
qinsoon committed
239
        MuType_::FuncRef(sig)
qinsoon's avatar
qinsoon committed
240
    }
241
    pub fn ufuncptr(sig: P<MuFuncSig>) -> MuType_ {
qinsoon's avatar
qinsoon committed
242
        MuType_::UFuncPtr(sig)
qinsoon's avatar
qinsoon committed
243 244 245 246
    }
}

/// is a type floating-point type?
qinsoon's avatar
qinsoon committed
247
pub fn is_fp(ty: &MuType) -> bool {
qinsoon's avatar
qinsoon committed
248
    match ty.v {
qinsoon's avatar
qinsoon committed
249
        MuType_::Float | MuType_::Double => true,
qinsoon's avatar
qinsoon committed
250 251 252 253 254
        _ => false
    }
}

/// is a type raw pointer?
qinsoon's avatar
qinsoon committed
255
pub fn is_ptr(ty: &MuType) -> bool {
qinsoon's avatar
qinsoon committed
256
    match ty.v {
qinsoon's avatar
qinsoon committed
257
        MuType_::UPtr(_) | MuType_::UFuncPtr(_) => true,
qinsoon's avatar
qinsoon committed
258 259 260 261 262
        _ => false
    }
}

/// is a type scalar type?
qinsoon's avatar
qinsoon committed
263
pub fn is_scalar(ty: &MuType) -> bool {
qinsoon's avatar
qinsoon committed
264
    match ty.v {
qinsoon's avatar
qinsoon committed
265 266 267 268 269 270 271 272 273 274 275 276
        MuType_::Int(_)
        | MuType_::Float
        | MuType_::Double
        | MuType_::Ref(_)
        | MuType_::IRef(_)
        | MuType_::WeakRef(_)
        | MuType_::FuncRef(_)
        | MuType_::UFuncPtr(_)
        | MuType_::ThreadRef
        | MuType_::StackRef
        | MuType_::Tagref64
        | MuType_::UPtr(_) => true,
qinsoon's avatar
qinsoon committed
277 278 279 280 281
        _ => false
    }
}

/// is a type traced by the garbage collector?
282
/// Note: An aggregated type is traced if any of its part is traced.
qinsoon's avatar
qinsoon committed
283
pub fn is_traced(ty: &MuType) -> bool {
qinsoon's avatar
qinsoon committed
284
    match ty.v {
qinsoon's avatar
qinsoon committed
285 286 287 288 289 290 291 292 293
        MuType_::Ref(_) => true,
        MuType_::IRef(_) => true,
        MuType_::WeakRef(_) => true,
        MuType_::Array(ref elem_ty, _)
        | MuType_::Vector(ref elem_ty, _) => is_traced(elem_ty),
        MuType_::ThreadRef
        | MuType_::StackRef
        | MuType_::Tagref64 => true,
        MuType_::Hybrid(ref fix_tys, ref var_ty) => {
qinsoon's avatar
qinsoon committed
294 295
            is_traced(var_ty) ||
            fix_tys.into_iter().map(|ty| is_traced(ty))
296
                .fold(false, |ret, this| ret || this)
qinsoon's avatar
qinsoon committed
297
            },
298
        MuType_::Struct(ref tag) => {
qinsoon's avatar
qinsoon committed
299 300 301
            let map = STRUCT_TAG_MAP.read().unwrap();
            let struct_ty = map.get(tag).unwrap();
            let ref field_tys = struct_ty.tys;
302

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

/// is a type native safe?
/// Note: An aggregated type is native safe if all of its parts are native safe.
qinsoon's avatar
qinsoon committed
312
pub fn is_native_safe(ty: &MuType) -> bool {
qinsoon's avatar
qinsoon committed
313
    match ty.v {
qinsoon's avatar
qinsoon committed
314 315 316 317 318 319 320 321 322
        MuType_::Int(_) => true,
        MuType_::Float => true,
        MuType_::Double => true,
        MuType_::Void => true,
        MuType_::Array(ref elem_ty, _)
        | MuType_::Vector(ref elem_ty, _) => is_native_safe(elem_ty),
        MuType_::UPtr(_) => true,
        MuType_::UFuncPtr(_) => true,
        MuType_::Hybrid(ref fix_tys, ref var_ty) => {
323
            is_native_safe(var_ty) &&
qinsoon's avatar
qinsoon committed
324 325 326
            fix_tys.into_iter().map(|ty| is_native_safe(&ty))
                .fold(true, |ret, this| ret && this)
        },
327
        MuType_::Struct(ref tag) => {
qinsoon's avatar
qinsoon committed
328 329 330
            let map = STRUCT_TAG_MAP.read().unwrap();
            let struct_ty = map.get(tag).unwrap();
            let ref field_tys = struct_ty.tys;
331

qinsoon's avatar
qinsoon committed
332 333 334 335
            field_tys.into_iter().map(|ty| is_native_safe(&ty))
                .fold(true, |ret, this| ret && this)
        },
        _ => false
qinsoon's avatar
qinsoon committed
336 337 338
    }
}

339
pub fn get_referent_ty(ty: &MuType) -> Option<P<MuType>> {
qinsoon's avatar
qinsoon committed
340 341 342 343
    match ty.v {
        MuType_::Ref(ref referent)
        | MuType_::IRef(ref referent)
        | MuType_::WeakRef(ref referent) => Some(referent.clone()),
344 345 346 347
        _ => None
    }
}

qinsoon's avatar
qinsoon committed
348 349 350 351 352 353 354 355 356
macro_rules! is_type (
    ($e:expr, $p:pat) => (
        match $e {
            $p => true,
            _ => false
        }
    )
);

357 358
pub type CFuncSig = MuFuncSig;

qinsoon's avatar
qinsoon committed
359
#[derive(PartialEq, Debug, RustcEncodable, RustcDecodable)]
qinsoon's avatar
qinsoon committed
360
pub struct MuFuncSig {
361
    pub hdr: MuEntityHeader,
qinsoon's avatar
qinsoon committed
362 363
    pub ret_tys : Vec<P<MuType>>,
    pub arg_tys: Vec<P<MuType>>
364 365
}

366
impl fmt::Display for MuFuncSig {
367
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
qinsoon's avatar
qinsoon committed
368
        write!(f, "[{}] -> [{}]", vec_utils::as_str(&self.ret_tys), vec_utils::as_str(&self.arg_tys))
369 370
    }
}