lucet_runtime_internals/
c_api.rs

1#![allow(non_camel_case_types)]
2
3pub use self::lucet_result::*;
4pub use self::lucet_val::*;
5
6use crate::alloc::Limits;
7use crate::error::Error;
8use crate::instance::signals::SignalBehavior;
9use libc::{c_int, c_void};
10use num_derive::FromPrimitive;
11
12#[macro_export]
13macro_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]
25macro_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)]
61pub struct lucet_vmctx {
62    _unused: [u8; 0],
63}
64
65#[repr(C)]
66#[derive(Clone, Copy, Debug, FromPrimitive)]
67pub 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
86impl From<Error> for lucet_error {
87    fn from(e: Error) -> lucet_error {
88        lucet_error::from(&e)
89    }
90}
91
92impl From<&Error> for lucet_error {
93    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)]
115pub struct lucet_instance {
116    _unused: [u8; 0],
117}
118
119#[repr(C)]
120pub struct lucet_region {
121    _unused: [u8; 0],
122}
123
124#[repr(C)]
125pub 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)]
134pub 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 release builds, at least 12K for
144    /// debug builds; minimum MINSIGSTKSZ)
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 debug assertions in your release builds, the default signal stack may
151    /// be larger.
152    pub signal_stack_size: u64,
153}
154
155impl From<Limits> for lucet_alloc_limits {
156    fn from(limits: Limits) -> lucet_alloc_limits {
157        (&limits).into()
158    }
159}
160
161impl From<&Limits> for lucet_alloc_limits {
162    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
173impl From<lucet_alloc_limits> for Limits {
174    fn from(limits: lucet_alloc_limits) -> Limits {
175        (&limits).into()
176    }
177}
178
179impl From<&lucet_alloc_limits> for Limits {
180    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)]
193pub enum lucet_signal_behavior {
194    Default,
195    Continue,
196    Terminate,
197}
198
199impl From<lucet_signal_behavior> for SignalBehavior {
200    fn from(sb: lucet_signal_behavior) -> SignalBehavior {
201        sb.into()
202    }
203}
204
205impl From<&lucet_signal_behavior> for SignalBehavior {
206    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
215pub 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
223pub type lucet_fatal_handler = unsafe extern "C" fn(inst: *mut lucet_instance);
224
225pub struct CTerminationDetails {
226    pub details: *mut c_void,
227}
228
229unsafe impl Send for CTerminationDetails {}
230unsafe impl Sync for CTerminationDetails {}
231
232pub struct CYieldedVal {
233    pub val: *mut c_void,
234}
235
236unsafe impl Send for CYieldedVal {}
237unsafe impl Sync for CYieldedVal {}
238
239pub 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 {
251        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                            TerminationDetails::Remote => lucet_terminated {
311                                reason: lucet_terminated_reason::Remote,
312                                provided: std::ptr::null_mut(),
313                            },
314                        },
315                    },
316                },
317                Err(e) => lucet_result {
318                    tag: lucet_result_tag::Errored,
319                    val: lucet_result_val { errored: e.into() },
320                },
321            }
322        }
323    }
324
325    #[repr(C)]
326    #[derive(Clone, Copy)]
327    pub struct lucet_result {
328        pub tag: lucet_result_tag,
329        pub val: lucet_result_val,
330    }
331
332    #[repr(C)]
333    #[derive(Clone, Copy, Debug, FromPrimitive)]
334    pub enum lucet_result_tag {
335        Returned,
336        Yielded,
337        Faulted,
338        Terminated,
339        Errored,
340    }
341
342    #[repr(C)]
343    #[derive(Clone, Copy)]
344    pub union lucet_result_val {
345        pub returned: lucet_val::lucet_untyped_retval,
346        pub yielded: lucet_yielded,
347        pub fault: lucet_runtime_faulted,
348        pub terminated: lucet_terminated,
349        pub errored: lucet_error,
350    }
351
352    #[repr(C)]
353    #[derive(Clone, Copy)]
354    pub struct lucet_terminated {
355        pub reason: lucet_terminated_reason,
356        pub provided: *mut c_void,
357    }
358
359    #[repr(C)]
360    #[derive(Clone, Copy)]
361    pub enum lucet_terminated_reason {
362        Signal,
363        CtxNotFound,
364        YieldTypeMismatch,
365        BorrowError,
366        Provided,
367        Remote,
368    }
369
370    #[repr(C)]
371    #[derive(Clone, Copy)]
372    pub struct lucet_yielded {
373        pub val: *mut c_void,
374    }
375
376    #[repr(C)]
377    #[derive(Clone, Copy)]
378    pub struct lucet_runtime_faulted {
379        pub fatal: bool,
380        pub trapcode: lucet_trapcode,
381        pub rip_addr: libc::uintptr_t,
382        pub rip_addr_details: lucet_module_addr_details,
383    }
384
385    #[repr(C)]
386    #[derive(Clone, Copy, Debug)]
387    pub enum lucet_trapcode {
388        StackOverflow,
389        HeapOutOfBounds,
390        OutOfBounds,
391        IndirectCallToNull,
392        BadSignature,
393        IntegerOverflow,
394        IntegerDivByZero,
395        BadConversionToInteger,
396        Interrupt,
397        TableOutOfBounds,
398        Unreachable,
399        Unknown,
400    }
401
402    impl From<Option<TrapCode>> for lucet_trapcode {
403        fn from(ty: Option<TrapCode>) -> lucet_trapcode {
404            (&ty).into()
405        }
406    }
407
408    impl From<&Option<TrapCode>> for lucet_trapcode {
409        fn from(ty: &Option<TrapCode>) -> lucet_trapcode {
410            if let Some(ty) = ty {
411                match ty {
412                    TrapCode::StackOverflow => lucet_trapcode::StackOverflow,
413                    TrapCode::HeapOutOfBounds => lucet_trapcode::HeapOutOfBounds,
414                    TrapCode::OutOfBounds => lucet_trapcode::OutOfBounds,
415                    TrapCode::IndirectCallToNull => lucet_trapcode::IndirectCallToNull,
416                    TrapCode::BadSignature => lucet_trapcode::BadSignature,
417                    TrapCode::IntegerOverflow => lucet_trapcode::IntegerOverflow,
418                    TrapCode::IntegerDivByZero => lucet_trapcode::IntegerDivByZero,
419                    TrapCode::BadConversionToInteger => lucet_trapcode::BadConversionToInteger,
420                    TrapCode::Interrupt => lucet_trapcode::Interrupt,
421                    TrapCode::TableOutOfBounds => lucet_trapcode::TableOutOfBounds,
422                    TrapCode::Unreachable => lucet_trapcode::Unreachable,
423                }
424            } else {
425                lucet_trapcode::Unknown
426            }
427        }
428    }
429
430    const ADDR_DETAILS_NAME_LEN: usize = 256;
431
432    /// Half a kilobyte is too substantial for `Copy`, but we must have it because [unions with
433    /// non-`Copy` fields are unstable](https://github.com/rust-lang/rust/issues/32836).
434    #[repr(C)]
435    #[derive(Clone, Copy)]
436    pub struct lucet_module_addr_details {
437        pub module_code_resolvable: bool,
438        pub in_module_code: bool,
439        pub file_name: [c_uchar; ADDR_DETAILS_NAME_LEN],
440        pub sym_name: [c_uchar; ADDR_DETAILS_NAME_LEN],
441    }
442
443    impl Default for lucet_module_addr_details {
444        fn default() -> Self {
445            lucet_module_addr_details {
446                module_code_resolvable: false,
447                in_module_code: false,
448                file_name: [0; ADDR_DETAILS_NAME_LEN],
449                sym_name: [0; ADDR_DETAILS_NAME_LEN],
450            }
451        }
452    }
453
454    impl From<Option<AddrDetails>> for lucet_module_addr_details {
455        fn from(details: Option<AddrDetails>) -> Self {
456            /// Convert a string into C-compatible bytes, truncate it to length
457            /// `ADDR_DETAILS_NAME_LEN`, and make sure it has a trailing nul.
458            fn trunc_c_str_bytes(s: &str) -> Vec<u8> {
459                let s = CString::new(s);
460                let mut bytes = s.ok().map(|s| s.into_bytes_with_nul()).unwrap_or(vec![0]);
461                bytes.truncate(ADDR_DETAILS_NAME_LEN);
462                // we always have at least the 0, so this `last` can be unwrapped
463                *bytes.last_mut().unwrap() = 0;
464                bytes
465            }
466
467            let mut ret = details
468                .as_ref()
469                .map(|details| lucet_module_addr_details {
470                    module_code_resolvable: true,
471                    in_module_code: details.in_module_code,
472                    file_name: [0; ADDR_DETAILS_NAME_LEN],
473                    sym_name: [0; ADDR_DETAILS_NAME_LEN],
474                })
475                .unwrap_or_default();
476
477            // get truncated C-compatible bytes for each string, or "\0" if they're not present
478            let file_name_bytes = details
479                .as_ref()
480                .and_then(|details| details.file_name.as_ref().map(|s| trunc_c_str_bytes(s)))
481                .unwrap_or_else(|| vec![0]);
482            let sym_name_bytes = details
483                .and_then(|details| details.sym_name.as_ref().map(|s| trunc_c_str_bytes(s)))
484                .unwrap_or_else(|| vec![0]);
485
486            // copy the bytes into the array, making sure to copy only as many as are in the string
487            ret.file_name[0..file_name_bytes.len()].copy_from_slice(file_name_bytes.as_slice());
488            ret.sym_name[0..sym_name_bytes.len()].copy_from_slice(sym_name_bytes.as_slice());
489
490            ret
491        }
492    }
493}
494
495pub mod lucet_val {
496    use crate::val::{UntypedRetVal, UntypedRetValInternal, Val};
497    use libc::{c_char, c_void};
498
499    // Note on the value associated with each type: the most significant bits represent the "class"
500    // of the type (1: a C pointer, 2: something unsigned that fits in 64 bits, 3: something signed
501    // that fits in 64 bits, 4: f32, 5: f64). The remain bits can be anything as long as it is
502    // unique.
503    #[repr(C)]
504    #[derive(Clone, Copy, Debug)]
505    pub enum lucet_val_type {
506        C_Ptr,    // = (1 << 16) | 0x0100,
507        GuestPtr, // = (2 << 16) | 0x0101,
508        U8,       // = (2 << 16) | 0x0201,
509        U16,      // = (2 << 16) | 0x0202,
510        U32,      // = (2 << 16) | 0x0203,
511        U64,      // = (2 << 16) | 0x0204,
512        I8,       // = (3 << 16) | 0x0300,
513        I16,      // = (3 << 16) | 0x0301,
514        I32,      // = (3 << 16) | 0x0302,
515        I64,      // = (3 << 16) | 0x0303,
516        USize,    // = (2 << 16) | 0x0400,
517        ISize,    // = (3 << 16) | 0x0401,
518        Bool,     // = (2 << 16) | 0x0700,
519        F32,      // = (4 << 16) | 0x0800,
520        F64,      // = (5 << 16) | 0x0801,
521    }
522
523    #[repr(C)]
524    #[derive(Clone, Copy)]
525    pub union lucet_val_inner_val {
526        as_c_ptr: *mut c_void, // (1 << 16)
527        as_u64: u64,           // (2 << 16)
528        as_i64: i64,           // (3 << 16)
529        as_f32: f32,           // (4 << 16)
530        as_f64: f64,           // (5 << 16)
531    }
532
533    #[repr(C)]
534    #[derive(Clone, Copy)]
535    pub struct lucet_val {
536        ty: lucet_val_type,
537        inner_val: lucet_val_inner_val,
538    }
539
540    impl From<lucet_val> for Val {
541        fn from(val: lucet_val) -> Val {
542            (&val).into()
543        }
544    }
545
546    impl From<&lucet_val> for Val {
547        fn from(val: &lucet_val) -> Val {
548            match val.ty {
549                lucet_val_type::C_Ptr => Val::CPtr(unsafe { val.inner_val.as_u64 } as _),
550                lucet_val_type::GuestPtr => Val::GuestPtr(unsafe { val.inner_val.as_u64 } as _),
551                lucet_val_type::U8 => Val::U8(unsafe { val.inner_val.as_u64 } as _),
552                lucet_val_type::U16 => Val::U16(unsafe { val.inner_val.as_u64 } as _),
553                lucet_val_type::U32 => Val::U32(unsafe { val.inner_val.as_u64 } as _),
554                lucet_val_type::U64 => Val::U64(unsafe { val.inner_val.as_u64 } as _),
555                lucet_val_type::I8 => Val::I16(unsafe { val.inner_val.as_i64 } as _),
556                lucet_val_type::I16 => Val::I32(unsafe { val.inner_val.as_i64 } as _),
557                lucet_val_type::I32 => Val::I32(unsafe { val.inner_val.as_i64 } as _),
558                lucet_val_type::I64 => Val::I64(unsafe { val.inner_val.as_i64 } as _),
559                lucet_val_type::USize => Val::USize(unsafe { val.inner_val.as_u64 } as _),
560                lucet_val_type::ISize => Val::ISize(unsafe { val.inner_val.as_i64 } as _),
561                lucet_val_type::Bool => Val::Bool(unsafe { val.inner_val.as_u64 } != 0),
562                lucet_val_type::F32 => Val::F32(unsafe { val.inner_val.as_f32 } as _),
563                lucet_val_type::F64 => Val::F64(unsafe { val.inner_val.as_f64 } as _),
564            }
565        }
566    }
567
568    impl From<Val> for lucet_val {
569        fn from(val: Val) -> Self {
570            (&val).into()
571        }
572    }
573
574    impl From<&Val> for lucet_val {
575        fn from(val: &Val) -> Self {
576            match val {
577                Val::CPtr(a) => lucet_val {
578                    ty: lucet_val_type::C_Ptr,
579                    inner_val: lucet_val_inner_val { as_u64: *a as _ },
580                },
581                Val::GuestPtr(a) => lucet_val {
582                    ty: lucet_val_type::GuestPtr,
583                    inner_val: lucet_val_inner_val { as_u64: *a as _ },
584                },
585                Val::U8(a) => lucet_val {
586                    ty: lucet_val_type::U8,
587                    inner_val: lucet_val_inner_val { as_u64: *a as _ },
588                },
589                Val::U16(a) => lucet_val {
590                    ty: lucet_val_type::U16,
591                    inner_val: lucet_val_inner_val { as_u64: *a as _ },
592                },
593                Val::U32(a) => lucet_val {
594                    ty: lucet_val_type::U32,
595                    inner_val: lucet_val_inner_val { as_u64: *a as _ },
596                },
597                Val::U64(a) => lucet_val {
598                    ty: lucet_val_type::U64,
599                    inner_val: lucet_val_inner_val { as_u64: *a as _ },
600                },
601                Val::I8(a) => lucet_val {
602                    ty: lucet_val_type::I8,
603                    inner_val: lucet_val_inner_val { as_i64: *a as _ },
604                },
605                Val::I16(a) => lucet_val {
606                    ty: lucet_val_type::I16,
607                    inner_val: lucet_val_inner_val { as_i64: *a as _ },
608                },
609                Val::I32(a) => lucet_val {
610                    ty: lucet_val_type::I32,
611                    inner_val: lucet_val_inner_val { as_i64: *a as _ },
612                },
613                Val::I64(a) => lucet_val {
614                    ty: lucet_val_type::I64,
615                    inner_val: lucet_val_inner_val { as_i64: *a as _ },
616                },
617                Val::USize(a) => lucet_val {
618                    ty: lucet_val_type::USize,
619                    inner_val: lucet_val_inner_val { as_u64: *a as _ },
620                },
621                Val::ISize(a) => lucet_val {
622                    ty: lucet_val_type::ISize,
623                    inner_val: lucet_val_inner_val { as_i64: *a as _ },
624                },
625                Val::Bool(a) => lucet_val {
626                    ty: lucet_val_type::Bool,
627                    inner_val: lucet_val_inner_val { as_u64: *a as _ },
628                },
629                Val::F32(a) => lucet_val {
630                    ty: lucet_val_type::F32,
631                    inner_val: lucet_val_inner_val { as_f32: *a as _ },
632                },
633                Val::F64(a) => lucet_val {
634                    ty: lucet_val_type::F64,
635                    inner_val: lucet_val_inner_val { as_f64: *a as _ },
636                },
637            }
638        }
639    }
640
641    #[repr(C)]
642    #[derive(Clone, Copy, Debug)]
643    pub struct lucet_untyped_retval {
644        pub fp: [c_char; 16],
645        pub gp: [c_char; 8],
646    }
647
648    #[repr(C)]
649    #[derive(Clone, Copy)]
650    pub union lucet_retval_gp {
651        pub as_untyped: [c_char; 8],
652        pub as_c_ptr: *mut c_void,
653        pub as_u64: u64,
654        pub as_i64: i64,
655    }
656
657    impl From<UntypedRetVal> for lucet_untyped_retval {
658        fn from(retval: UntypedRetVal) -> lucet_untyped_retval {
659            let mut v = lucet_untyped_retval {
660                fp: [0; 16],
661                gp: [0; 8],
662            };
663            unsafe {
664                core::arch::x86_64::_mm_storeu_ps(
665                    v.fp.as_mut().as_mut_ptr() as *mut f32,
666                    retval.fp(),
667                );
668                *(v.gp.as_mut().as_mut_ptr() as *mut u64) = retval.gp();
669            }
670            v
671        }
672    }
673}