libdusk/
interpreter.rs

1use std::alloc;
2use std::collections::HashMap;
3use std::convert::TryInto;
4use std::ffi::{CStr, CString, c_void, OsString};
5use std::mem;
6use std::slice;
7use std::fmt::{Write, Debug};
8use std::cell::RefCell;
9use std::sync::RwLock;
10use std::borrow::Cow;
11#[cfg(windows)]
12use std::cmp::min;
13use std::io::Write as IoWrite;
14
15use indenter::indented;
16use smallvec::SmallVec;
17use paste::paste;
18use num_bigint::{BigInt, Sign};
19use display_adapter::display_adapter;
20use index_vec::IndexVec;
21use lazy_static::lazy_static;
22
23use dusk_dire::arch::Arch;
24use dusk_dire::hir::{Intrinsic, ModScopeId, EnumId, GenericParamId, ExternFunctionRef};
25use dusk_dire::mir::{Const, Instr, InstrId, FuncId, StaticId, ExternFunction};
26use dusk_dire::ty::{Type, FunctionType, QualType, IntWidth, FloatWidth, StructType, InternalType};
27use dusk_dire::{OpId, BlockId};
28use dusk_dire::{InternalField, internal_fields};
29
30use crate::driver::{DRIVER, Driver, DriverRef};
31use crate::mir::{FunctionRef, function_by_ref};
32use crate::type_provider::TypeProvider;
33use crate::x64::*;
34
35#[derive(Debug, Clone)]
36pub enum InternalValue {
37    Ty(Type),
38    Mod(ModScopeId),
39    FunctionPointer { generic_arguments: Vec<Type>, func: FuncId },
40    StrLit(CString),
41    Args(Vec<CString>),
42}
43
44#[derive(Debug)]
45pub enum Value {
46    /// An inline value
47    Inline(SmallVec<[u8; 64 / 8]>),
48    /// A *pointer* to a piece of memory
49    Dynamic(Box<[u8]>),
50    Internal { val: InternalValue, indirection: u8 },
51    Nothing,
52}
53
54impl Clone for Value {
55    fn clone(&self) -> Value {
56        match self {
57            Value::Inline(storage) => Value::Inline(storage.clone()),
58            Value::Dynamic(_) => Value::from_bytes(&self.as_bytes()),
59            &Value::Internal { ref val, indirection } => Value::Internal { val: val.clone(), indirection },
60            Value::Nothing => Value::Nothing,
61        }
62    }
63}
64
65macro_rules! int_conversions {
66    ($($ty_name:ty),+) => {
67        impl Value {
68            paste! {
69                $(
70                    #[allow(dead_code)]
71                    fn [<as_ $ty_name>](&self) -> $ty_name {
72                        $ty_name::from_le_bytes(self.as_bytes().as_ref().try_into().unwrap())
73                    }
74
75                    #[allow(dead_code)]
76                    fn [<from_ $ty_name>](val: $ty_name) -> Value {
77                        Value::from_bytes(val.to_le_bytes().as_ref())
78                    }
79                )+
80            }
81        }
82    }
83}
84int_conversions!(u8, u16, u32, u64, usize, i8, i16, i32, i64, isize);
85
86impl Driver {
87    fn eval_struct_lit(&self, strukt: &StructType, fields: impl Iterator<Item=Value> + Debug) -> Value {
88        let layout = self.layout_struct(strukt);
89        let mut buf = SmallVec::new();
90        buf.resize(layout.size, 0);
91        for (i, field) in fields.enumerate() {
92            let offset = layout.field_offsets[i];
93            let ty = &strukt.field_tys[i];
94            let size = self.size_of(ty);
95            let val = field.as_bytes_with_driver(self);
96            buf[offset..(offset + size)].copy_from_slice(&val);
97        }
98        Value::Inline(buf)
99    }
100}
101
102struct Enum {
103    discriminant: u32,
104}
105impl Value {
106    fn as_bytes_with_driver_maybe(&self, d: Option<&Driver>) -> Cow<[u8]> {
107        match self {
108            Value::Inline(storage) => Cow::Borrowed(storage.as_ref()),
109            Value::Dynamic(ptr) => unsafe {
110                let address_bits = mem::transmute::<&Box<_>, *const u8>(ptr);
111                Cow::Borrowed(slice::from_raw_parts(address_bits, mem::size_of::<usize>()))
112            },
113            &Value::Internal { val: InternalValue::FunctionPointer { ref generic_arguments, func }, indirection: 0 } if d.is_some() => {
114                assert!(generic_arguments.is_empty());
115                Cow::Owned(d.unwrap().fetch_inverse_thunk(func).as_bytes().to_vec())
116            },
117            Value::Internal { .. } => panic!("Can't get bytes of a compiler internal data structure!"),
118            Value::Nothing => Cow::Borrowed(&[]),
119        }
120    }
121    fn as_bytes_with_driver(&self, d: &Driver) -> Cow<[u8]> {
122        self.as_bytes_with_driver_maybe(Some(d))
123    }
124    fn as_bytes(&self) -> Cow<[u8]> {
125        self.as_bytes_with_driver_maybe(None)
126    }
127
128    /// Interprets the value as a pointer and loads from it
129    fn load(&self, size: usize) -> Value {
130        match self {
131            Value::Inline(_) => {
132                let ptr = self.as_raw_ptr();
133                let slice = unsafe { std::slice::from_raw_parts(ptr, size) };
134                let buf = SmallVec::from_slice(slice);
135                Value::Inline(buf)
136            },
137            Value::Dynamic(val) => {
138                let buf = SmallVec::from_slice(val);
139                Value::Inline(buf)
140            },
141            Value::Internal { val, indirection } => Value::Internal { val: val.clone(), indirection: indirection - 1 },
142            Value::Nothing => panic!("can't load from nothing"),
143        }
144    }
145
146    fn store(&mut self, val: Value) {
147        match val {
148            Value::Internal { val, indirection } => *self = Value::Internal { val, indirection: indirection + 1 },
149            _ => {
150                let ptr = self.as_raw_ptr();
151                let val = val.as_bytes();
152                let slice = unsafe { std::slice::from_raw_parts_mut(ptr, val.len()) };
153                slice.copy_from_slice(&val);
154            }
155        }
156    }
157
158    pub fn as_big_int(&self, signed: bool) -> BigInt {
159        if signed {
160            BigInt::from_signed_bytes_le(self.as_bytes().as_ref())
161        } else {
162            BigInt::from_bytes_le(Sign::Plus, self.as_bytes().as_ref())
163        }
164    }
165
166    fn as_raw_ptr(&self) -> *mut u8 {
167        unsafe { mem::transmute(usize::from_le_bytes(self.as_bytes().as_ref().try_into().unwrap())) }
168    }
169
170    fn as_f64(&self) -> f64 {
171        f64::from_bits(self.as_u64())
172    }
173
174    fn as_f32(&self) -> f32 {
175        f32::from_bits(self.as_u32())
176    }
177
178    fn as_bool(&self) -> bool {
179        let bytes = self.as_bytes();
180        assert!(bytes.len() == 1);
181        bytes[0] != 0
182    }
183
184    fn as_enum(&self) -> Enum {
185        Enum {
186            discriminant: self.as_u32()
187        }
188    }
189
190    fn as_internal(&self) -> &InternalValue {
191        match self {
192            Value::Internal { val, indirection } => {
193                assert_eq!(*indirection, 0, "can't get pointer to internal compiler data structure without dereferencing");
194                val
195            },
196            _ => panic!("Can't get non-internal compiler data structure as internal compiler data structure"),
197        }
198    }
199
200    fn as_ty(&self) -> Type {
201        match self.as_internal() {
202            InternalValue::Ty(ty) => ty.clone(),
203            _ => panic!("Can't get non-type as type"),
204        }
205    }
206
207    fn as_mod(&self) -> ModScopeId {
208        match *self.as_internal() {
209            InternalValue::Mod(id) => id,
210            _ => panic!("Can't get non-module as module"),
211        }
212    }
213
214    fn from_bytes(bytes: &[u8]) -> Value {
215        let storage = SmallVec::from_slice(bytes);
216        Value::Inline(storage)
217    }
218
219    fn from_big_int(big_int: BigInt, width: IntWidth, is_signed: bool, arch: Arch) -> Value {
220        let size = match width {
221            IntWidth::W8 => 1,
222            IntWidth::W16 => 2,
223            IntWidth::W32 => 4,
224            IntWidth::W64 => 8,
225            IntWidth::Pointer => arch.pointer_size() / 8,
226        };
227        let (mut bytes, extension) = if is_signed {
228            (
229                big_int.to_signed_bytes_le(),
230                match big_int.sign() {
231                    Sign::Plus | Sign::NoSign => 0x00,
232                    Sign::Minus => 0xFF,
233                }
234            )
235        } else {
236            let (sign, bytes) = big_int.to_bytes_le();
237            assert!(!matches!(sign, Sign::Minus), "Can't put negative value in an unsigned int");
238            (bytes, 0x00)
239        };
240
241        assert!(bytes.len() <= size, "Integer is too big");
242        while bytes.len() < size {
243            bytes.push(extension);
244        }
245
246        Value::from_bytes(&bytes)
247    }
248
249    pub fn from_const(konst: &Const, driver: &Driver) -> Value {
250        match *konst {
251            Const::Int { ref lit, ref ty } => match ty {
252                &Type::Int { width, is_signed } => Value::from_big_int(lit.clone(), width, is_signed, driver.arch),
253                _ => panic!("unexpected int constant type {:?}", ty),
254            },
255            Const::Float { lit, ref ty } => match driver.size_of(ty) {
256                4 => Value::from_f32(lit as f32),
257                8 => Value::from_f64(lit),
258                _ => panic!("Unrecognized float constant size"),
259            },
260            Const::Bool(val) => Value::from_bool(val),
261            Const::Str { id, .. } => {
262                let ptr = driver.code.mir.strings[id].as_ptr();
263                Value::from_usize(ptr as usize)
264            },
265            Const::StrLit(ref lit) => Value::from_internal(InternalValue::StrLit(lit.clone())),
266            Const::Ty(ref ty) => Value::from_ty(ty.clone()),
267            Const::Void => Value::Nothing,
268            Const::Mod(id) => Value::from_mod(id),
269            Const::BasicVariant { enuum, index } => Value::from_variant(driver, enuum, index, Value::Nothing),
270            Const::StructLit { ref fields, id } => {
271                let field_tys: Vec<_> = fields.iter().map(|val| val.ty()).collect();
272                let fields = fields.iter().map(|val| Value::from_const(val, driver));
273                let strukt = StructType {
274                    field_tys,
275                    identity: id,
276                };
277                driver.eval_struct_lit(&strukt, fields)
278            },
279        }
280    }
281
282    fn from_f32(val: f32) -> Value {
283        Value::from_u32(val.to_bits())
284    }
285
286    fn from_f64(val: f64) -> Value {
287        Value::from_u64(val.to_bits())
288    }
289
290    fn from_bool(val: bool) -> Value {
291        Value::from_u8(unsafe { mem::transmute(val) })
292    }
293
294    fn from_variant(d: &Driver, enuum: EnumId, index: usize, payload: Value) -> Value {
295        let layout = &d.code.mir.enums[&enuum];
296        let payload_offset = layout.payload_offsets[index];
297        let mut bytes = Vec::new();
298        bytes.extend(Value::from_u32(index as u32).as_bytes().as_ref());
299        while bytes.len() < payload_offset {
300            bytes.push(0);
301        }
302        bytes.extend(payload.as_bytes().as_ref());
303        Value::from_bytes(&bytes)
304    }
305
306    fn from_internal(val: InternalValue) -> Value {
307        Value::Internal { val, indirection: 0 }
308    }
309
310    fn from_ty(ty: Type) -> Value {
311        Self::from_internal(InternalValue::Ty(ty))
312    }
313
314    fn from_mod(id: ModScopeId) -> Value {
315        Self::from_internal(InternalValue::Mod(id))
316    }
317}
318
319pub struct StackFrame {
320    func_ref: FunctionRef,
321    block: BlockId,
322    pc: usize,
323    results: IndexVec<InstrId, Value>,
324    generic_ctx: HashMap<GenericParamId, Type>,
325}
326
327impl StackFrame {
328    fn branch_to(&mut self, bb: BlockId) {
329        self.block = bb;
330        self.pc = 0;
331    }
332
333    fn canonicalize_type(&self, ty: &Type) -> Type {
334        match ty {
335            &Type::GenericParam(id) => {
336                if let Some(result) = self.generic_ctx.get(&id) {
337                    result.clone()
338                } else {
339                    ty.clone()
340                }
341            },
342            Type::Pointer(pointee) =>
343                Type::Pointer(
344                    Box::new(QualType { ty: self.canonicalize_type(&pointee.ty), is_mut: pointee.is_mut })
345                ),
346            Type::Function(FunctionType { param_tys, return_ty }) =>
347                Type::Function(
348                    FunctionType {
349                        param_tys: param_tys.iter().map(|ty| self.canonicalize_type(ty)).collect(),
350                        return_ty: Box::new(self.canonicalize_type(return_ty)),
351                    }
352                ),
353            &Type::Struct(StructType { ref field_tys, identity }) => Type::Struct(
354                StructType {
355                    field_tys: field_tys.iter().map(|ty| self.canonicalize_type(ty)).collect(),
356                    identity,
357                }
358            ),
359            ty => ty.clone(),
360        }
361    }
362
363    fn get_val(&self, op: OpId, d: &Driver) -> &Value {
364        let instr_id = d.code.ops[op].get_mir_instr_id().unwrap();
365        &self.results[instr_id]
366    }
367
368    fn get_val_mut(&mut self, op: OpId, d: &Driver) -> &mut Value {
369        let instr_id = d.code.ops[op].get_mir_instr_id().unwrap();
370        &mut self.results[instr_id]
371    }
372}
373
374#[derive(Copy, Clone, Debug)]
375pub enum InterpMode {
376    CompileTime,
377    RunTime,
378}
379
380struct Allocation(region::Allocation);
381unsafe impl Sync for Allocation {}
382unsafe impl Send for Allocation {}
383
384pub struct Interpreter {
385    statics: HashMap<StaticId, Value>,
386    allocations: HashMap<usize, alloc::Layout>,
387    switch_cache: HashMap<OpId, HashMap<Box<[u8]>, BlockId>>,
388    #[cfg(windows)]
389    inverse_thunk_cache: HashMap<FuncId, Allocation>,
390    mode: InterpMode,
391    command_line_args: Vec<CString>,
392}
393
394impl Interpreter {
395    pub fn new(mode: InterpMode) -> Self {
396        Self {
397            statics: HashMap::new(),
398            allocations: HashMap::new(),
399            switch_cache: HashMap::new(),
400            #[cfg(windows)]
401            inverse_thunk_cache: HashMap::new(),
402            command_line_args: Vec::new(),
403            mode,
404        }
405    }
406}
407
408macro_rules! bin_op {
409    ($salf:ident, $stack:ident, $args:ident, $conv:ident, $first_ty:ident | $($ty:ident)|+, {$sign:tt}) => {{
410        bin_op!(@preamble $salf, $stack, $args, lhs, rhs, ty, final_val);
411        bin_op!(@kontinue $salf, ty, lhs, rhs, $conv, $first_ty | $($ty)|+, {$sign}, final_val);
412        final_val.expect("Unexpected type for arguments")
413    }};
414    ($salf:ident, $stack:ident, $args:ident, $conv:ident, $ty:ident, {$sign:tt}) => {{
415        bin_op!(@preamble $salf, $stack, $args, lhs, rhs, ty, final_val);
416        bin_op!(@kontinue $salf, ty, lhs, rhs, $conv, $ty, {$sign}, final_val);
417        final_val.expect("Unexpected type for arguments")
418    }};
419    (@kontinue $salf:ident, $ty_var:ident, $lhs:ident, $rhs:ident, $conv:ident, $first_ty:ident | $($ty:ident)|+, {$sign:tt}, $final_val:ident) => {
420        bin_op!(@kontinue $salf, $ty_var, $lhs, $rhs, $conv, $first_ty, {$sign}, $final_val);
421        bin_op!(@kontinue $salf, $ty_var, $lhs, $rhs, $conv, $($ty)|+, {$sign}, $final_val);
422    };
423    (@kontinue $salf:ident, $ty:ident, $lhs:ident, $rhs:ident, $conv:ident, SignedInt, {$sign:tt}, $final_val:ident) => {
424        if let Type::Int { width, is_signed } = $ty {
425            // We assume in the match below that pointer-sized ints are 64 bits
426            assert_eq!($salf.read().arch.pointer_size(), 64);
427            use IntWidth::*;
428            match (width, is_signed) {
429                (W8, true) => bin_op!(@out $final_val, $conv, i8, $lhs, $rhs, {$sign}),
430                (W16, true) => bin_op!(@out $final_val, $conv, i16, $lhs, $rhs, {$sign}),
431                (W32, true) => bin_op!(@out $final_val, $conv, i32, $lhs, $rhs, {$sign}),
432                (W64, true) | (Pointer, true) => bin_op!(@out $final_val, $conv, i64, $lhs, $rhs, {$sign}),
433                _ => {},
434            }
435        }
436    };
437    (@kontinue $salf:ident, $ty:ident, $lhs:ident, $rhs:ident, $conv:ident, UnsignedInt, {$sign:tt}, $final_val:ident) => {
438        if let Type::Int { width, is_signed } = $ty {
439            // We assume in the match below that pointer-sized ints are 64 bits
440            assert_eq!($salf.read().arch.pointer_size(), 64);
441            use IntWidth::*;
442            match (width, is_signed) {
443                (W8, false) => bin_op!(@out $final_val, $conv, u8, $lhs, $rhs, {$sign}),
444                (W16, false) => bin_op!(@out $final_val, $conv, u16, $lhs, $rhs, {$sign}),
445                (W32, false) => bin_op!(@out $final_val, $conv, u32, $lhs, $rhs, {$sign}),
446                (W64, false) | (Pointer, false) => bin_op!(@out $final_val, $conv, u64, $lhs, $rhs, {$sign}),
447                _ => {},
448            }
449        }
450    };
451    (@kontinue $salf:ident, $ty:ident, $lhs:ident, $rhs:ident, $conv:ident, Float, {$sign:tt}, $final_val:ident) => {
452        if let Type::Float(width) = $ty {
453            match width {
454                FloatWidth::W32 => bin_op!(@out $final_val, $conv, f32, $lhs, $rhs, {$sign}),
455                FloatWidth::W64 => bin_op!(@out $final_val, $conv, f64, $lhs, $rhs, {$sign}),
456            }
457        }
458    };
459    (@kontinue $salf:ident, $ty:ident, $lhs:ident, $rhs:ident, $conv:ident, Bool, {$sign:tt}, $final_val:ident) => {
460        if let Type::Bool = $ty {
461            bin_op!(@out $final_val, $conv, bool, $lhs, $rhs, {$sign});
462        }
463    };
464    (@kontinue $salf:ident, $ty:ident, $lhs:ident, $rhs:ident, $conv:ident, Int, {$sign:tt}, $final_val:ident) => {
465        bin_op!(@kontinue $salf, $ty, $lhs, $rhs, $conv, UnsignedInt | SignedInt, {$sign}, $final_val);
466    };
467    (@preamble $salf:ident, $stack:ident, $args:ident, $lhs:ident, $rhs:ident, $ty:ident, $final_val:ident) => {
468        let frame = $stack.last().unwrap();
469        assert_eq!($args.len(), 2);
470        let ($lhs, $rhs) = ($args[0], $args[1]);
471        let salf = $salf.read();
472        let $ty = salf.type_of($lhs);
473        assert_eq!($ty, $salf.read().type_of($rhs));
474        let ($lhs, $rhs) = (frame.get_val($lhs, &*$salf.read()), frame.get_val($rhs, &*$salf.read()));
475        let mut $final_val = None;
476    };
477    (@out $final_val:ident, no_convert, $ty:ident, $lhs:ident, $rhs:ident, {$sign:tt}) => {
478        paste!($final_val = Some($lhs.[<as_ $ty>]() $sign $rhs.[<as_ $ty>]()));
479    };
480    (@out $final_val:ident, convert, $ty:ident, $lhs:ident, $rhs:ident, {$sign:tt}) => {
481        paste!($final_val = Some(Value::[<from_ $ty>]($lhs.[<as_ $ty>]() $sign $rhs.[<as_ $ty>]())))
482    };
483    (@out $final_val:ident, bool_convert, $ty:ident, $lhs:ident, $rhs:ident, {$sign:tt}) => {
484        paste!($final_val = Some(Value::from_bool($lhs.[<as_ $ty>]() $sign $rhs.[<as_ $ty>]())))
485    };
486}
487
488#[cfg_attr(not(windows), allow(unused))]
489extern "C" fn interp_ffi_entry_point(func: u32, params: *const *const (), return_value_addr: *mut ()) {
490    let func_id = FuncId::new(func as usize);
491
492    let mut driver = DriverRef::new(&DRIVER);
493
494    let func_ty = driver.read().code.mir.functions[func_id].ty.clone();
495    let return_ty = func_ty.return_ty.as_ref().clone();
496    let mut arguments = Vec::with_capacity(func_ty.param_tys.len());
497    macro_rules! get_param {
498        ($index:ident) => {
499            unsafe {
500                **(params.add($index) as *const *const _)
501            }
502        }
503    }
504    for (i, ty) in func_ty.param_tys.iter().enumerate() {
505        let val = match ty {
506            Type::Int { width: IntWidth::W8, .. } => Value::from_u8(get_param!(i)),
507            Type::Int { width: IntWidth::W16, .. } => Value::from_u16(get_param!(i)),
508            Type::Int { width: IntWidth::W32, .. } => Value::from_u32(get_param!(i)),
509            Type::Int { width: IntWidth::W64 | IntWidth::Pointer, .. } | Type::Pointer(_) => {
510                assert_eq!(driver.read().arch.pointer_size(), 64);
511                Value::from_u64(get_param!(i))
512            },
513            _ => todo!("parameter type {:?}", ty),
514        };
515        arguments.push(val);
516    }
517    let return_value = driver.call(FunctionRef::Id(func_id), arguments, Vec::new());
518    macro_rules! set_ret_val {
519        ($val:expr) => {
520            unsafe {
521                *(return_value_addr as *mut _) = $val;
522            }
523        }
524    }
525    match return_ty {
526        Type::Int { width: IntWidth::W8, .. } => set_ret_val!(return_value.as_u8()),
527        Type::Int { width: IntWidth::W16, .. } => set_ret_val!(return_value.as_u16()),
528        Type::Int { width: IntWidth::W32, .. } => set_ret_val!(return_value.as_u32()),
529        Type::Int { width: IntWidth::W64 | IntWidth::Pointer, .. } | Type::Pointer(_) => {
530            assert_eq!(driver.read().arch.pointer_size(), 64);
531            set_ret_val!(return_value.as_u64());
532        },
533        _ => todo!("parameter type {:?}", return_ty),
534    }
535}
536
537// Thank you, Hagen von Eitzen: https://math.stackexchange.com/a/291494
538#[cfg(windows)]
539fn nearest_multiple_of_16(val: i32) -> i32 { ((val - 1) | 15) + 1 }
540#[cfg(windows)]
541fn nearest_multiple_of_8(val: i32) -> i32 { ((val - 1) | 7) + 1 }
542
543impl Driver {
544    pub fn value_to_const(&mut self, val: Value, ty: Type, tp: &impl TypeProvider) -> Const {
545        match ty {
546            Type::Int { is_signed, .. } => {
547                let lit = val.as_big_int(is_signed);
548                Const::Int { lit, ty }
549            },
550            Type::Float(width) => {
551                let lit = match width {
552                    FloatWidth::W32 => val.as_f32() as f64,
553                    FloatWidth::W64 => val.as_f64(),
554                };
555                Const::Float { lit, ty }
556            },
557            Type::Bool => Const::Bool(val.as_bool()),
558            Type::Pointer(ref pointee) => {
559                assert!(!pointee.is_mut);
560                assert!(pointee.ty == Type::i8() || pointee.ty == Type::u8());
561                #[cfg(debug_assertions)]
562                println!("NOTICE: about to blindly copy a pointer into the global strings!");
563                let string = unsafe { CString::from(CStr::from_ptr(val.as_raw_ptr() as *const _)) };
564                let id = self.code.mir.strings.push(string);
565                Const::Str { id, ty }
566            },
567            Type::Ty => Const::Ty(val.as_ty()),
568            Type::Mod => Const::Mod(val.as_mod()),
569            Type::Struct(strukt) => {
570                let layout = self.layout_struct(&strukt);
571                let buf = val.as_bytes();
572                let mut fields = Vec::new();
573                for i in 0..strukt.field_tys.len() {
574                    let offset = layout.field_offsets[i];
575                    let ty = strukt.field_tys[i].clone();
576                    let size = self.size_of(&ty);
577                    let val = Value::from_bytes(&buf[offset..(offset+size)]);
578                    let konst = self.value_to_const(val, ty.clone(), tp);
579                    fields.push(konst);
580                }
581                Const::StructLit { fields, id: strukt.identity }
582            },
583            Type::Enum(enuum) => {
584                let enum_val = &self.code.hir.enums[enuum];
585                let valid = enum_val.variants.iter().map(|variant| variant.payload_ty).all(|ty| ty.is_none());
586                assert!(valid, "In order to output vaue of type {:?} as constant, it must not have any payloads", Type::Enum(enuum));
587                Const::BasicVariant { enuum, index: val.as_enum().discriminant as usize }
588            },
589            Type::Void => Const::Void,
590            Type::Internal(InternalType::StringLiteral) => match val.as_internal() {
591                InternalValue::StrLit(string) => Const::StrLit(string.clone()),
592                _ => panic!("unexpected non-StrLit in StringLiteral"),
593            },
594            _ => panic!("Can't output value of type `{:?}` as constant", ty),
595        }
596    }
597
598    fn new_stack_frame(&self, func_ref: FunctionRef, arguments: Vec<Value>, generic_arguments: Vec<Type>) -> StackFrame {
599        let func = function_by_ref(&self.code.mir, &func_ref);
600
601        let mut results = IndexVec::new();
602
603        let num_parameters = self.code.num_parameters(func);
604        if num_parameters != arguments.len() {
605            let interner = &self.interner;
606            let func_name = func.name.map(|name| interner.resolve(name).unwrap()).unwrap_or("<anonymous func>");
607            panic!(
608                "Compiler bug! Tried to call {} with {} arguments, but {} were expected.",
609                func_name,
610                arguments.len(),
611                num_parameters
612            );
613        }
614        let start_block = func.blocks[0];
615        results.push(Value::Nothing); // void
616        for (i, arg) in arguments.into_iter().enumerate() {
617            let op = self.code.blocks[start_block].ops[i];
618            let param = self.code.ops[op].as_mir_instr().unwrap();
619            assert!(matches!(param, Instr::Parameter(_)));
620            results.push(arg);
621        }
622        results.resize_with(func.num_instrs, || Value::Nothing);
623
624        let mut generic_ctx = HashMap::new();
625        assert_eq!(func.generic_params.len(), generic_arguments.len());
626        for (&generic_param, generic_argument) in func.generic_params.iter().zip(generic_arguments) {
627            generic_ctx.insert(generic_param, generic_argument);
628        }
629
630        StackFrame {
631            func_ref,
632            block: start_block,
633            pc: num_parameters,
634            generic_ctx,
635            results,
636        }
637    }
638
639    #[display_adapter]
640    pub fn stack_trace(&self, stack: &[StackFrame], f: &mut Formatter) {
641        for (i, frame) in stack.iter().rev().enumerate() {
642            let func = function_by_ref(&self.code.mir, &frame.func_ref);
643            writeln!(f, "{}: {}", i, self.fn_name(func.name))?;
644        }
645        Ok(())
646    }
647}
648
649impl DriverRef<'_> {
650    pub fn set_command_line_arguments(&mut self, args: &[OsString]) {
651        INTERP.write().unwrap().command_line_args = args.iter().map(|arg| {
652            CString::new(arg.to_string_lossy().as_bytes()).unwrap()
653        }).collect();
654    }
655    pub fn call(&mut self, func_ref: FunctionRef, arguments: Vec<Value>, generic_arguments: Vec<Type>) -> Value {
656        let frame = self.read().new_stack_frame(func_ref, arguments, generic_arguments);
657        INTERP_STACK.with(|stack| {
658            stack.borrow_mut().push(frame);
659            loop {
660                // TODO: I don't love the fact that I repeatedly borrow the RefCell here...
661                if let Some(val) = self.execute_next(stack) {
662                    stack.borrow_mut().pop().unwrap();
663                    return val;
664                }
665            }
666        })
667    }
668}
669
670impl Driver {
671    /// Generates a so-called "inverse thunk", which is a native function with the appropriate calling convention for
672    /// func, which accepts all of func's parameters, allocates space on the stack for func's return value, and calls
673    /// into the interpreter. It then returns the value given by the interpreter. For example, given the following Dusk
674    /// function:
675    ///     ```dusk
676    ///     fn add(a: u32, b: u32): u32 { a + b }
677    ///     ```
678    /// `fetch_inverse_thunk` would generate a thunk that closely corresponds to the following C code:
679    ///     ```c
680    ///     #include <stdint.h>
681    ///     #define ADD_FUNC_ID (insert the FuncId of add here)
682    ///     uint32_t add(uint32_t a, uint32_t b) {
683    ///         void* parameters[] = {&a, &b};
684    ///         int return_value;
685    ///         interp_ffi_entry_point(ADD_FUNC_ID, parameters, &return_value);
686    ///         return return_value;
687    ///     }
688    ///     ```
689    #[cfg(windows)]
690    pub fn fetch_inverse_thunk(&self, func_id: FuncId) -> Value {
691        if let Some(alloc) = INTERP.read().unwrap().inverse_thunk_cache.get(&func_id) {
692            return Value::from_usize(alloc.0.as_ptr::<()>() as usize);
693        }
694
695        let func = &self.code.mir.functions[func_id];
696        let param_tys = func.ty.param_tys.clone();
697
698        let mut thunk = X64Encoder::new();
699        // Store the first four parameters in shadow space in reverse order
700        for (i, param_ty) in param_tys.iter().take(4).enumerate().rev() {
701            let offset = (i as i32 + 1) * 8;
702            match *param_ty {
703                Type::Int { width: IntWidth::W16, .. } => {
704                    // Store i'th argument as 16-bit value
705                    let registers = [Reg16::Cx, Reg16::Dx, Reg16::R8w, Reg16::R9w];
706                    thunk.store16(Reg64::Rsp + offset, registers[i]);
707                },
708                Type::Int { width: IntWidth::W32, .. } => {
709                    // Store i'th argument as 32-bit value
710                    let registers = [Reg32::Ecx, Reg32::Edx, Reg32::R8d, Reg32::R9d];
711                    thunk.store32(Reg64::Rsp + offset, registers[i]);
712                },
713                Type::Pointer(_) | Type::Int { width: IntWidth::W64 | IntWidth::Pointer, .. } => {
714                    assert_eq!(self.arch.pointer_size(), 64);
715                    // Store i'th argument as 64-bit value
716                    let registers = [Reg64::Rcx, Reg64::Rdx, Reg64::R8, Reg64::R9];
717                    thunk.store64(Reg64::Rsp + offset, registers[i]);
718                },
719                _ => todo!("parameter type {:?}", param_ty),
720            }
721        }
722        let param_address_array_space = param_tys.len() as i32 * 8;
723        // round up to the nearest multiple of 8 if necessary, to make sure that the parameter address array is 8-byte
724        // aligned.
725        let return_value_space = nearest_multiple_of_8(self.size_of(&func.ty.return_ty) as i32);
726        assert!(return_value_space <= 8, "return values bigger than 8 bytes are not yet supported in inverse thunks!");
727        let call_space = 4 * 8;
728        let total_stack_allocation = nearest_multiple_of_16(param_address_array_space + return_value_space + call_space) + 8;
729        let return_value_offset = call_space;
730        let param_address_array_offset = return_value_offset + return_value_space;
731        let shadow_offset = total_stack_allocation + 8;
732
733        // Allocate the necessary space on the stack
734        thunk.sub64_imm(Reg64::Rsp, total_stack_allocation);
735
736        // Fill the parameter array with the addresses of each parameter.
737        for (i, param_ty) in param_tys.iter().enumerate() {
738            let rsp_offset = i as i32 * 8;
739            // Get the address
740            if self.size_of(param_ty) > 8 {
741                // If the value is larger than 64 bits, it was passed by address. Therefore, we should load this
742                // address from shadow space directly, instead of loading the address of the address.
743                thunk.load64(Reg64::Rax, Reg64::Rsp + shadow_offset + rsp_offset)
744            } else {
745                thunk.lea64(Reg64::Rax, Reg64::Rsp + shadow_offset + rsp_offset);
746            }
747            // Store the address in the array.
748            thunk.store64(Reg64::Rsp + param_address_array_offset + rsp_offset, Reg64::Rax);
749        }
750
751        // Pass arguments to interpreter entry point
752        thunk.lea64(Reg64::R8, Reg64::Rsp + return_value_offset);
753        thunk.lea64(Reg64::Rdx, Reg64::Rsp + param_address_array_offset);
754        thunk.mov32_imm(Reg32::Ecx, func_id.index() as i32);
755
756        // Call interp_ffi_entry_point
757        thunk.movabs(Reg64::Rax, (interp_ffi_entry_point as usize as isize).try_into().unwrap());
758        thunk.call_direct(Reg64::Rax);
759
760        // Move return value into *ax
761        match &*func.ty.return_ty {
762            Type::Int { width: IntWidth::W16, .. } => thunk.load16(Reg16::Ax, Reg64::Rsp + return_value_offset),
763            Type::Int { width: IntWidth::W32, .. } => thunk.load32(Reg32::Eax, Reg64::Rsp + return_value_offset),
764            Type::Pointer(_) | Type::Int { width: IntWidth::W64 | IntWidth::Pointer, .. } => {
765                assert_eq!(self.arch.pointer_size(), 64);
766                thunk.load64(Reg64::Rax, Reg64::Rsp + return_value_offset);
767            },
768            _ if self.size_of(&func.ty.return_ty) == 0 => {},
769            _ => todo!("return type {:?}", func.ty.return_ty),
770        }
771
772        // Return the stack to its previous state
773        thunk.add64_imm(Reg64::Rsp, total_stack_allocation);
774        
775        // Return
776        thunk.ret();
777
778        let thunk = thunk.allocate();
779        let val = Value::from_usize(thunk.as_ptr::<u8>() as usize);
780        INTERP.write().unwrap().inverse_thunk_cache.insert(func_id, Allocation(thunk));
781
782        val
783    }
784    #[cfg(not(windows))]
785    pub fn fetch_inverse_thunk(&self, _func_id: FuncId) -> Value {
786        panic!("getting a function pointer to a Dusk function is not yet supported on non-Windows platforms");
787    }
788}
789
790#[cfg(windows)]
791unsafe fn open_dylib(path: *const i8) -> *mut c_void {
792    winapi::um::libloaderapi::LoadLibraryA(path) as *mut _
793}
794#[cfg(not(windows))]
795unsafe fn open_dylib(path: *const i8) -> *mut c_void {
796    libc::dlopen(path, libc::RTLD_LAZY)
797}
798#[cfg(windows)]
799unsafe fn get_dylib_symbol(dylib: *mut c_void, name: *const i8) -> *const c_void {
800    winapi::um::libloaderapi::GetProcAddress(dylib as *mut _, name) as *const _
801}
802#[cfg(not(windows))]
803unsafe fn get_dylib_symbol(dylib: *mut c_void, name: *const i8) -> *const c_void {
804    libc::dlsym(dylib, name)
805}
806#[cfg(windows)]
807unsafe fn free_dylib(dylib: *mut c_void) {
808    winapi::um::libloaderapi::FreeLibrary(dylib as *mut _);
809}
810#[cfg(not(windows))]
811unsafe fn free_dylib(dylib: *mut c_void) {
812    libc::dlclose(dylib);
813}
814
815impl DriverRef<'_> {
816    #[cfg(windows)]
817    #[cfg(target_arch="x86_64")]
818    fn generate_thunk(&self, func: &ExternFunction, func_address: i64, args: &[Box<[u8]>]) -> region::Allocation {
819        let mut thunk = X64Encoder::new();
820        thunk.store64(Reg64::Rsp + 16, Reg64::Rdx);
821        thunk.store64(Reg64::Rsp + 8, Reg64::Rcx);
822
823        let mut extension: i32 = 40;
824        if args.len() > 4 {
825            extension += ((args.len() - 3) / 2 * 16) as i32;
826        }
827        thunk.sub64_imm(Reg64::Rsp, extension);
828
829        assert_eq!(args.len(), func.ty.param_tys.len());
830        for i in (0..args.len()).rev() {
831            // get pointer to arguments
832            thunk.load64(Reg64::Rax, Reg64::Rsp + extension + 8);
833
834            // get pointer to i'th argument
835            thunk.load64(Reg64::Rax, Reg64::Rax + (i as i32 * 8));
836
837            match func.ty.param_tys[i] {
838                Type::Int { width: IntWidth::W16, .. } => {
839                    // Read i'th argument as 16-bit value
840                    let registers = [Reg16::Cx, Reg16::Dx, Reg16::R8w, Reg16::R9w, Reg16::Ax];
841                    thunk.load16(registers[min(i, 4)], Reg64::Rax);
842
843                    // If this is one of the first four parameters, then we're done. Otherwise, we must store the parameter on the stack.
844                    if i >= 4 {
845                        let offset = (32 + (i-4) * 8) as i32;
846                        thunk.store16(Reg64::Rsp + offset, Reg16::Ax);
847                    }
848                },
849                Type::Int { width: IntWidth::W32, .. } => {
850                    // Read i'th argument as 32-bit value
851                    let registers = [Reg32::Ecx, Reg32::Edx, Reg32::R8d, Reg32::R9d, Reg32::Eax];
852                    thunk.load32(registers[min(i, 4)], Reg64::Rax);
853
854                    // If this is one of the first four parameters, then we're done. Otherwise, we must store the parameter on the stack.
855                    if i >= 4 {
856                        let offset = (32 + (i-4) * 8) as i32;
857                        thunk.store32(Reg64::Rsp + offset, Reg32::Eax);
858                    }
859                },
860                Type::Pointer(_) | Type::Int { width: IntWidth::W64 | IntWidth::Pointer, .. } => {
861                    assert_eq!(self.read().arch.pointer_size(), 64);
862                    // Read i'th argument as 64-bit value
863                    let registers = [Reg64::Rcx, Reg64::Rdx, Reg64::R8, Reg64::R9, Reg64::Rax];
864                    thunk.load64(registers[min(i, 4)], Reg64::Rax);
865
866                    // If this is one of the first four parameters, then we're done. Otherwise, we must store the parameter on the stack.
867                    if i >= 4 {
868                        let offset = (32 + (i-4) * 8) as i32;
869                        thunk.store64(Reg64::Rsp + offset, Reg64::Rax);
870                    }
871                },
872                _ => todo!("parameter type {:?}", func.ty.param_tys[i]),
873            }
874        }
875
876        // Call function
877        thunk.movabs(Reg64::R10, func_address);
878        thunk.call_direct(Reg64::R10);
879
880        // get pointer to return value
881        thunk.load64(Reg64::Rcx, Reg64::Rsp + extension + 16);
882
883        // TODO: large values require passing a pointer as the first parameter
884        // copy return value to the passed in location
885        match &*func.ty.return_ty {
886            Type::Int { width: IntWidth::W16, .. } => thunk.store16(Reg64::Rcx, Reg16::Ax),
887            Type::Int { width: IntWidth::W32, .. } => thunk.store32(Reg64::Rcx, Reg32::Eax),
888            Type::Pointer(_) | Type::Int { width: IntWidth::W64 | IntWidth::Pointer, .. } => {
889                assert_eq!(self.read().arch.pointer_size(), 64);
890                thunk.store64(Reg64::Rcx, Reg64::Rax);
891            },
892            _ => todo!("return type {:?}", func.ty.return_ty),
893        }
894
895        thunk.add64_imm(Reg64::Rsp, extension);
896        thunk.ret();
897
898        thunk.allocate()
899    }
900    #[cfg(unix)]
901    #[cfg(target_arch="x86_64")]
902    fn generate_thunk(&self, func: &ExternFunction, func_address: i64, args: &[Box<[u8]>]) -> region::Allocation {
903        let mut thunk = X64Encoder::new();
904        thunk.push64(Reg64::Rbp);
905        thunk.mov64(Reg64::Rbp, Reg64::Rsp);
906
907        // Copy the two arguments to the stack
908        let extension = 16;
909        thunk.sub64_imm(Reg64::Rsp, extension);
910        thunk.store64(Reg64::Rbp - 8, Reg64::Rdi);
911        thunk.store64(Reg64::Rbp - 16, Reg64::Rsi);
912
913        assert!(args.len() <= 6, "more than 6 arguments are not yet supported on UNIX platforms");
914        assert_eq!(args.len(), func.ty.param_tys.len());
915        for i in 0..args.len() {
916            // get pointer to arguments
917            thunk.load64(Reg64::Rax, Reg64::Rbp - 8);
918
919            // get pointer to i'th argument
920            thunk.load64(Reg64::Rax, Reg64::Rax + (i as i32 * 8));
921
922            match func.ty.param_tys[i] {
923                Type::Int { width: IntWidth::W16, .. } => {
924                    // Read i'th argument as 16-bit value
925                    let registers = [Reg16::Di, Reg16::Si, Reg16::Dx, Reg16::Cx, Reg16::R8w, Reg16::R9w];
926                    thunk.load16(registers[i], Reg64::Rax);
927                },
928                Type::Int { width: IntWidth::W32, .. } => {
929                    // Read i'th argument as 32-bit value
930                    let registers = [Reg32::Edi, Reg32::Esi, Reg32::Edx, Reg32::Ecx, Reg32::R8d, Reg32::R9d];
931                    thunk.load32(registers[i], Reg64::Rax);
932                },
933                Type::Pointer(_) | Type::Int { width: IntWidth::W64 | IntWidth::Pointer, .. } => {
934                    assert_eq!(self.read().arch.pointer_size(), 64);
935                    // Read i'th argument as 64-bit value
936                    let registers = [Reg64::Rdi, Reg64::Rsi, Reg64::Rdx, Reg64::Rcx, Reg64::R8, Reg64::R9];
937                    thunk.load64(registers[i], Reg64::Rax);
938                },
939                _ => todo!("parameter type {:?}", func.ty.param_tys[i]),
940            }
941        }
942
943        // Call the function
944        thunk.movabs(Reg64::R10, func_address);
945        thunk.call_direct(Reg64::R10);
946
947        // get pointer to return value
948        if !matches!(*func.ty.return_ty, Type::Void) {
949            thunk.load64(Reg64::Rcx, Reg64::Rbp - 16);
950        }
951
952        match &*func.ty.return_ty {
953            Type::Int { width: IntWidth::W16, .. } => thunk.store16(Reg64::Rcx, Reg16::Ax),
954            Type::Int { width: IntWidth::W32, .. } => thunk.store32(Reg64::Rcx, Reg32::Eax),
955            Type::Pointer(_) | Type::Int { width: IntWidth::W64 | IntWidth::Pointer, .. } => {
956                assert_eq!(self.read().arch.pointer_size(), 64);
957                thunk.store64(Reg64::Rcx, Reg64::Rax);
958            },
959            Type::Void => {},
960
961            _ => todo!("return type {:?}", func.ty.return_ty),
962        }
963
964        thunk.add64_imm(Reg64::Rsp, extension);
965        thunk.pop64(Reg64::Rbp);
966        thunk.ret();
967
968        thunk.allocate()
969    }
970    pub fn extern_call(&self, func_ref: ExternFunctionRef, mut args: Vec<Box<[u8]>>) -> Value {
971        let indirect_args: Vec<*mut u8> = args.iter_mut()
972            .map(|arg| arg.as_mut_ptr())
973            .collect();
974        
975        let library = &self.read().code.mir.extern_mods[&func_ref.extern_mod];
976        let func = &library.imported_functions[func_ref.index];
977        // TODO: cache library and proc addresses (and thunks, for that matter)
978        let dylib = unsafe { open_dylib(library.library_path.as_ptr()) };
979        if dylib.is_null() {
980            panic!("unable to load library {:?}", library.library_path);
981        }
982        let func_name = CString::new(func.name.clone()).unwrap();
983        let func_ptr = unsafe { get_dylib_symbol(dylib, func_name.as_ptr()) };
984        if func_ptr.is_null() {
985            panic!("unable to load function {:?} from library {:?}", func_name, library.library_path);
986        }
987        let func_address: i64 = func_ptr as i64;
988        
989        let thunk = self.generate_thunk(func, func_address, &args);
990        unsafe {
991            let thunk_ptr = thunk.as_ptr::<u8>();
992            type Thunk = fn(*const *mut u8, *mut u8);
993            let thunk: Thunk = mem::transmute(thunk_ptr);
994            let mut return_val_storage = SmallVec::new();
995            return_val_storage.resize(self.read().size_of(&func.ty.return_ty), 0);
996            thunk(indirect_args.as_ptr(), return_val_storage.as_mut_ptr());
997
998            free_dylib(dylib);
999
1000            Value::Inline(return_val_storage)
1001        }
1002    }
1003}
1004
1005impl Driver {
1006    #[display_adapter]
1007    fn panic_message(&self, stack: &[StackFrame], msg: Option<OpId>, f: &mut Formatter) {
1008        let frame = stack.last().unwrap();
1009        let msg = msg.map(|msg| frame.get_val(msg, self).as_raw_ptr());
1010        write!(f, "Userspace panic")?;
1011        if let Some(mut msg) = msg {
1012            write!(f, ": ")?;
1013            unsafe {
1014                while *msg != 0 {
1015                    write!(f, "{}", *msg as char)?;
1016                    msg = msg.offset(1);
1017                }
1018            }
1019        }
1020        writeln!(f, "\nStack trace:")?;
1021        writeln!(indented(f), "{}", self.stack_trace(stack))?;
1022        Ok(())
1023    }
1024}
1025
1026impl DriverRef<'_> {
1027    /// Execute the next instruction. Iff the instruction is a return, this function returns its `Value`. Otherwise, it returns `None`.
1028    fn execute_next(&mut self, stack_cell: &RefCell<Vec<StackFrame>>) -> Option<Value> {
1029        let val = {
1030            let mut stack = stack_cell.borrow_mut();
1031            let frame = stack.last_mut().unwrap();
1032            let next_op = self.read().code.blocks[frame.block].ops[frame.pc];
1033            let d = self.read();
1034            match d.code.ops[next_op].as_mir_instr().unwrap() {
1035                Instr::Void => Value::Nothing,
1036                Instr::Const(konst) => Value::from_const(&konst.clone(), &*self.read()),
1037                Instr::Alloca(ty) => {
1038                    let mut storage = Vec::new();
1039                    storage.resize(self.read().size_of(ty), 0);
1040                    Value::Dynamic(storage.into_boxed_slice())
1041                },
1042                &Instr::LogicalNot(val) => {
1043                    let val = frame.get_val(val, &*self.read()).as_bool();
1044                    Value::from_bool(!val)
1045                },
1046                &Instr::FunctionRef { ref generic_arguments, func } => {
1047                    Value::from_internal(InternalValue::FunctionPointer { generic_arguments: generic_arguments.clone(), func })
1048                },
1049                &Instr::Call { ref arguments, ref generic_arguments, func } => {
1050                    let mut copied_args = Vec::new();
1051                    copied_args.reserve_exact(arguments.len());
1052                    for &arg in arguments {
1053                        copied_args.push(frame.get_val(arg, &*self.read()).clone());
1054                    }
1055                    let generic_arguments = generic_arguments.clone();
1056                    // Stop immutably borrowing the stack, so it can be borrowed again in call()
1057                    drop(stack);
1058                    drop(d);
1059                    self.call(FunctionRef::Id(func), copied_args, generic_arguments)
1060                },
1061                &Instr::ExternCall { ref arguments, func } => {
1062                    let mut copied_args = Vec::new();
1063                    copied_args.reserve_exact(arguments.len());
1064                    for &arg in arguments {
1065                        copied_args.push(frame.get_val(arg, &*self.read()).as_bytes().as_ref().to_owned().into_boxed_slice());
1066                    }
1067                    // Stop immutably borrowing the stack, because there may come a time where extern functions can transparently call into the interpreter
1068                    drop(stack);
1069                    drop(d);
1070                    self.read_only();
1071                    self.extern_call(func, copied_args)
1072                },
1073                &Instr::GenericParam(id) => {
1074                    let ty = Type::GenericParam(id);
1075                    Value::from_ty(frame.canonicalize_type(&ty))
1076                },
1077                &Instr::Intrinsic { ref arguments, intr, .. } => {
1078                    match intr {
1079                        Intrinsic::Mult => bin_op!(self, stack, arguments, convert, Int | Float, {*}),
1080                        Intrinsic::Div => bin_op!(self, stack, arguments, convert, Int | Float, {/}),
1081                        Intrinsic::Mod => bin_op!(self, stack, arguments, convert, Int | Float, {%}),
1082                        Intrinsic::Add => bin_op!(self, stack, arguments, convert, Int | Float, {+}),
1083                        Intrinsic::Sub => bin_op!(self, stack, arguments, convert, Int | Float, {-}),
1084                        Intrinsic::Less => bin_op!(self, stack, arguments, bool_convert, Int | Float, {<}),
1085                        Intrinsic::LessOrEq => bin_op!(self, stack, arguments, bool_convert, Int | Float, {<=}),
1086                        Intrinsic::Greater => bin_op!(self, stack, arguments, bool_convert, Int | Float, {>}),
1087                        Intrinsic::GreaterOrEq => bin_op!(self, stack, arguments, bool_convert, Int | Float, {>=}),
1088                        Intrinsic::Eq => {
1089                            let ty = d.type_of(arguments[0]);
1090                            match ty {
1091                                Type::Enum(_) => {
1092                                    assert_eq!(arguments.len(), 2);
1093                                    let frame = stack.last().unwrap();
1094                                    let a = frame.get_val(arguments[0], &*self.read());
1095                                    let b = frame.get_val(arguments[1], &*self.read());
1096                                    let a = a.as_big_int(false);
1097                                    let b = b.as_big_int(false);
1098                                    Value::from_bool(a == b)
1099                                }
1100                                _ => bin_op!(self, stack, arguments, bool_convert, Int | Float | Bool, {==}),
1101                            }
1102                        },
1103                        Intrinsic::NotEq => {
1104                            let ty = d.type_of(arguments[0]);
1105                            match ty {
1106                                Type::Enum(_) => {
1107                                    assert_eq!(arguments.len(), 2);
1108                                    let frame = stack.last().unwrap();
1109                                    let a = frame.get_val(arguments[0], &*self.read());
1110                                    let b = frame.get_val(arguments[1], &*self.read());
1111                                    let a = a.as_big_int(false);
1112                                    let b = b.as_big_int(false);
1113                                    Value::from_bool(a != b)
1114                                }
1115                                _ => bin_op!(self, stack, arguments, bool_convert, Int | Float | Bool, {!=}),
1116                            }
1117                        },
1118                        Intrinsic::BitwiseAnd => bin_op!(self, stack, arguments, convert, Int | Bool, {&}),
1119                        Intrinsic::BitwiseOr => bin_op!(self, stack, arguments, convert, Int | Bool, {|}),
1120                        Intrinsic::BitwiseXor => bin_op!(self, stack, arguments, convert, Int | Bool, {^}),
1121                        Intrinsic::LeftShift => bin_op!(self, stack, arguments, convert, Int, {<<}),
1122                        Intrinsic::RightShift => bin_op!(self, stack, arguments, convert, Int, {>>}),
1123                        Intrinsic::LogicalNot => panic!("Unexpected logical not intrinsic, should've been replaced by instruction"),
1124                        Intrinsic::Neg => {
1125                            assert_eq!(arguments.len(), 1);
1126                            let frame = stack.last().unwrap();
1127                            let arg = arguments[0];
1128                            let ty = d.type_of(arg);
1129                            let arg = frame.get_val(arg, &*self.read());
1130                            match *ty {
1131                                Type::Int { width, is_signed } => {
1132                                    Value::from_big_int(-arg.as_big_int(is_signed), width, is_signed, self.read().arch)
1133                                },
1134                                Type::Float(width) => match width {
1135                                    FloatWidth::W32 => Value::from_f32(-arg.as_f32()),
1136                                    FloatWidth::W64 => Value::from_f64(-arg.as_f64()),
1137                                },
1138                                _ => panic!("Unexpected type for intrinsic arguments"),
1139                            }
1140                        },
1141                        Intrinsic::BitwiseNot => {
1142                            assert_eq!(arguments.len(), 1);
1143                            let arg = arguments[0];
1144                            let ty = d.type_of(arg);
1145                            let arg = frame.get_val(arg, &*self.read());
1146                            match ty {
1147                                &Type::Int { width, .. } => {
1148                                    match width {
1149                                        IntWidth::Pointer | IntWidth::W64 => {
1150                                            assert_eq!(self.read().arch.pointer_size(), 64);
1151                                            Value::from_u64(!arg.as_u64())
1152                                        },
1153                                        IntWidth::W32 => Value::from_u32(!arg.as_u32()),
1154                                        IntWidth::W16 => Value::from_u16(!arg.as_u16()),
1155                                        IntWidth::W8  => Value::from_u8(!arg.as_u8()),
1156                                    }
1157                                },
1158                                _ => panic!("Unexpected type for intrinsic arguments")
1159                            }
1160                        },
1161                        Intrinsic::Pos => {
1162                            assert_eq!(arguments.len(), 1);
1163                            frame.get_val(arguments[0], &*self.read()).clone()
1164                        },
1165                        Intrinsic::Panic => {
1166                            assert!(arguments.len() <= 1);
1167                            panic!("{}", self.read().panic_message(&stack, arguments.first().copied()));
1168                        },
1169                        Intrinsic::Print => {
1170                            let frame = stack.last().unwrap();
1171                            assert_eq!(arguments.len(), 1);
1172                            let id = arguments[0];
1173                            let val = frame.get_val(id, &*self.read());
1174                            let ty = d.type_of(id);
1175                            match ty {
1176                                Type::Pointer(_) => unsafe {
1177                                    let mut ptr = val.as_raw_ptr();
1178                                    while *ptr != 0 {
1179                                        print!("{}", *ptr as char);
1180                                        ptr = ptr.offset(1);
1181                                    }
1182                                },
1183                                Type::Int { .. } => print!("{}", val.as_u8() as char),
1184                                _ => panic!("Unexpected type passed to `print`: {:?}", ty),
1185                            }
1186                            std::io::stdout().flush().unwrap();
1187                            Value::Nothing 
1188                        },
1189                        Intrinsic::Malloc => {
1190                            assert_eq!(arguments.len(), 1);
1191                            assert_eq!(self.read().arch.pointer_size(), 64);
1192                            let size = frame.get_val(arguments[0], &*self.read()).as_u64() as usize;
1193                            let layout = alloc::Layout::from_size_align(size, 8).unwrap();
1194                            let buf = unsafe { alloc::alloc(layout) };
1195                            let address = buf as usize;
1196                            INTERP.write().unwrap().allocations.insert(address, layout);
1197                            Value::from_usize(address)
1198                        }
1199                        Intrinsic::Free => {
1200                            assert_eq!(arguments.len(), 1);
1201                            assert_eq!(self.read().arch.pointer_size(), 64);
1202                            let ptr = frame.get_val(arguments[0], &*self.read()).as_raw_ptr();
1203                            let address = ptr as usize;
1204                            let layout = INTERP.write().unwrap().allocations.remove(&address).unwrap();
1205                            unsafe { alloc::dealloc(ptr, layout) };
1206                            Value::Nothing
1207                        },
1208                        Intrinsic::PrintType => {
1209                            let frame = stack.last().unwrap();
1210                            assert_eq!(arguments.len(), 1);
1211                            let ty = frame.get_val(arguments[0], &*self.read()).as_ty();
1212                            let ty = frame.canonicalize_type(&ty);
1213                            print!("{:?}", ty);
1214                            Value::Nothing
1215                        },
1216                        Intrinsic::AlignOf => {
1217                            let frame = stack.last().unwrap();
1218                            assert_eq!(arguments.len(), 1);
1219                            let ty = frame.get_val(arguments[0], &*self.read()).as_ty();
1220                            let ty = frame.canonicalize_type(&ty);
1221                            Value::from_usize(self.read().align_of(&ty))
1222                        },
1223                        Intrinsic::StrideOf => {
1224                            let frame = stack.last().unwrap();
1225                            assert_eq!(arguments.len(), 1);
1226                            let ty = frame.get_val(arguments[0], &*self.read()).as_ty();
1227                            let ty = frame.canonicalize_type(&ty);
1228                            Value::from_usize(self.read().stride_of(&ty))
1229                        },
1230                        Intrinsic::SizeOf => {
1231                            let frame = stack.last().unwrap();
1232                            assert_eq!(arguments.len(), 1);
1233                            let ty = frame.get_val(arguments[0], &*self.read()).as_ty();
1234                            let ty = frame.canonicalize_type(&ty);
1235                            Value::from_usize(self.read().size_of(&ty))
1236                        },
1237                        Intrinsic::OffsetOf => {
1238                            assert_eq!(arguments.len(), 2);
1239                            let ty = frame.get_val(arguments[0], &*self.read()).as_ty();
1240                            let field_name = unsafe { CStr::from_ptr(frame.get_val(arguments[1], &*self.read()).as_raw_ptr() as *const _) };
1241                            let field_name = self.read().interner.get(field_name.to_str().unwrap());
1242                            let mut offset = None;
1243                            if let Some(field_name) = field_name {
1244                                match ty {
1245                                    Type::Struct(strukt) => {
1246                                        let layout = self.read().layout_struct(&strukt);
1247                                        for (index, field) in self.read().code.hir.structs[strukt.identity].fields.iter().enumerate() {
1248                                            if field_name == field.name {
1249                                                offset = Some(layout.field_offsets[index]);
1250                                                break;
1251                                            }
1252                                        }
1253                                    }
1254                                    _ => panic!("Can't get field offset on a non-struct type"),
1255                                }
1256                            }
1257                            let offset = offset.expect("No such field name in call to offset_of");
1258                            Value::from_usize(offset)
1259                        },
1260                        Intrinsic::GetNumArgs => {
1261                            Value::from_usize(INTERP.read().unwrap().command_line_args.len())
1262                        },
1263                        Intrinsic::GetArg => {
1264                            assert_eq!(arguments.len(), 1);
1265                            let index = frame.get_val(arguments[0], &*self.read()).as_usize();
1266                            let command_line_args = &INTERP.read().unwrap().command_line_args;
1267                            Value::from_internal(InternalValue::StrLit(command_line_args[index].clone()))
1268                        },
1269                        _ => panic!("Call to unimplemented intrinsic {:?}", intr),
1270                    }
1271                },
1272                &Instr::Reinterpret(instr, _) => frame.get_val(instr, &*self.read()).clone(),
1273                &Instr::Truncate(instr, ref ty) => {
1274                    let frame = stack.last().unwrap();
1275                    let bytes = frame.get_val(instr, &*self.read()).as_bytes();
1276                    let new_size = self.read().size_of(ty);
1277                    Value::from_bytes(&bytes[0..new_size])
1278                },
1279                &Instr::SignExtend(val, ref dest_ty) => {
1280                    let frame = stack.last().unwrap();
1281                    let src_ty = d.type_of(val);
1282                    let val = frame.get_val(val, &*self.read());
1283                    match (src_ty, dest_ty) {
1284                        (
1285                            &Type::Int { is_signed: src_is_signed, .. },
1286                            &Type::Int { width: dest_width, is_signed: dest_is_signed }
1287                        ) => Value::from_big_int(val.as_big_int(src_is_signed), dest_width, dest_is_signed, self.read().arch),
1288                        (_, _) => panic!("Invalid operand types to sign extension")
1289                    }
1290                },
1291                &Instr::ZeroExtend(val, ref dest_ty) => {
1292                    let frame = stack.last().unwrap();
1293                    let src_ty = d.type_of(val);
1294                    let val = frame.get_val(val, &*self.read());
1295                    match (src_ty, dest_ty) {
1296                        (
1297                            &Type::Int { is_signed: src_is_signed, .. },
1298                            &Type::Int { width: dest_width, is_signed: dest_is_signed }
1299                        ) => Value::from_big_int(val.as_big_int(src_is_signed), dest_width, dest_is_signed, self.read().arch),
1300                        (_, _) => panic!("Invalid operand types to zero extension")
1301                    }
1302                },
1303                &Instr::FloatCast(instr, ref ty) => {
1304                    let frame = stack.last().unwrap();
1305                    let val = frame.get_val(instr, &*self.read());
1306                    match (val.as_bytes().len(), self.read().size_of(ty)) {
1307                        (x, y) if x == y => val.clone(),
1308                        (4, 8) => Value::from_f64(val.as_f32() as f64),
1309                        (8, 4) => Value::from_f32(val.as_f64() as f32),
1310                        (4, _) | (8, _) => panic!("Unexpected destination float cast type size"),
1311                        (_, 4) | (_, 8) => panic!("Unexpected source float cast type size"),
1312                        (_, _) => panic!("Unexpected float cast type sizes"),
1313                    }
1314                },
1315                &Instr::FloatToInt(instr, ref dest_ty) => {
1316                    let frame = stack.last().unwrap();
1317                    let val = frame.get_val(instr, &*self.read());
1318                    let src_ty = d.type_of(instr);
1319                    let src_size = self.read().size_of(src_ty);
1320
1321                    match dest_ty {
1322                        &Type::Int { width, is_signed } => {
1323                            let big_int = if is_signed {
1324                                let int = match src_size * 8 {
1325                                    32 => val.as_f32() as i64,
1326                                    64 => val.as_f64() as i64,
1327                                    _ => panic!("Invalid float size"),
1328                                };
1329                                BigInt::from(int)
1330                            } else {
1331                                let int = match src_size * 8 {
1332                                    32 => val.as_f32() as u64,
1333                                    64 => val.as_f64() as u64,
1334                                    _ => panic!("Invalid float size"),
1335                                };
1336                                BigInt::from(int)
1337                            };
1338                            Value::from_big_int(big_int, width, is_signed, self.read().arch)
1339                        },
1340                        _ => panic!("Invalid destination type in float to int cast: {:?}", dest_ty),
1341                    }
1342                }
1343                &Instr::IntToFloat(instr, ref dest_ty) => {
1344                    let frame = stack.last().unwrap();
1345                    let val = frame.get_val(instr, &*self.read());
1346                    let src_ty = d.type_of(instr);
1347                    let dest_size = self.read().size_of(dest_ty);
1348                    match src_ty {
1349                        &Type::Int { is_signed, .. } => {
1350                            let big_int = val.as_big_int(is_signed);
1351                            if is_signed {
1352                                let int: i64 = big_int.try_into().unwrap();
1353                                match dest_size * 8 {
1354                                    32 => Value::from_f32(int as _),
1355                                    64 => Value::from_f64(int as _),
1356                                    _ => panic!("Invalid destination size in int to float cast"),
1357                                }
1358                            } else {
1359                                let int: u64 = big_int.try_into().unwrap();
1360                                match dest_size * 8 {
1361                                    32 => Value::from_f32(int as _),
1362                                    64 => Value::from_f64(int as _),
1363                                    _ => panic!("Invalid destination size in int to float cast"),
1364                                }
1365                            }
1366                        },
1367                        _ => panic!("Invalid source type in int to float cast: {:?}", src_ty),
1368                    }
1369                }
1370                &Instr::Load(location) => {
1371                    let frame = stack.last().unwrap();
1372                    let op = self.read().code.blocks[frame.block].ops[frame.pc];
1373                    let ty = d.type_of(op);
1374                    let ty = frame.canonicalize_type(ty);
1375                    let size = self.read().size_of(&ty);
1376                    let frame = stack.last_mut().unwrap();
1377                    frame.get_val(location, &*self.read()).load(size)
1378                },
1379                &Instr::Store { location, value } => {
1380                    let val = frame.get_val(value, &*self.read()).clone();
1381                    let result = frame.get_val_mut(location, &*self.read());
1382                    result.store(val);
1383                    Value::Nothing
1384                },
1385                &Instr::AddressOfStatic(statik) => {
1386                    if let InterpMode::CompileTime = INTERP.read().unwrap().mode {
1387                        panic!("Can't access static at compile time!");
1388                    }
1389                    let static_value = Value::from_const(&self.read().code.mir.statics[statik].val.clone(), &*self.read());
1390                    let statik = INTERP.write().unwrap().statics.entry(statik)
1391                        .or_insert(static_value)
1392                        .as_bytes()
1393                        .as_ptr();
1394                    Value::from_usize(statik as usize)
1395                },
1396                &Instr::Pointer { op, is_mut } => {
1397                    Value::from_ty(frame.get_val(op, &*self.read()).as_ty().ptr_with_mut(is_mut))
1398                },
1399                &Instr::FunctionTy { ref param_tys, ret_ty } => {
1400                    let param_tys = param_tys.iter()
1401                        .map(|&ty| frame.get_val(ty, &*self.read()).as_ty())
1402                        .collect();
1403                    let ret_ty = frame.get_val(ret_ty, &*self.read()).as_ty();
1404
1405                    Value::from_ty(Type::Function(FunctionType { param_tys, return_ty: Box::new(ret_ty) }))
1406                }
1407                &Instr::Struct { ref fields, id } => {
1408                    let mut field_tys = Vec::new();
1409                    for &field in fields {
1410                        field_tys.push(frame.get_val(field, &*self.read()).as_ty());
1411                    }
1412                    drop(d);
1413                    let strukt = StructType {
1414                        field_tys,
1415                        identity: id,
1416                    };
1417                    Value::from_ty(Type::Struct(strukt))
1418                },
1419                &Instr::Enum { ref variants, id } => {
1420                    if !self.read().code.mir.enums.contains_key(&id) {
1421                        let mut variant_tys = Vec::new();
1422                        for &variant in variants {
1423                            variant_tys.push(frame.get_val(variant, &*self.read()).as_ty());
1424                        }
1425                        let layout = self.read().layout_enum(&variant_tys);
1426                        drop(d);
1427                        self.write().code.mir.enums.insert(
1428                            id,
1429                            layout,
1430                        );
1431                    }
1432                    Value::from_ty(Type::Enum(id))
1433                }
1434                &Instr::StructLit { ref fields, id } => {
1435                    let frame = stack.last().unwrap();
1436                    let field_tys: Vec<_> = fields.iter()
1437                        .map(|&instr| {
1438                            let ty = d.type_of(instr);
1439                            frame.canonicalize_type(ty)
1440                        })
1441                        .collect();
1442                    let fields: Vec<_> = fields.iter()
1443                        .map(|&instr| frame.get_val(instr, &*self.read()).clone())
1444                        .collect();
1445                    drop(d);
1446                    let strukt = StructType {
1447                        field_tys,
1448                        identity: id,
1449                    };
1450                    self.write().eval_struct_lit(&strukt, fields.into_iter())
1451                },
1452                &Instr::Ret(instr) => {
1453                    let val = frame.get_val(instr, &*self.read()).clone();
1454                    return Some(val)
1455                },
1456                &Instr::Br(bb) => {
1457                    frame.branch_to(bb);
1458                    return None
1459                },
1460                &Instr::CondBr { condition, true_bb, false_bb } => {
1461                    let condition = frame.get_val(condition, &*self.read()).as_bool();
1462                    let branch = if condition { true_bb } else { false_bb };
1463                    frame.branch_to(branch);
1464                    return None
1465                },
1466                &Instr::SwitchBr { scrutinee, ref cases, catch_all_bb } => {
1467                    // TODO: this is a very crude (and possibly slow) way of supporting arbitrary integer scrutinees
1468                    let scrutinee = frame.get_val(scrutinee, &*self.read()).as_bytes().to_owned();
1469                    let interp = INTERP.read().unwrap();
1470                    let block = if let Some(table) = interp.switch_cache.get(&next_op) {
1471                        let block = table.get(scrutinee.as_ref()).copied();
1472                        drop(interp);
1473                        block
1474                    } else {
1475                        drop(interp);
1476                        let mut table = HashMap::new();
1477                        for case in cases.clone() {
1478                            let val = Value::from_const(&case.value, &*self.read());
1479                            let val = val.as_bytes();
1480                            table.insert(val.as_ref().to_owned().into_boxed_slice(), case.bb);
1481                        }
1482                        INTERP.write().unwrap().switch_cache.entry(next_op).or_insert(table)
1483                            .get(scrutinee.as_ref()).copied()
1484                    }.unwrap_or(catch_all_bb);
1485
1486                    let frame = stack.last_mut().unwrap();
1487                    frame.branch_to(block);
1488                    return None
1489                },
1490                &Instr::Variant { enuum, index, payload } => {
1491                    let payload = frame.get_val(payload, &*self.read()).clone();
1492                    Value::from_variant(&*self.read(), enuum, index, payload)
1493                },
1494                &Instr::DiscriminantAccess { val } => {
1495                    let enuum = frame.get_val(val, &*self.read()).as_enum();
1496                    Value::from_u32(enuum.discriminant)
1497                },
1498                &Instr::DirectFieldAccess { val, index } => {
1499                    let frame = stack.last().unwrap();
1500                    let bytes = frame.get_val(val, &*self.read()).as_bytes();
1501                    let strukt = match d.type_of(val) {
1502                        Type::Struct(strukt) => strukt,
1503                        _ => panic!("Can't directly get field of non-struct"),
1504                    };
1505                    let layout = self.read().layout_struct(strukt);
1506                    let size = self.read().size_of(&strukt.field_tys[index]);
1507                    let offset = layout.field_offsets[index];
1508                    Value::from_bytes(&bytes[offset..(offset + size)])
1509                },
1510                &Instr::IndirectFieldAccess { val, index } => {
1511                    let addr = frame.get_val(val, &*self.read()).as_usize();
1512                    let base_ty = &d.type_of(val).deref().unwrap().ty;
1513                    let strukt = match base_ty {
1514                        Type::Struct(strukt) => strukt,
1515                        _ => panic!("Can't directly get field of non-struct"),
1516                    };
1517                    let offset = self.read().layout_struct(strukt).field_offsets[index];
1518                    Value::from_usize(addr + offset)
1519                },
1520                &Instr::InternalFieldAccess { val, field } => {
1521                    let val = frame.get_val(val, &*self.read()).as_internal();
1522                    match (val, field) {
1523                        (InternalValue::StrLit(lit), InternalField::StringLiteral(field)) => {
1524                            use internal_fields::StringLiteral::*;
1525                            match field {
1526                                length => {
1527                                    Value::from_usize(lit.as_bytes().len())
1528                                },
1529                                data => Value::from_usize(lit.as_ptr() as usize),
1530                            }
1531                        },
1532                        pair => unimplemented!("unimplemented internal field access: {:?}", pair),
1533                    }
1534                },
1535                &Instr::Import(path) => {
1536                    let val = frame.get_val(path, &*self.read());
1537                    let ptr = val.as_raw_ptr();
1538                    
1539                    let str = unsafe { CStr::from_ptr(ptr as _) };
1540                    let path = str.to_str().unwrap();
1541                    drop(d);
1542                    let before = self.read().take_snapshot();
1543                    let file = self.write().src_map.add_file_on_disk(path).unwrap();
1544                    self.write().parse_added_files().unwrap();
1545                    let new_code = self.read().get_new_code_since(before);
1546                    self.write().finalize_hir();
1547                    self.write().initialize_tir(&new_code);
1548
1549                    let added_module = self.read().code.hir.global_scopes[file];
1550                    Value::from_mod(added_module)
1551                },
1552                Instr::Parameter(_) => panic!("Invalid parameter instruction in the middle of a function!"),
1553                Instr::Invalid => panic!("Must not have invalid instruction in an interpreted function!"),
1554            }
1555        };
1556
1557        let mut stack = stack_cell.borrow_mut();
1558        let frame = stack.last_mut().unwrap();
1559        let op = self.read().code.blocks[frame.block].ops[frame.pc];
1560        *frame.get_val_mut(op, &*self.read()) = val;
1561        frame.pc += 1;
1562        None
1563    }
1564}
1565
1566lazy_static! {
1567    static ref INTERP: RwLock<Interpreter> = RwLock::new(Interpreter::new(InterpMode::CompileTime));
1568}
1569thread_local! {
1570    static INTERP_STACK: RefCell<Vec<StackFrame>> = RefCell::new(Vec::new());
1571}
1572pub fn restart_interp(mode: InterpMode) {
1573    *INTERP.write().unwrap() = Interpreter::new(mode);
1574}