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 Inline(SmallVec<[u8; 64 / 8]>),
48 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 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 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 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#[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); 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 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 #[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 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 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 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 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 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 thunk.sub64_imm(Reg64::Rsp, total_stack_allocation);
735
736 for (i, param_ty) in param_tys.iter().enumerate() {
738 let rsp_offset = i as i32 * 8;
739 if self.size_of(param_ty) > 8 {
741 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 thunk.store64(Reg64::Rsp + param_address_array_offset + rsp_offset, Reg64::Rax);
749 }
750
751 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 thunk.movabs(Reg64::Rax, (interp_ffi_entry_point as usize as isize).try_into().unwrap());
758 thunk.call_direct(Reg64::Rax);
759
760 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 thunk.add64_imm(Reg64::Rsp, total_stack_allocation);
774
775 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 thunk.load64(Reg64::Rax, Reg64::Rsp + extension + 8);
833
834 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 let registers = [Reg16::Cx, Reg16::Dx, Reg16::R8w, Reg16::R9w, Reg16::Ax];
841 thunk.load16(registers[min(i, 4)], Reg64::Rax);
842
843 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 let registers = [Reg32::Ecx, Reg32::Edx, Reg32::R8d, Reg32::R9d, Reg32::Eax];
852 thunk.load32(registers[min(i, 4)], Reg64::Rax);
853
854 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 let registers = [Reg64::Rcx, Reg64::Rdx, Reg64::R8, Reg64::R9, Reg64::Rax];
864 thunk.load64(registers[min(i, 4)], Reg64::Rax);
865
866 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 thunk.movabs(Reg64::R10, func_address);
878 thunk.call_direct(Reg64::R10);
879
880 thunk.load64(Reg64::Rcx, Reg64::Rsp + extension + 16);
882
883 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 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 thunk.load64(Reg64::Rax, Reg64::Rbp - 8);
918
919 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 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 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 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 thunk.movabs(Reg64::R10, func_address);
945 thunk.call_direct(Reg64::R10);
946
947 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 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 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 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 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 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}