1 #![allow(non_camel_case_types)]
2 
3 pub use self::lucet_result::*;
4 pub use self::lucet_val::*;
5 
6 use crate::alloc::Limits;
7 use crate::error::Error;
8 use crate::instance::signals::SignalBehavior;
9 use libc::{c_int, c_void};
10 use num_derive::FromPrimitive;
11 
12 #[macro_export]
13 macro_rules! assert_nonnull {
14     ( $name:ident ) => {
15         if $name.is_null() {
16             return lucet_error::InvalidArgument;
17         }
18     };
19 }
20 
21 /// Wrap up the management of `Arc`s that go across the FFI boundary.
22 ///
23 /// Trait objects must be wrapped in two `Arc`s in order to yield a thin pointer.
24 #[macro_export]
25 macro_rules! with_ffi_arcs {
26     ( [ $name:ident : dyn $ty:ident ], $body:block ) => {{
27         assert_nonnull!($name);
28         let $name = Arc::from_raw($name as *const Arc<dyn $ty>);
29         let res = $body;
30         Arc::into_raw($name);
31         res
32     }};
33     ( [ $name:ident : $ty:ty ], $body:block ) => {{
34         assert_nonnull!($name);
35         let $name = Arc::from_raw($name as *const $ty);
36         let res = $body;
37         Arc::into_raw($name);
38         res
39     }};
40     ( [ $name:ident : dyn $ty:ident, $($tail:tt)* ], $body:block ) => {{
41         assert_nonnull!($name);
42         let $name = Arc::from_raw($name as *const Arc<dyn $ty>);
43         let rec = with_ffi_arcs!([$($tail)*], $body);
44         Arc::into_raw($name);
45         rec
46     }};
47     ( [ $name:ident : $ty:ty, $($tail:tt)* ], $body:block ) => {{
48         assert_nonnull!($name);
49         let $name = Arc::from_raw($name as *const $ty);
50         let rec = with_ffi_arcs!([$($tail)*], $body);
51         Arc::into_raw($name);
52         rec
53     }};
54 }
55 
56 /// Marker type for the `vmctx` pointer argument.
57 ///
58 /// This type should only be used with [`Vmctx::from_raw()`](struct.Vmctx.html#method.from_raw) or
59 /// the C API.
60 #[repr(C)]
61 pub struct lucet_vmctx {
62     _unused: [u8; 0],
63 }
64 
65 #[repr(C)]
66 #[derive(Clone, Copy, Debug, FromPrimitive)]
67 pub enum lucet_error {
68     Ok,
69     InvalidArgument,
70     RegionFull,
71     Module,
72     LimitsExceeded,
73     NoLinearMemory,
74     SymbolNotFound,
75     FuncNotFound,
76     RuntimeFault,
77     RuntimeTerminated,
78     Dl,
79     InstanceNotReturned,
80     InstanceNotYielded,
81     StartYielded,
82     Internal,
83     Unsupported,
84 }
85 
86 impl From<Error> for lucet_error {
from(e: Error) -> lucet_error87     fn from(e: Error) -> lucet_error {
88         lucet_error::from(&e)
89     }
90 }
91 
92 impl From<&Error> for lucet_error {
from(e: &Error) -> lucet_error93     fn from(e: &Error) -> lucet_error {
94         match e {
95             Error::InvalidArgument(_) => lucet_error::InvalidArgument,
96             Error::RegionFull(_) => lucet_error::RegionFull,
97             Error::ModuleError(_) => lucet_error::Module,
98             Error::LimitsExceeded(_) => lucet_error::LimitsExceeded,
99             Error::NoLinearMemory(_) => lucet_error::NoLinearMemory,
100             Error::SymbolNotFound(_) => lucet_error::SymbolNotFound,
101             Error::FuncNotFound(_, _) => lucet_error::FuncNotFound,
102             Error::RuntimeFault(_) => lucet_error::RuntimeFault,
103             Error::RuntimeTerminated(_) => lucet_error::RuntimeTerminated,
104             Error::DlError(_) => lucet_error::Dl,
105             Error::InstanceNotReturned => lucet_error::InstanceNotReturned,
106             Error::InstanceNotYielded => lucet_error::InstanceNotYielded,
107             Error::StartYielded => lucet_error::StartYielded,
108             Error::InternalError(_) => lucet_error::Internal,
109             Error::Unsupported(_) => lucet_error::Unsupported,
110         }
111     }
112 }
113 
114 #[repr(C)]
115 pub struct lucet_instance {
116     _unused: [u8; 0],
117 }
118 
119 #[repr(C)]
120 pub struct lucet_region {
121     _unused: [u8; 0],
122 }
123 
124 #[repr(C)]
125 pub struct lucet_dl_module {
126     _unused: [u8; 0],
127 }
128 
129 /// Runtime limits for the various memories that back a Lucet instance.
130 ///
131 /// Each value is specified in bytes, and must be evenly divisible by the host page size (4K).
132 #[derive(Clone, Debug)]
133 #[repr(C)]
134 pub struct lucet_alloc_limits {
135     /// Max size of the heap, which can be backed by real memory. (default 1M)
136     pub heap_memory_size: u64,
137     /// Size of total virtual memory. (default 8G)
138     pub heap_address_space_size: u64,
139     /// Size of the guest stack. (default 128K)
140     pub stack_size: u64,
141     /// Size of the globals region in bytes; each global uses 8 bytes. (default 4K)
142     pub globals_size: u64,
143     /// Size of the signal stack in bytes. (default SIGSTKSZ for Rust release builds, 12K for Rust
144     /// debug builds)
145     ///
146     /// This difference is to account for the greatly increased stack size usage in the signal
147     /// handler when running without optimizations.
148     ///
149     /// Note that debug vs. release mode is determined by `cfg(debug_assertions)`, so if you are
150     /// specifically enabling Rust debug assertions in your Cargo release builds, the default signal
151     /// stack will be larger.
152     pub signal_stack_size: u64,
153 }
154 
155 impl From<Limits> for lucet_alloc_limits {
from(limits: Limits) -> lucet_alloc_limits156     fn from(limits: Limits) -> lucet_alloc_limits {
157         (&limits).into()
158     }
159 }
160 
161 impl From<&Limits> for lucet_alloc_limits {
from(limits: &Limits) -> lucet_alloc_limits162     fn from(limits: &Limits) -> lucet_alloc_limits {
163         lucet_alloc_limits {
164             heap_memory_size: limits.heap_memory_size as u64,
165             heap_address_space_size: limits.heap_address_space_size as u64,
166             stack_size: limits.stack_size as u64,
167             globals_size: limits.globals_size as u64,
168             signal_stack_size: limits.signal_stack_size as u64,
169         }
170     }
171 }
172 
173 impl From<lucet_alloc_limits> for Limits {
from(limits: lucet_alloc_limits) -> Limits174     fn from(limits: lucet_alloc_limits) -> Limits {
175         (&limits).into()
176     }
177 }
178 
179 impl From<&lucet_alloc_limits> for Limits {
from(limits: &lucet_alloc_limits) -> Limits180     fn from(limits: &lucet_alloc_limits) -> Limits {
181         Limits {
182             heap_memory_size: limits.heap_memory_size as usize,
183             heap_address_space_size: limits.heap_address_space_size as usize,
184             stack_size: limits.stack_size as usize,
185             globals_size: limits.globals_size as usize,
186             signal_stack_size: limits.signal_stack_size as usize,
187         }
188     }
189 }
190 
191 #[repr(C)]
192 #[derive(Clone, Copy, Debug)]
193 pub enum lucet_signal_behavior {
194     Default,
195     Continue,
196     Terminate,
197 }
198 
199 impl From<lucet_signal_behavior> for SignalBehavior {
from(sb: lucet_signal_behavior) -> SignalBehavior200     fn from(sb: lucet_signal_behavior) -> SignalBehavior {
201         sb.into()
202     }
203 }
204 
205 impl From<&lucet_signal_behavior> for SignalBehavior {
from(sb: &lucet_signal_behavior) -> SignalBehavior206     fn from(sb: &lucet_signal_behavior) -> SignalBehavior {
207         match sb {
208             lucet_signal_behavior::Default => SignalBehavior::Default,
209             lucet_signal_behavior::Continue => SignalBehavior::Continue,
210             lucet_signal_behavior::Terminate => SignalBehavior::Terminate,
211         }
212     }
213 }
214 
215 pub type lucet_signal_handler = unsafe extern "C" fn(
216     inst: *mut lucet_instance,
217     trap: lucet_result::lucet_trapcode,
218     signum: c_int,
219     siginfo: *const libc::siginfo_t,
220     context: *const c_void,
221 ) -> lucet_signal_behavior;
222 
223 pub type lucet_fatal_handler = unsafe extern "C" fn(inst: *mut lucet_instance);
224 
225 pub struct CTerminationDetails {
226     pub details: *mut c_void,
227 }
228 
229 unsafe impl Send for CTerminationDetails {}
230 unsafe impl Sync for CTerminationDetails {}
231 
232 pub struct CYieldedVal {
233     pub val: *mut c_void,
234 }
235 
236 unsafe impl Send for CYieldedVal {}
237 unsafe impl Sync for CYieldedVal {}
238 
239 pub mod lucet_result {
240     use super::lucet_error;
241     use crate::c_api::{lucet_val, CTerminationDetails, CYieldedVal};
242     use crate::error::Error;
243     use crate::instance::{RunResult, TerminationDetails};
244     use crate::module::{AddrDetails, TrapCode};
245     use libc::{c_uchar, c_void};
246     use num_derive::FromPrimitive;
247     use std::ffi::CString;
248     use std::ptr;
249 
250     impl From<Result<RunResult, Error>> for lucet_result {
from(res: Result<RunResult, Error>) -> lucet_result251         fn from(res: Result<RunResult, Error>) -> lucet_result {
252             match res {
253                 Ok(RunResult::Returned(retval)) => lucet_result {
254                     tag: lucet_result_tag::Returned,
255                     val: lucet_result_val {
256                         returned: retval.into(),
257                     },
258                 },
259                 Ok(RunResult::Yielded(val)) => lucet_result {
260                     tag: lucet_result_tag::Yielded,
261                     val: lucet_result_val {
262                         yielded: lucet_yielded {
263                             val: val
264                                 .downcast_ref()
265                                 .map(|CYieldedVal { val }| *val)
266                                 .unwrap_or(ptr::null_mut()),
267                         },
268                     },
269                 },
270                 // TODO: test this path; currently our C API tests don't include any faulting tests
271                 Err(Error::RuntimeFault(details)) => lucet_result {
272                     tag: lucet_result_tag::Faulted,
273                     val: lucet_result_val {
274                         fault: lucet_runtime_faulted {
275                             fatal: details.fatal,
276                             trapcode: details.trapcode.into(),
277                             rip_addr: details.rip_addr,
278                             rip_addr_details: details.rip_addr_details.into(),
279                         },
280                     },
281                 },
282                 // TODO: test this path; currently our C API tests don't include any terminating tests
283                 Err(Error::RuntimeTerminated(details)) => lucet_result {
284                     tag: lucet_result_tag::Terminated,
285                     val: lucet_result_val {
286                         terminated: match details {
287                             TerminationDetails::Signal => lucet_terminated {
288                                 reason: lucet_terminated_reason::Signal,
289                                 provided: ptr::null_mut(),
290                             },
291                             TerminationDetails::CtxNotFound => lucet_terminated {
292                                 reason: lucet_terminated_reason::CtxNotFound,
293                                 provided: ptr::null_mut(),
294                             },
295                             TerminationDetails::YieldTypeMismatch => lucet_terminated {
296                                 reason: lucet_terminated_reason::YieldTypeMismatch,
297                                 provided: ptr::null_mut(),
298                             },
299                             TerminationDetails::BorrowError(_) => lucet_terminated {
300                                 reason: lucet_terminated_reason::BorrowError,
301                                 provided: ptr::null_mut(),
302                             },
303                             TerminationDetails::Provided(p) => lucet_terminated {
304                                 reason: lucet_terminated_reason::Provided,
305                                 provided: p
306                                     .downcast_ref()
307                                     .map(|CTerminationDetails { details }| *details)
308                                     .unwrap_or(ptr::null_mut()),
309                             },
310                         },
311                     },
312                 },
313                 Err(e) => lucet_result {
314                     tag: lucet_result_tag::Errored,
315                     val: lucet_result_val { errored: e.into() },
316                 },
317             }
318         }
319     }
320 
321     #[repr(C)]
322     #[derive(Clone, Copy)]
323     pub struct lucet_result {
324         pub tag: lucet_result_tag,
325         pub val: lucet_result_val,
326     }
327 
328     #[repr(C)]
329     #[derive(Clone, Copy, Debug, FromPrimitive)]
330     pub enum lucet_result_tag {
331         Returned,
332         Yielded,
333         Faulted,
334         Terminated,
335         Errored,
336     }
337 
338     #[repr(C)]
339     #[derive(Clone, Copy)]
340     pub union lucet_result_val {
341         pub returned: lucet_val::lucet_untyped_retval,
342         pub yielded: lucet_yielded,
343         pub fault: lucet_runtime_faulted,
344         pub terminated: lucet_terminated,
345         pub errored: lucet_error,
346     }
347 
348     #[repr(C)]
349     #[derive(Clone, Copy)]
350     pub struct lucet_terminated {
351         pub reason: lucet_terminated_reason,
352         pub provided: *mut c_void,
353     }
354 
355     #[repr(C)]
356     #[derive(Clone, Copy)]
357     pub enum lucet_terminated_reason {
358         Signal,
359         CtxNotFound,
360         YieldTypeMismatch,
361         BorrowError,
362         Provided,
363     }
364 
365     #[repr(C)]
366     #[derive(Clone, Copy)]
367     pub struct lucet_yielded {
368         pub val: *mut c_void,
369     }
370 
371     #[repr(C)]
372     #[derive(Clone, Copy)]
373     pub struct lucet_runtime_faulted {
374         pub fatal: bool,
375         pub trapcode: lucet_trapcode,
376         pub rip_addr: libc::uintptr_t,
377         pub rip_addr_details: lucet_module_addr_details,
378     }
379 
380     #[repr(C)]
381     #[derive(Clone, Copy, Debug)]
382     pub enum lucet_trapcode {
383         StackOverflow,
384         HeapOutOfBounds,
385         OutOfBounds,
386         IndirectCallToNull,
387         BadSignature,
388         IntegerOverflow,
389         IntegerDivByZero,
390         BadConversionToInteger,
391         Interrupt,
392         TableOutOfBounds,
393         Unreachable,
394         Unknown,
395     }
396 
397     impl From<Option<TrapCode>> for lucet_trapcode {
from(ty: Option<TrapCode>) -> lucet_trapcode398         fn from(ty: Option<TrapCode>) -> lucet_trapcode {
399             (&ty).into()
400         }
401     }
402 
403     impl From<&Option<TrapCode>> for lucet_trapcode {
from(ty: &Option<TrapCode>) -> lucet_trapcode404         fn from(ty: &Option<TrapCode>) -> lucet_trapcode {
405             if let Some(ty) = ty {
406                 match ty {
407                     TrapCode::StackOverflow => lucet_trapcode::StackOverflow,
408                     TrapCode::HeapOutOfBounds => lucet_trapcode::HeapOutOfBounds,
409                     TrapCode::OutOfBounds => lucet_trapcode::OutOfBounds,
410                     TrapCode::IndirectCallToNull => lucet_trapcode::IndirectCallToNull,
411                     TrapCode::BadSignature => lucet_trapcode::BadSignature,
412                     TrapCode::IntegerOverflow => lucet_trapcode::IntegerOverflow,
413                     TrapCode::IntegerDivByZero => lucet_trapcode::IntegerDivByZero,
414                     TrapCode::BadConversionToInteger => lucet_trapcode::BadConversionToInteger,
415                     TrapCode::Interrupt => lucet_trapcode::Interrupt,
416                     TrapCode::TableOutOfBounds => lucet_trapcode::TableOutOfBounds,
417                     TrapCode::Unreachable => lucet_trapcode::Unreachable,
418                 }
419             } else {
420                 lucet_trapcode::Unknown
421             }
422         }
423     }
424 
425     const ADDR_DETAILS_NAME_LEN: usize = 256;
426 
427     /// Half a kilobyte is too substantial for `Copy`, but we must have it because [unions with
428     /// non-`Copy` fields are unstable](https://github.com/rust-lang/rust/issues/32836).
429     #[repr(C)]
430     #[derive(Clone, Copy)]
431     pub struct lucet_module_addr_details {
432         pub module_code_resolvable: bool,
433         pub in_module_code: bool,
434         pub file_name: [c_uchar; ADDR_DETAILS_NAME_LEN],
435         pub sym_name: [c_uchar; ADDR_DETAILS_NAME_LEN],
436     }
437 
438     impl Default for lucet_module_addr_details {
default() -> Self439         fn default() -> Self {
440             lucet_module_addr_details {
441                 module_code_resolvable: false,
442                 in_module_code: false,
443                 file_name: [0; ADDR_DETAILS_NAME_LEN],
444                 sym_name: [0; ADDR_DETAILS_NAME_LEN],
445             }
446         }
447     }
448 
449     impl From<Option<AddrDetails>> for lucet_module_addr_details {
from(details: Option<AddrDetails>) -> Self450         fn from(details: Option<AddrDetails>) -> Self {
451             /// Convert a string into C-compatible bytes, truncate it to length
452             /// `ADDR_DETAILS_NAME_LEN`, and make sure it has a trailing nul.
453             fn trunc_c_str_bytes(s: &str) -> Vec<u8> {
454                 let s = CString::new(s);
455                 let mut bytes = s.ok().map(|s| s.into_bytes_with_nul()).unwrap_or(vec![0]);
456                 bytes.truncate(ADDR_DETAILS_NAME_LEN);
457                 // we always have at least the 0, so this `last` can be unwrapped
458                 *bytes.last_mut().unwrap() = 0;
459                 bytes
460             }
461 
462             let mut ret = details
463                 .as_ref()
464                 .map(|details| lucet_module_addr_details {
465                     module_code_resolvable: true,
466                     in_module_code: details.in_module_code,
467                     file_name: [0; ADDR_DETAILS_NAME_LEN],
468                     sym_name: [0; ADDR_DETAILS_NAME_LEN],
469                 })
470                 .unwrap_or_default();
471 
472             // get truncated C-compatible bytes for each string, or "\0" if they're not present
473             let file_name_bytes = details
474                 .as_ref()
475                 .and_then(|details| details.file_name.as_ref().map(|s| trunc_c_str_bytes(s)))
476                 .unwrap_or_else(|| vec![0]);
477             let sym_name_bytes = details
478                 .and_then(|details| details.sym_name.as_ref().map(|s| trunc_c_str_bytes(s)))
479                 .unwrap_or_else(|| vec![0]);
480 
481             // copy the bytes into the array, making sure to copy only as many as are in the string
482             ret.file_name[0..file_name_bytes.len()].copy_from_slice(file_name_bytes.as_slice());
483             ret.sym_name[0..sym_name_bytes.len()].copy_from_slice(sym_name_bytes.as_slice());
484 
485             ret
486         }
487     }
488 }
489 
490 pub mod lucet_val {
491     use crate::val::{UntypedRetVal, UntypedRetValInternal, Val};
492     use libc::{c_char, c_void};
493 
494     // Note on the value associated with each type: the most significant bits represent the "class"
495     // of the type (1: a C pointer, 2: something unsigned that fits in 64 bits, 3: something signed
496     // that fits in 64 bits, 4: f32, 5: f64). The remain bits can be anything as long as it is
497     // unique.
498     #[repr(C)]
499     #[derive(Clone, Copy, Debug)]
500     pub enum lucet_val_type {
501         C_Ptr,    // = (1 << 16) | 0x0100,
502         GuestPtr, // = (2 << 16) | 0x0101,
503         U8,       // = (2 << 16) | 0x0201,
504         U16,      // = (2 << 16) | 0x0202,
505         U32,      // = (2 << 16) | 0x0203,
506         U64,      // = (2 << 16) | 0x0204,
507         I8,       // = (3 << 16) | 0x0300,
508         I16,      // = (3 << 16) | 0x0301,
509         I32,      // = (3 << 16) | 0x0302,
510         I64,      // = (3 << 16) | 0x0303,
511         USize,    // = (2 << 16) | 0x0400,
512         ISize,    // = (3 << 16) | 0x0401,
513         Bool,     // = (2 << 16) | 0x0700,
514         F32,      // = (4 << 16) | 0x0800,
515         F64,      // = (5 << 16) | 0x0801,
516     }
517 
518     #[repr(C)]
519     #[derive(Clone, Copy)]
520     pub union lucet_val_inner_val {
521         as_c_ptr: *mut c_void, // (1 << 16)
522         as_u64: u64,           // (2 << 16)
523         as_i64: i64,           // (3 << 16)
524         as_f32: f32,           // (4 << 16)
525         as_f64: f64,           // (5 << 16)
526     }
527 
528     #[repr(C)]
529     #[derive(Clone, Copy)]
530     pub struct lucet_val {
531         ty: lucet_val_type,
532         inner_val: lucet_val_inner_val,
533     }
534 
535     impl From<lucet_val> for Val {
from(val: lucet_val) -> Val536         fn from(val: lucet_val) -> Val {
537             (&val).into()
538         }
539     }
540 
541     impl From<&lucet_val> for Val {
from(val: &lucet_val) -> Val542         fn from(val: &lucet_val) -> Val {
543             match val.ty {
544                 lucet_val_type::C_Ptr => Val::CPtr(unsafe { val.inner_val.as_u64 } as _),
545                 lucet_val_type::GuestPtr => Val::GuestPtr(unsafe { val.inner_val.as_u64 } as _),
546                 lucet_val_type::U8 => Val::U8(unsafe { val.inner_val.as_u64 } as _),
547                 lucet_val_type::U16 => Val::U16(unsafe { val.inner_val.as_u64 } as _),
548                 lucet_val_type::U32 => Val::U32(unsafe { val.inner_val.as_u64 } as _),
549                 lucet_val_type::U64 => Val::U64(unsafe { val.inner_val.as_u64 } as _),
550                 lucet_val_type::I8 => Val::I16(unsafe { val.inner_val.as_i64 } as _),
551                 lucet_val_type::I16 => Val::I32(unsafe { val.inner_val.as_i64 } as _),
552                 lucet_val_type::I32 => Val::I32(unsafe { val.inner_val.as_i64 } as _),
553                 lucet_val_type::I64 => Val::I64(unsafe { val.inner_val.as_i64 } as _),
554                 lucet_val_type::USize => Val::USize(unsafe { val.inner_val.as_u64 } as _),
555                 lucet_val_type::ISize => Val::ISize(unsafe { val.inner_val.as_i64 } as _),
556                 lucet_val_type::Bool => Val::Bool(unsafe { val.inner_val.as_u64 } != 0),
557                 lucet_val_type::F32 => Val::F32(unsafe { val.inner_val.as_f32 } as _),
558                 lucet_val_type::F64 => Val::F64(unsafe { val.inner_val.as_f64 } as _),
559             }
560         }
561     }
562 
563     impl From<Val> for lucet_val {
from(val: Val) -> Self564         fn from(val: Val) -> Self {
565             (&val).into()
566         }
567     }
568 
569     impl From<&Val> for lucet_val {
from(val: &Val) -> Self570         fn from(val: &Val) -> Self {
571             match val {
572                 Val::CPtr(a) => lucet_val {
573                     ty: lucet_val_type::C_Ptr,
574                     inner_val: lucet_val_inner_val { as_u64: *a as _ },
575                 },
576                 Val::GuestPtr(a) => lucet_val {
577                     ty: lucet_val_type::GuestPtr,
578                     inner_val: lucet_val_inner_val { as_u64: *a as _ },
579                 },
580                 Val::U8(a) => lucet_val {
581                     ty: lucet_val_type::U8,
582                     inner_val: lucet_val_inner_val { as_u64: *a as _ },
583                 },
584                 Val::U16(a) => lucet_val {
585                     ty: lucet_val_type::U16,
586                     inner_val: lucet_val_inner_val { as_u64: *a as _ },
587                 },
588                 Val::U32(a) => lucet_val {
589                     ty: lucet_val_type::U32,
590                     inner_val: lucet_val_inner_val { as_u64: *a as _ },
591                 },
592                 Val::U64(a) => lucet_val {
593                     ty: lucet_val_type::U64,
594                     inner_val: lucet_val_inner_val { as_u64: *a as _ },
595                 },
596                 Val::I8(a) => lucet_val {
597                     ty: lucet_val_type::I8,
598                     inner_val: lucet_val_inner_val { as_i64: *a as _ },
599                 },
600                 Val::I16(a) => lucet_val {
601                     ty: lucet_val_type::I16,
602                     inner_val: lucet_val_inner_val { as_i64: *a as _ },
603                 },
604                 Val::I32(a) => lucet_val {
605                     ty: lucet_val_type::I32,
606                     inner_val: lucet_val_inner_val { as_i64: *a as _ },
607                 },
608                 Val::I64(a) => lucet_val {
609                     ty: lucet_val_type::I64,
610                     inner_val: lucet_val_inner_val { as_i64: *a as _ },
611                 },
612                 Val::USize(a) => lucet_val {
613                     ty: lucet_val_type::USize,
614                     inner_val: lucet_val_inner_val { as_u64: *a as _ },
615                 },
616                 Val::ISize(a) => lucet_val {
617                     ty: lucet_val_type::ISize,
618                     inner_val: lucet_val_inner_val { as_i64: *a as _ },
619                 },
620                 Val::Bool(a) => lucet_val {
621                     ty: lucet_val_type::Bool,
622                     inner_val: lucet_val_inner_val { as_u64: *a as _ },
623                 },
624                 Val::F32(a) => lucet_val {
625                     ty: lucet_val_type::F32,
626                     inner_val: lucet_val_inner_val { as_f32: *a as _ },
627                 },
628                 Val::F64(a) => lucet_val {
629                     ty: lucet_val_type::F64,
630                     inner_val: lucet_val_inner_val { as_f64: *a as _ },
631                 },
632             }
633         }
634     }
635 
636     #[repr(C)]
637     #[derive(Clone, Copy, Debug)]
638     pub struct lucet_untyped_retval {
639         pub fp: [c_char; 16],
640         pub gp: [c_char; 8],
641     }
642 
643     #[repr(C)]
644     #[derive(Clone, Copy)]
645     pub union lucet_retval_gp {
646         pub as_untyped: [c_char; 8],
647         pub as_c_ptr: *mut c_void,
648         pub as_u64: u64,
649         pub as_i64: i64,
650     }
651 
652     impl From<UntypedRetVal> for lucet_untyped_retval {
from(retval: UntypedRetVal) -> lucet_untyped_retval653         fn from(retval: UntypedRetVal) -> lucet_untyped_retval {
654             let mut v = lucet_untyped_retval {
655                 fp: [0; 16],
656                 gp: [0; 8],
657             };
658             unsafe {
659                 core::arch::x86_64::_mm_storeu_ps(
660                     v.fp.as_mut().as_mut_ptr() as *mut f32,
661                     retval.fp(),
662                 );
663                 *(v.gp.as_mut().as_mut_ptr() as *mut u64) = retval.gp();
664             }
665             v
666         }
667     }
668 }
669