wasmer_vm/
vmcontext.rs

1// This file contains code from external sources.
2// Attributions: https://github.com/wasmerio/wasmer/blob/master/ATTRIBUTIONS.md
3
4//! This file declares `VMContext` and several related structs which contain
5//! fields that compiled wasm code accesses directly.
6
7use crate::func_data_registry::VMFuncRef;
8use crate::global::Global;
9use crate::instance::Instance;
10use crate::memory::Memory;
11use crate::sig_registry::VMSharedSignatureIndex;
12use crate::table::Table;
13use crate::trap::{Trap, TrapCode};
14use crate::VMExternRef;
15use std::any::Any;
16use std::convert::TryFrom;
17use std::fmt;
18use std::ptr::{self, NonNull};
19use std::sync::Arc;
20use std::u32;
21
22/// Union representing the first parameter passed when calling a function.
23///
24/// It may either be a pointer to the [`VMContext`] if it's a Wasm function
25/// or a pointer to arbitrary data controlled by the host if it's a host function.
26#[derive(Copy, Clone, Eq)]
27pub union VMFunctionEnvironment {
28    /// Wasm functions take a pointer to [`VMContext`].
29    pub vmctx: *mut VMContext,
30    /// Host functions can have custom environments.
31    pub host_env: *mut std::ffi::c_void,
32}
33
34impl VMFunctionEnvironment {
35    /// Check whether the pointer stored is null or not.
36    pub fn is_null(&self) -> bool {
37        unsafe { self.host_env.is_null() }
38    }
39}
40
41impl std::fmt::Debug for VMFunctionEnvironment {
42    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
43        f.debug_struct("VMFunctionEnvironment")
44            .field("vmctx_or_hostenv", unsafe { &self.host_env })
45            .finish()
46    }
47}
48
49impl std::cmp::PartialEq for VMFunctionEnvironment {
50    fn eq(&self, rhs: &Self) -> bool {
51        unsafe { self.host_env as usize == rhs.host_env as usize }
52    }
53}
54
55impl std::hash::Hash for VMFunctionEnvironment {
56    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
57        unsafe {
58            self.vmctx.hash(state);
59        }
60    }
61}
62
63/// Represents a continuous region of executable memory starting with a function
64/// entry point.
65#[derive(Debug)]
66#[repr(C)]
67pub struct FunctionExtent {
68    /// Entry point for normal entry of the function. All addresses in the
69    /// function lie after this address.
70    pub address: FunctionBodyPtr,
71    /// Length in bytes.
72    pub length: usize,
73}
74
75/// An imported function.
76#[derive(Debug, Copy, Clone)]
77#[repr(C)]
78pub struct VMFunctionImport {
79    /// A pointer to the imported function body.
80    pub body: FunctionBodyPtr,
81
82    /// Function signature index within the source module.
83    pub signature: VMSharedSignatureIndex,
84
85    /// Function call trampoline
86    pub trampoline: Option<VMTrampoline>,
87
88    /// A pointer to the `VMContext` that owns the function or host env data.
89    pub environment: VMFunctionEnvironment,
90}
91
92#[cfg(test)]
93mod test_vmfunction_import {
94    use super::VMFunctionImport;
95    use crate::VMOffsets;
96    use memoffset::offset_of;
97    use std::mem::size_of;
98    use wasmer_types::ModuleInfo;
99
100    #[test]
101    fn check_vmfunction_import_offsets() {
102        let module = ModuleInfo::new();
103        let offsets = VMOffsets::new(size_of::<*mut u8>() as u8).with_module_info(&module);
104        assert_eq!(
105            size_of::<VMFunctionImport>(),
106            usize::from(offsets.size_of_vmfunction_import())
107        );
108        assert_eq!(
109            offset_of!(VMFunctionImport, body),
110            usize::from(offsets.vmfunction_import_body())
111        );
112        assert_eq!(
113            offset_of!(VMFunctionImport, environment),
114            usize::from(offsets.vmfunction_import_vmctx())
115        );
116    }
117}
118
119/// A locally defined function.
120#[derive(Debug, Copy, Clone)]
121#[repr(C)]
122pub struct VMLocalFunction {
123    /// A pointer to the imported function body.
124    pub body: FunctionBodyPtr,
125
126    /// Length of the function code
127    pub length: u32,
128
129    /// Function signature
130    pub signature: VMSharedSignatureIndex,
131
132    /// Trampoline for host->VM function calls.
133    pub trampoline: VMTrampoline,
134}
135
136/// The `VMDynamicFunctionContext` is the context that dynamic
137/// functions will receive when called (rather than `vmctx`).
138/// A dynamic function is a function for which we don't know the signature
139/// until runtime.
140///
141/// As such, we need to expose the dynamic function `context`
142/// containing the relevant context for running the function indicated
143/// in `address`.
144#[repr(C)]
145pub struct VMDynamicFunctionContext<T: Sized + Send + Sync> {
146    /// The address of the inner dynamic function.
147    ///
148    /// Note: The function must be on the form of
149    /// `(*mut T, SignatureIndex, *mut i128)`.
150    pub address: *const VMFunctionBody,
151
152    /// The context that the inner dynamic function will receive.
153    pub ctx: T,
154}
155
156// The `ctx` itself must be `Send`, `address` can be passed between
157// threads because all usage is `unsafe` and synchronized.
158unsafe impl<T: Sized + Send + Sync> Send for VMDynamicFunctionContext<T> {}
159// The `ctx` itself must be `Sync`, `address` can be shared between
160// threads because all usage is `unsafe` and synchronized.
161unsafe impl<T: Sized + Send + Sync> Sync for VMDynamicFunctionContext<T> {}
162
163impl<T: Sized + Clone + Send + Sync> Clone for VMDynamicFunctionContext<T> {
164    fn clone(&self) -> Self {
165        Self {
166            address: self.address,
167            ctx: self.ctx.clone(),
168        }
169    }
170}
171
172#[cfg(test)]
173mod test_vmdynamicfunction_import_context {
174    use super::VMDynamicFunctionContext;
175    use crate::VMOffsets;
176    use memoffset::offset_of;
177    use std::mem::size_of;
178    use wasmer_types::ModuleInfo;
179
180    #[test]
181    fn check_vmdynamicfunction_import_context_offsets() {
182        let module = ModuleInfo::new();
183        let offsets = VMOffsets::new(size_of::<*mut u8>() as u8).with_module_info(&module);
184        assert_eq!(
185            size_of::<VMDynamicFunctionContext<usize>>(),
186            usize::from(offsets.size_of_vmdynamicfunction_import_context())
187        );
188        assert_eq!(
189            offset_of!(VMDynamicFunctionContext<usize>, address),
190            usize::from(offsets.vmdynamicfunction_import_context_address())
191        );
192        assert_eq!(
193            offset_of!(VMDynamicFunctionContext<usize>, ctx),
194            usize::from(offsets.vmdynamicfunction_import_context_ctx())
195        );
196    }
197}
198
199/// A placeholder byte-sized type which is just used to provide some amount of type
200/// safety when dealing with pointers to JIT-compiled function bodies. Note that it's
201/// deliberately not Copy, as we shouldn't be carelessly copying function body bytes
202/// around.
203#[repr(C)]
204pub struct VMFunctionBody(u8);
205
206#[cfg(test)]
207mod test_vmfunction_body {
208    use super::VMFunctionBody;
209    use std::mem::size_of;
210
211    #[test]
212    fn check_vmfunction_body_offsets() {
213        assert_eq!(size_of::<VMFunctionBody>(), 1);
214    }
215}
216
217/// A pointer to the beginning of the function body.
218#[derive(Clone, Copy, Debug)]
219#[repr(transparent)]
220pub struct FunctionBodyPtr(pub *const VMFunctionBody);
221
222impl std::ops::Deref for FunctionBodyPtr {
223    type Target = *const VMFunctionBody;
224
225    fn deref(&self) -> &Self::Target {
226        &self.0
227    }
228}
229
230// SAFETY: The VMFunctionBody that this points to is opaque, so there's no data to read or write
231// through this pointer. This is essentially a usize.
232unsafe impl Send for FunctionBodyPtr {}
233
234/// SAFETY: The VMFunctionBody that this points to is opaque, so there's no data to read or write
235/// through this pointer. This is essentially a usize.
236unsafe impl Sync for FunctionBodyPtr {}
237
238/// A function kind is a calling convention into and out of wasm code.
239#[derive(Debug, Copy, Clone, PartialEq)]
240#[repr(C)]
241pub enum VMFunctionKind {
242    /// A static function has the native signature:
243    /// `extern "C" (vmctx, arg1, arg2...) -> (result1, result2, ...)`.
244    ///
245    /// This is the default for functions that are defined:
246    /// 1. In the Host, natively
247    /// 2. In the WebAssembly file
248    Static,
249
250    /// A dynamic function has the native signature:
251    /// `extern "C" (ctx, &[Value]) -> Vec<Value>`.
252    ///
253    /// This is the default for functions that are defined:
254    /// 1. In the Host, dynamically
255    Dynamic,
256}
257
258/// The fields compiled code needs to access to utilize a WebAssembly table
259/// imported from another instance.
260#[derive(Debug, Clone)]
261#[repr(C)]
262pub struct VMTableImport {
263    /// A pointer to the imported table description.
264    pub definition: NonNull<VMTableDefinition>,
265
266    /// A pointer to the `Table` that owns the table description.
267    pub from: Arc<dyn Table>,
268}
269
270#[cfg(test)]
271mod test_vmtable_import {
272    use super::VMTableImport;
273    use crate::VMOffsets;
274    use memoffset::offset_of;
275    use std::mem::size_of;
276    use wasmer_types::ModuleInfo;
277
278    #[test]
279    fn check_vmtable_import_offsets() {
280        let module = ModuleInfo::new();
281        let offsets = VMOffsets::new(size_of::<*mut u8>() as u8).with_module_info(&module);
282        assert_eq!(
283            size_of::<VMTableImport>(),
284            usize::from(offsets.size_of_vmtable_import())
285        );
286        assert_eq!(
287            offset_of!(VMTableImport, definition),
288            usize::from(offsets.vmtable_import_definition())
289        );
290        assert_eq!(
291            offset_of!(VMTableImport, from),
292            usize::from(offsets.vmtable_import_from())
293        );
294    }
295}
296
297/// The fields compiled code needs to access to utilize a WebAssembly linear
298/// memory imported from another instance.
299#[derive(Debug, Clone)]
300#[repr(C)]
301pub struct VMMemoryImport {
302    /// A pointer to the imported memory description.
303    pub definition: NonNull<VMMemoryDefinition>,
304
305    /// A pointer to the `Memory` that owns the memory description.
306    pub from: Arc<dyn Memory>,
307}
308
309#[cfg(test)]
310mod test_vmmemory_import {
311    use super::VMMemoryImport;
312    use crate::VMOffsets;
313    use memoffset::offset_of;
314    use std::mem::size_of;
315    use wasmer_types::ModuleInfo;
316
317    #[test]
318    fn check_vmmemory_import_offsets() {
319        let module = ModuleInfo::new();
320        let offsets = VMOffsets::new(size_of::<*mut u8>() as u8).with_module_info(&module);
321        assert_eq!(
322            size_of::<VMMemoryImport>(),
323            usize::from(offsets.size_of_vmmemory_import())
324        );
325        assert_eq!(
326            offset_of!(VMMemoryImport, definition),
327            usize::from(offsets.vmmemory_import_definition())
328        );
329        assert_eq!(
330            offset_of!(VMMemoryImport, from),
331            usize::from(offsets.vmmemory_import_from())
332        );
333    }
334}
335
336/// The fields compiled code needs to access to utilize a WebAssembly global
337/// variable imported from another instance.
338#[derive(Debug, Clone)]
339#[repr(C)]
340pub struct VMGlobalImport {
341    /// A pointer to the imported global variable description.
342    pub definition: NonNull<VMGlobalDefinition>,
343
344    /// A pointer to the `Global` that owns the global description.
345    pub from: Arc<Global>,
346}
347
348/// # Safety
349/// This data is safe to share between threads because it's plain data that
350/// is the user's responsibility to synchronize. Additionally, all operations
351/// on `from` are thread-safe through the use of a mutex in [`Global`].
352unsafe impl Send for VMGlobalImport {}
353/// # Safety
354/// This data is safe to share between threads because it's plain data that
355/// is the user's responsibility to synchronize. And because it's `Clone`, there's
356/// really no difference between passing it by reference or by value as far as
357/// correctness in a multi-threaded context is concerned.
358unsafe impl Sync for VMGlobalImport {}
359
360#[cfg(test)]
361mod test_vmglobal_import {
362    use super::VMGlobalImport;
363    use crate::VMOffsets;
364    use memoffset::offset_of;
365    use std::mem::size_of;
366    use wasmer_types::ModuleInfo;
367
368    #[test]
369    fn check_vmglobal_import_offsets() {
370        let module = ModuleInfo::new();
371        let offsets = VMOffsets::new(size_of::<*mut u8>() as u8).with_module_info(&module);
372        assert_eq!(
373            size_of::<VMGlobalImport>(),
374            usize::from(offsets.size_of_vmglobal_import())
375        );
376        assert_eq!(
377            offset_of!(VMGlobalImport, definition),
378            usize::from(offsets.vmglobal_import_definition())
379        );
380        assert_eq!(
381            offset_of!(VMGlobalImport, from),
382            usize::from(offsets.vmglobal_import_from())
383        );
384    }
385}
386
387/// The fields compiled code needs to access to utilize a WebAssembly linear
388/// memory defined within the instance, namely the start address and the
389/// size in bytes.
390#[derive(Debug, Copy, Clone)]
391#[repr(C)]
392pub struct VMMemoryDefinition {
393    /// The start address which is always valid, even if the memory grows.
394    pub base: *mut u8,
395
396    /// The current logical size of this linear memory in bytes.
397    pub current_length: usize,
398}
399
400/// # Safety
401/// This data is safe to share between threads because it's plain data that
402/// is the user's responsibility to synchronize.
403unsafe impl Send for VMMemoryDefinition {}
404/// # Safety
405/// This data is safe to share between threads because it's plain data that
406/// is the user's responsibility to synchronize. And it's `Copy` so there's
407/// really no difference between passing it by reference or by value as far as
408/// correctness in a multi-threaded context is concerned.
409unsafe impl Sync for VMMemoryDefinition {}
410
411impl VMMemoryDefinition {
412    /// Do an unsynchronized, non-atomic `memory.copy` for the memory.
413    ///
414    /// # Errors
415    ///
416    /// Returns a `Trap` error when the source or destination ranges are out of
417    /// bounds.
418    ///
419    /// # Safety
420    ///
421    /// The memory is not copied atomically and is not synchronized: it's the
422    /// caller's responsibility to synchronize.
423    pub(crate) unsafe fn memory_copy(&self, dst: u32, src: u32, len: u32) -> Result<(), Trap> {
424        // https://webassembly.github.io/reference-types/core/exec/instructions.html#exec-memory-copy
425        if src
426            .checked_add(len)
427            .map_or(true, |n| usize::try_from(n).unwrap() > self.current_length)
428            || dst
429                .checked_add(len)
430                .map_or(true, |m| usize::try_from(m).unwrap() > self.current_length)
431        {
432            return Err(Trap::lib(TrapCode::HeapAccessOutOfBounds));
433        }
434
435        let dst = usize::try_from(dst).unwrap();
436        let src = usize::try_from(src).unwrap();
437
438        // Bounds and casts are checked above, by this point we know that
439        // everything is safe.
440        let dst = self.base.add(dst);
441        let src = self.base.add(src);
442        ptr::copy(src, dst, len as usize);
443
444        Ok(())
445    }
446
447    /// Perform the `memory.fill` operation for the memory in an unsynchronized,
448    /// non-atomic way.
449    ///
450    /// # Errors
451    ///
452    /// Returns a `Trap` error if the memory range is out of bounds.
453    ///
454    /// # Safety
455    /// The memory is not filled atomically and is not synchronized: it's the
456    /// caller's responsibility to synchronize.
457    pub(crate) unsafe fn memory_fill(&self, dst: u32, val: u32, len: u32) -> Result<(), Trap> {
458        if dst
459            .checked_add(len)
460            .map_or(true, |m| usize::try_from(m).unwrap() > self.current_length)
461        {
462            return Err(Trap::lib(TrapCode::HeapAccessOutOfBounds));
463        }
464
465        let dst = isize::try_from(dst).unwrap();
466        let val = val as u8;
467
468        // Bounds and casts are checked above, by this point we know that
469        // everything is safe.
470        let dst = self.base.offset(dst);
471        ptr::write_bytes(dst, val, len as usize);
472
473        Ok(())
474    }
475}
476
477#[cfg(test)]
478mod test_vmmemory_definition {
479    use super::VMMemoryDefinition;
480    use crate::VMOffsets;
481    use memoffset::offset_of;
482    use std::mem::size_of;
483    use wasmer_types::ModuleInfo;
484
485    #[test]
486    fn check_vmmemory_definition_offsets() {
487        let module = ModuleInfo::new();
488        let offsets = VMOffsets::new(size_of::<*mut u8>() as u8).with_module_info(&module);
489        assert_eq!(
490            size_of::<VMMemoryDefinition>(),
491            usize::from(offsets.size_of_vmmemory_definition())
492        );
493        assert_eq!(
494            offset_of!(VMMemoryDefinition, base),
495            usize::from(offsets.vmmemory_definition_base())
496        );
497        assert_eq!(
498            offset_of!(VMMemoryDefinition, current_length),
499            usize::from(offsets.vmmemory_definition_current_length())
500        );
501    }
502}
503
504/// The fields compiled code needs to access to utilize a WebAssembly table
505/// defined within the instance.
506#[derive(Debug, Clone, Copy)]
507#[repr(C)]
508pub struct VMTableDefinition {
509    /// Pointer to the table data.
510    pub base: *mut u8,
511
512    /// The current number of elements in the table.
513    pub current_elements: u32,
514}
515
516#[cfg(test)]
517mod test_vmtable_definition {
518    use super::VMTableDefinition;
519    use crate::VMOffsets;
520    use memoffset::offset_of;
521    use std::mem::size_of;
522    use wasmer_types::ModuleInfo;
523
524    #[test]
525    fn check_vmtable_definition_offsets() {
526        let module = ModuleInfo::new();
527        let offsets = VMOffsets::new(size_of::<*mut u8>() as u8).with_module_info(&module);
528        assert_eq!(
529            size_of::<VMTableDefinition>(),
530            usize::from(offsets.size_of_vmtable_definition())
531        );
532        assert_eq!(
533            offset_of!(VMTableDefinition, base),
534            usize::from(offsets.vmtable_definition_base())
535        );
536        assert_eq!(
537            offset_of!(VMTableDefinition, current_elements),
538            usize::from(offsets.vmtable_definition_current_elements())
539        );
540    }
541}
542
543/// A typesafe wrapper around the storage for a global variables.
544///
545/// # Safety
546///
547/// Accessing the different members of this union is always safe because there
548/// are no invalid values for any of the types and the whole object is
549/// initialized by VMGlobalDefinition::new().
550#[derive(Clone, Copy)]
551#[repr(C, align(16))]
552pub union VMGlobalDefinitionStorage {
553    as_i32: i32,
554    as_u32: u32,
555    as_f32: f32,
556    as_i64: i64,
557    as_u64: u64,
558    as_f64: f64,
559    as_u128: u128,
560    as_funcref: VMFuncRef,
561    as_externref: VMExternRef,
562    bytes: [u8; 16],
563}
564
565impl fmt::Debug for VMGlobalDefinitionStorage {
566    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
567        f.debug_struct("VMGlobalDefinitionStorage")
568            .field("bytes", unsafe { &self.bytes })
569            .finish()
570    }
571}
572
573/// The storage for a WebAssembly global defined within the instance.
574///
575/// TODO: Pack the globals more densely, rather than using the same size
576/// for every type.
577#[derive(Debug, Clone)]
578#[repr(C, align(16))]
579pub struct VMGlobalDefinition {
580    storage: VMGlobalDefinitionStorage,
581    // If more elements are added here, remember to add offset_of tests below!
582}
583
584#[cfg(test)]
585mod test_vmglobal_definition {
586    use super::VMGlobalDefinition;
587    use crate::{VMFuncRef, VMOffsets};
588    use more_asserts::assert_ge;
589    use std::mem::{align_of, size_of};
590    use wasmer_types::ModuleInfo;
591
592    #[test]
593    fn check_vmglobal_definition_alignment() {
594        assert_ge!(align_of::<VMGlobalDefinition>(), align_of::<i32>());
595        assert_ge!(align_of::<VMGlobalDefinition>(), align_of::<i64>());
596        assert_ge!(align_of::<VMGlobalDefinition>(), align_of::<f32>());
597        assert_ge!(align_of::<VMGlobalDefinition>(), align_of::<f64>());
598        assert_ge!(align_of::<VMGlobalDefinition>(), align_of::<VMFuncRef>());
599        assert_ge!(align_of::<VMGlobalDefinition>(), align_of::<[u8; 16]>());
600    }
601
602    #[test]
603    fn check_vmglobal_definition_offsets() {
604        let module = ModuleInfo::new();
605        let offsets = VMOffsets::new(size_of::<*mut u8>() as u8).with_module_info(&module);
606        assert_eq!(
607            size_of::<*const VMGlobalDefinition>(),
608            usize::from(offsets.size_of_vmglobal_local())
609        );
610    }
611
612    #[test]
613    fn check_vmglobal_begins_aligned() {
614        let module = ModuleInfo::new();
615        let offsets = VMOffsets::new(size_of::<*mut u8>() as u8).with_module_info(&module);
616        assert_eq!(offsets.vmctx_globals_begin() % 16, 0);
617    }
618}
619
620impl VMGlobalDefinition {
621    /// Construct a `VMGlobalDefinition`.
622    pub fn new() -> Self {
623        Self {
624            storage: VMGlobalDefinitionStorage { bytes: [0; 16] },
625        }
626    }
627
628    /// Return the value as an i32.
629    ///
630    /// If this is not an I32 typed global it is unspecified what value is returned.
631    pub fn to_i32(&self) -> i32 {
632        unsafe { self.storage.as_i32 }
633    }
634
635    /// Return a mutable reference to the value as an i32.
636    ///
637    /// # Safety
638    ///
639    /// It is the callers responsibility to make sure the global has I32 type.
640    /// Until the returned borrow is dropped, reads and writes of this global
641    /// must be done exclusively through this borrow. That includes reads and
642    /// writes of globals inside wasm functions.
643    pub unsafe fn as_i32_mut(&mut self) -> &mut i32 {
644        &mut self.storage.as_i32
645    }
646
647    /// Return a reference to the value as an u32.
648    ///
649    /// If this is not an I32 typed global it is unspecified what value is returned.
650    pub fn to_u32(&self) -> u32 {
651        unsafe { self.storage.as_u32 }
652    }
653
654    /// Return a mutable reference to the value as an u32.
655    ///
656    /// # Safety
657    ///
658    /// It is the callers responsibility to make sure the global has I32 type.
659    /// Until the returned borrow is dropped, reads and writes of this global
660    /// must be done exclusively through this borrow. That includes reads and
661    /// writes of globals inside wasm functions.
662    pub unsafe fn as_u32_mut(&mut self) -> &mut u32 {
663        &mut self.storage.as_u32
664    }
665
666    /// Return a reference to the value as an i64.
667    ///
668    /// If this is not an I64 typed global it is unspecified what value is returned.
669    pub fn to_i64(&self) -> i64 {
670        unsafe { self.storage.as_i64 }
671    }
672
673    /// Return a mutable reference to the value as an i64.
674    ///
675    /// # Safety
676    ///
677    /// It is the callers responsibility to make sure the global has I32 type.
678    /// Until the returned borrow is dropped, reads and writes of this global
679    /// must be done exclusively through this borrow. That includes reads and
680    /// writes of globals inside wasm functions.
681    pub unsafe fn as_i64_mut(&mut self) -> &mut i64 {
682        &mut self.storage.as_i64
683    }
684
685    /// Return a reference to the value as an u64.
686    ///
687    /// If this is not an I64 typed global it is unspecified what value is returned.
688    pub fn to_u64(&self) -> u64 {
689        unsafe { self.storage.as_u64 }
690    }
691
692    /// Return a mutable reference to the value as an u64.
693    ///
694    /// # Safety
695    ///
696    /// It is the callers responsibility to make sure the global has I64 type.
697    /// Until the returned borrow is dropped, reads and writes of this global
698    /// must be done exclusively through this borrow. That includes reads and
699    /// writes of globals inside wasm functions.
700    pub unsafe fn as_u64_mut(&mut self) -> &mut u64 {
701        &mut self.storage.as_u64
702    }
703
704    /// Return a reference to the value as an f32.
705    ///
706    /// If this is not an F32 typed global it is unspecified what value is returned.
707    pub fn to_f32(&self) -> f32 {
708        unsafe { self.storage.as_f32 }
709    }
710
711    /// Return a mutable reference to the value as an f32.
712    ///
713    /// # Safety
714    ///
715    /// It is the callers responsibility to make sure the global has F32 type.
716    /// Until the returned borrow is dropped, reads and writes of this global
717    /// must be done exclusively through this borrow. That includes reads and
718    /// writes of globals inside wasm functions.
719    pub unsafe fn as_f32_mut(&mut self) -> &mut f32 {
720        &mut self.storage.as_f32
721    }
722
723    /// Return a reference to the value as an f64.
724    ///
725    /// If this is not an F64 typed global it is unspecified what value is returned.
726    pub fn to_f64(&self) -> f64 {
727        unsafe { self.storage.as_f64 }
728    }
729
730    /// Return a mutable reference to the value as an f64.
731    ///
732    /// # Safety
733    ///
734    /// It is the callers responsibility to make sure the global has F64 type.
735    /// Until the returned borrow is dropped, reads and writes of this global
736    /// must be done exclusively through this borrow. That includes reads and
737    /// writes of globals inside wasm functions.
738    pub unsafe fn as_f64_mut(&mut self) -> &mut f64 {
739        &mut self.storage.as_f64
740    }
741
742    /// Return a reference to the value as a `VMFuncRef`.
743    ///
744    /// If this is not a `VMFuncRef` typed global it is unspecified what value is returned.
745    pub fn to_funcref(&self) -> VMFuncRef {
746        unsafe { self.storage.as_funcref }
747    }
748
749    /// Return a mutable reference to the value as a `VMFuncRef`.
750    ///
751    /// # Safety
752    ///
753    /// It is the callers responsibility to make sure the global has `VMFuncRef` type.
754    /// Until the returned borrow is dropped, reads and writes of this global
755    /// must be done exclusively through this borrow. That includes reads and
756    /// writes of globals inside wasm functions.
757    pub unsafe fn as_funcref_mut(&mut self) -> &mut VMFuncRef {
758        &mut self.storage.as_funcref
759    }
760
761    /// Return a mutable reference to the value as an `VMExternRef`.
762    ///
763    /// # Safety
764    ///
765    /// It is the callers responsibility to make sure the global has I32 type.
766    /// Until the returned borrow is dropped, reads and writes of this global
767    /// must be done exclusively through this borrow. That includes reads and
768    /// writes of globals inside wasm functions.
769    pub unsafe fn as_externref_mut(&mut self) -> &mut VMExternRef {
770        &mut self.storage.as_externref
771    }
772
773    /// Return a reference to the value as an `VMExternRef`.
774    ///
775    /// If this is not an I64 typed global it is unspecified what value is returned.
776    pub fn to_externref(&self) -> VMExternRef {
777        unsafe { self.storage.as_externref }
778    }
779
780    /// Return a reference to the value as an u128.
781    ///
782    /// If this is not an V128 typed global it is unspecified what value is returned.
783    pub fn to_u128(&self) -> u128 {
784        unsafe { self.storage.as_u128 }
785    }
786
787    /// Return a mutable reference to the value as an u128.
788    ///
789    /// # Safety
790    ///
791    /// It is the callers responsibility to make sure the global has V128 type.
792    /// Until the returned borrow is dropped, reads and writes of this global
793    /// must be done exclusively through this borrow. That includes reads and
794    /// writes of globals inside wasm functions.
795    pub unsafe fn as_u128_mut(&mut self) -> &mut u128 {
796        &mut self.storage.as_u128
797    }
798
799    /// Return a reference to the value as bytes.
800    pub fn to_bytes(&self) -> [u8; 16] {
801        unsafe { self.storage.bytes }
802    }
803
804    /// Return a mutable reference to the value as bytes.
805    ///
806    /// # Safety
807    ///
808    /// Until the returned borrow is dropped, reads and writes of this global
809    /// must be done exclusively through this borrow. That includes reads and
810    /// writes of globals inside wasm functions.
811    pub unsafe fn as_bytes_mut(&mut self) -> &mut [u8; 16] {
812        &mut self.storage.bytes
813    }
814}
815
816#[cfg(test)]
817mod test_vmshared_signature_index {
818    use super::VMSharedSignatureIndex;
819    use crate::vmoffsets::{TargetSharedSignatureIndex, VMOffsets};
820    use std::mem::size_of;
821    use wasmer_types::ModuleInfo;
822
823    #[test]
824    fn check_vmshared_signature_index() {
825        let module = ModuleInfo::new();
826        let offsets = VMOffsets::new(size_of::<*mut u8>() as u8).with_module_info(&module);
827        assert_eq!(
828            size_of::<VMSharedSignatureIndex>(),
829            usize::from(offsets.size_of_vmshared_signature_index())
830        );
831    }
832
833    #[test]
834    fn check_target_shared_signature_index() {
835        assert_eq!(
836            size_of::<VMSharedSignatureIndex>(),
837            size_of::<TargetSharedSignatureIndex>()
838        );
839    }
840}
841
842/// The VM caller-checked "anyfunc" record, for caller-side signature checking.
843/// It consists of the actual function pointer and a signature id to be checked
844/// by the caller.
845#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
846#[repr(C)]
847pub struct VMCallerCheckedAnyfunc {
848    /// Function body.
849    pub func_ptr: *const VMFunctionBody,
850    /// Function signature id.
851    pub type_index: VMSharedSignatureIndex,
852    /// Function `VMContext` or host env.
853    pub vmctx: VMFunctionEnvironment,
854    // If more elements are added here, remember to add offset_of tests below!
855}
856
857#[cfg(test)]
858mod test_vmcaller_checked_anyfunc {
859    use super::VMCallerCheckedAnyfunc;
860    use crate::VMOffsets;
861    use memoffset::offset_of;
862    use std::mem::size_of;
863    use wasmer_types::ModuleInfo;
864
865    #[test]
866    fn check_vmcaller_checked_anyfunc_offsets() {
867        let module = ModuleInfo::new();
868        let offsets = VMOffsets::new(size_of::<*mut u8>() as u8).with_module_info(&module);
869        assert_eq!(
870            size_of::<VMCallerCheckedAnyfunc>(),
871            usize::from(offsets.size_of_vmcaller_checked_anyfunc())
872        );
873        assert_eq!(
874            offset_of!(VMCallerCheckedAnyfunc, func_ptr),
875            usize::from(offsets.vmcaller_checked_anyfunc_func_ptr())
876        );
877        assert_eq!(
878            offset_of!(VMCallerCheckedAnyfunc, type_index),
879            usize::from(offsets.vmcaller_checked_anyfunc_type_index())
880        );
881        assert_eq!(
882            offset_of!(VMCallerCheckedAnyfunc, vmctx),
883            usize::from(offsets.vmcaller_checked_anyfunc_vmctx())
884        );
885    }
886}
887
888/// An index type for builtin functions.
889#[derive(Copy, Clone, Debug)]
890pub struct VMBuiltinFunctionIndex(u32);
891
892impl VMBuiltinFunctionIndex {
893    /// Returns an index for wasm's `memory.grow` builtin function.
894    pub const fn get_memory32_grow_index() -> Self {
895        Self(0)
896    }
897    /// Returns an index for wasm's imported `memory.grow` builtin function.
898    pub const fn get_imported_memory32_grow_index() -> Self {
899        Self(1)
900    }
901    /// Returns an index for wasm's `memory.size` builtin function.
902    pub const fn get_memory32_size_index() -> Self {
903        Self(2)
904    }
905    /// Returns an index for wasm's imported `memory.size` builtin function.
906    pub const fn get_imported_memory32_size_index() -> Self {
907        Self(3)
908    }
909    /// Returns an index for wasm's `table.copy` when both tables are locally
910    /// defined.
911    pub const fn get_table_copy_index() -> Self {
912        Self(4)
913    }
914    /// Returns an index for wasm's `table.init`.
915    pub const fn get_table_init_index() -> Self {
916        Self(5)
917    }
918    /// Returns an index for wasm's `elem.drop`.
919    pub const fn get_elem_drop_index() -> Self {
920        Self(6)
921    }
922    /// Returns an index for wasm's `memory.copy` for locally defined memories.
923    pub const fn get_memory_copy_index() -> Self {
924        Self(7)
925    }
926    /// Returns an index for wasm's `memory.copy` for imported memories.
927    pub const fn get_imported_memory_copy_index() -> Self {
928        Self(8)
929    }
930    /// Returns an index for wasm's `memory.fill` for locally defined memories.
931    pub const fn get_memory_fill_index() -> Self {
932        Self(9)
933    }
934    /// Returns an index for wasm's `memory.fill` for imported memories.
935    pub const fn get_imported_memory_fill_index() -> Self {
936        Self(10)
937    }
938    /// Returns an index for wasm's `memory.init` instruction.
939    pub const fn get_memory_init_index() -> Self {
940        Self(11)
941    }
942    /// Returns an index for wasm's `data.drop` instruction.
943    pub const fn get_data_drop_index() -> Self {
944        Self(12)
945    }
946    /// Returns an index for wasm's `raise_trap` instruction.
947    pub const fn get_raise_trap_index() -> Self {
948        Self(13)
949    }
950    /// Returns an index for wasm's `table.size` instruction for local tables.
951    pub const fn get_table_size_index() -> Self {
952        Self(14)
953    }
954    /// Returns an index for wasm's `table.size` instruction for imported tables.
955    pub const fn get_imported_table_size_index() -> Self {
956        Self(15)
957    }
958    /// Returns an index for wasm's `table.grow` instruction for local tables.
959    pub const fn get_table_grow_index() -> Self {
960        Self(16)
961    }
962    /// Returns an index for wasm's `table.grow` instruction for imported tables.
963    pub const fn get_imported_table_grow_index() -> Self {
964        Self(17)
965    }
966    /// Returns an index for wasm's `table.get` instruction for local tables.
967    pub const fn get_table_get_index() -> Self {
968        Self(18)
969    }
970    /// Returns an index for wasm's `table.get` instruction for imported tables.
971    pub const fn get_imported_table_get_index() -> Self {
972        Self(19)
973    }
974    /// Returns an index for wasm's `table.set` instruction for local tables.
975    pub const fn get_table_set_index() -> Self {
976        Self(20)
977    }
978    /// Returns an index for wasm's `table.set` instruction for imported tables.
979    pub const fn get_imported_table_set_index() -> Self {
980        Self(21)
981    }
982    /// Returns an index for wasm's `func.ref` instruction.
983    pub const fn get_func_ref_index() -> Self {
984        Self(22)
985    }
986    /// Returns an index for wasm's `table.fill` instruction for local tables.
987    pub const fn get_table_fill_index() -> Self {
988        Self(23)
989    }
990    /// Returns an index for a function to increment the externref count.
991    pub const fn get_externref_inc_index() -> Self {
992        Self(24)
993    }
994    /// Returns an index for a function to decrement the externref count.
995    pub const fn get_externref_dec_index() -> Self {
996        Self(25)
997    }
998    /// Returns the total number of builtin functions.
999    pub const fn builtin_functions_total_number() -> u32 {
1000        26
1001    }
1002
1003    /// Return the index as an u32 number.
1004    pub const fn index(self) -> u32 {
1005        self.0
1006    }
1007}
1008
1009/// An array that stores addresses of builtin functions. We translate code
1010/// to use indirect calls. This way, we don't have to patch the code.
1011#[repr(C)]
1012pub struct VMBuiltinFunctionsArray {
1013    ptrs: [usize; Self::len()],
1014}
1015
1016impl VMBuiltinFunctionsArray {
1017    pub const fn len() -> usize {
1018        VMBuiltinFunctionIndex::builtin_functions_total_number() as usize
1019    }
1020
1021    pub fn initialized() -> Self {
1022        use crate::libcalls::*;
1023
1024        let mut ptrs = [0; Self::len()];
1025
1026        ptrs[VMBuiltinFunctionIndex::get_memory32_grow_index().index() as usize] =
1027            wasmer_vm_memory32_grow as usize;
1028        ptrs[VMBuiltinFunctionIndex::get_imported_memory32_grow_index().index() as usize] =
1029            wasmer_vm_imported_memory32_grow as usize;
1030
1031        ptrs[VMBuiltinFunctionIndex::get_memory32_size_index().index() as usize] =
1032            wasmer_vm_memory32_size as usize;
1033        ptrs[VMBuiltinFunctionIndex::get_imported_memory32_size_index().index() as usize] =
1034            wasmer_vm_imported_memory32_size as usize;
1035
1036        ptrs[VMBuiltinFunctionIndex::get_table_copy_index().index() as usize] =
1037            wasmer_vm_table_copy as usize;
1038
1039        ptrs[VMBuiltinFunctionIndex::get_table_init_index().index() as usize] =
1040            wasmer_vm_table_init as usize;
1041        ptrs[VMBuiltinFunctionIndex::get_elem_drop_index().index() as usize] =
1042            wasmer_vm_elem_drop as usize;
1043
1044        ptrs[VMBuiltinFunctionIndex::get_memory_copy_index().index() as usize] =
1045            wasmer_vm_memory32_copy as usize;
1046        ptrs[VMBuiltinFunctionIndex::get_imported_memory_copy_index().index() as usize] =
1047            wasmer_vm_imported_memory32_copy as usize;
1048        ptrs[VMBuiltinFunctionIndex::get_memory_fill_index().index() as usize] =
1049            wasmer_vm_memory32_fill as usize;
1050        ptrs[VMBuiltinFunctionIndex::get_imported_memory_fill_index().index() as usize] =
1051            wasmer_vm_imported_memory32_fill as usize;
1052        ptrs[VMBuiltinFunctionIndex::get_memory_init_index().index() as usize] =
1053            wasmer_vm_memory32_init as usize;
1054        ptrs[VMBuiltinFunctionIndex::get_data_drop_index().index() as usize] =
1055            wasmer_vm_data_drop as usize;
1056        ptrs[VMBuiltinFunctionIndex::get_raise_trap_index().index() as usize] =
1057            wasmer_vm_raise_trap as usize;
1058        ptrs[VMBuiltinFunctionIndex::get_table_size_index().index() as usize] =
1059            wasmer_vm_table_size as usize;
1060        ptrs[VMBuiltinFunctionIndex::get_imported_table_size_index().index() as usize] =
1061            wasmer_vm_imported_table_size as usize;
1062        ptrs[VMBuiltinFunctionIndex::get_table_grow_index().index() as usize] =
1063            wasmer_vm_table_grow as usize;
1064        ptrs[VMBuiltinFunctionIndex::get_imported_table_grow_index().index() as usize] =
1065            wasmer_vm_imported_table_grow as usize;
1066        ptrs[VMBuiltinFunctionIndex::get_table_get_index().index() as usize] =
1067            wasmer_vm_table_get as usize;
1068        ptrs[VMBuiltinFunctionIndex::get_imported_table_get_index().index() as usize] =
1069            wasmer_vm_imported_table_get as usize;
1070        ptrs[VMBuiltinFunctionIndex::get_table_set_index().index() as usize] =
1071            wasmer_vm_table_set as usize;
1072        ptrs[VMBuiltinFunctionIndex::get_imported_table_set_index().index() as usize] =
1073            wasmer_vm_imported_table_set as usize;
1074        ptrs[VMBuiltinFunctionIndex::get_func_ref_index().index() as usize] =
1075            wasmer_vm_func_ref as usize;
1076        ptrs[VMBuiltinFunctionIndex::get_table_fill_index().index() as usize] =
1077            wasmer_vm_table_fill as usize;
1078        ptrs[VMBuiltinFunctionIndex::get_externref_inc_index().index() as usize] =
1079            wasmer_vm_externref_inc as usize;
1080        ptrs[VMBuiltinFunctionIndex::get_externref_dec_index().index() as usize] =
1081            wasmer_vm_externref_dec as usize;
1082
1083        debug_assert!(ptrs.iter().cloned().all(|p| p != 0));
1084
1085        Self { ptrs }
1086    }
1087}
1088
1089/// The VM "context", which is pointed to by the `vmctx` arg in the compiler.
1090/// This has information about globals, memories, tables, and other runtime
1091/// state associated with the current instance.
1092///
1093/// The struct here is empty, as the sizes of these fields are dynamic, and
1094/// we can't describe them in Rust's type system. Sufficient memory is
1095/// allocated at runtime.
1096///
1097/// TODO: We could move the globals into the `vmctx` allocation too.
1098#[derive(Debug)]
1099#[repr(C, align(16))] // align 16 since globals are aligned to that and contained inside
1100pub struct VMContext {}
1101
1102impl VMContext {
1103    /// Return a mutable reference to the associated `Instance`.
1104    ///
1105    /// # Safety
1106    /// This is unsafe because it doesn't work on just any `VMContext`, it must
1107    /// be a `VMContext` allocated as part of an `Instance`.
1108    #[allow(clippy::cast_ptr_alignment)]
1109    #[inline]
1110    pub(crate) unsafe fn instance(&self) -> &Instance {
1111        &*((self as *const Self as *mut u8).offset(-Instance::vmctx_offset()) as *const Instance)
1112    }
1113
1114    /// Return a reference to the host state associated with this `Instance`.
1115    ///
1116    /// # Safety
1117    /// This is unsafe because it doesn't work on just any `VMContext`, it must
1118    /// be a `VMContext` allocated as part of an `Instance`.
1119    #[inline]
1120    pub unsafe fn host_state(&self) -> &dyn Any {
1121        self.instance().host_state()
1122    }
1123}
1124
1125///
1126pub type VMTrampoline = unsafe extern "C" fn(
1127    *mut VMContext,        // callee vmctx
1128    *const VMFunctionBody, // function we're actually calling
1129    *mut u128,             // space for arguments and return values
1130);
1131
1132/// Pointers to section data.
1133#[derive(Clone, Copy, Debug)]
1134#[repr(transparent)]
1135pub struct SectionBodyPtr(pub *const u8);
1136
1137impl std::ops::Deref for SectionBodyPtr {
1138    type Target = *const u8;
1139
1140    fn deref(&self) -> &Self::Target {
1141        &self.0
1142    }
1143}