1 //! Runtime support for the component model in Wasmtime
2 //!
3 //! Currently this runtime support includes a `VMComponentContext` which is
4 //! similar in purpose to `VMContext`. The context is read from
5 //! cranelift-generated trampolines when entering the host from a wasm module.
6 //! Eventually it's intended that module-to-module calls, which would be
7 //! cranelift-compiled adapters, will use this `VMComponentContext` as well.
8 
9 use crate::Result;
10 use crate::component::{Component, Instance, InstancePre, ResourceType, RuntimeImport};
11 use crate::module::ModuleRegistry;
12 #[cfg(feature = "component-model-async")]
13 use crate::runtime::component::concurrent::ConcurrentInstanceState;
14 use crate::runtime::component::{ComponentInstanceId, RuntimeInstance};
15 use crate::runtime::vm::instance::{InstanceLayout, OwnedInstance, OwnedVMContext};
16 use crate::runtime::vm::vmcontext::VMFunctionBody;
17 use crate::runtime::vm::{
18     HostResult, SendSyncPtr, VMArrayCallFunction, VMFuncRef, VMGlobalDefinition,
19     VMMemoryDefinition, VMOpaqueContext, VMStore, VMStoreRawPtr, VMTableImport, VMWasmCallFunction,
20     ValRaw, VmPtr, VmSafe, catch_unwind_and_record_trap,
21 };
22 use crate::store::InstanceId;
23 use crate::{Func, vm};
24 use alloc::alloc::Layout;
25 use alloc::sync::Arc;
26 use core::mem;
27 use core::mem::offset_of;
28 use core::pin::Pin;
29 use core::ptr::NonNull;
30 use wasmtime_environ::component::*;
31 use wasmtime_environ::error::OutOfMemory;
32 use wasmtime_environ::{HostPtr, PrimaryMap, VMSharedTypeIndex};
33 
34 #[allow(
35     clippy::cast_possible_truncation,
36     reason = "it's intended this is truncated on 32-bit platforms"
37 )]
38 const INVALID_PTR: usize = 0xdead_dead_beef_beef_u64 as usize;
39 
40 mod handle_table;
41 mod libcalls;
42 mod resources;
43 
44 pub use self::handle_table::{HandleTable, RemovedResource};
45 #[cfg(feature = "component-model-async")]
46 pub use self::handle_table::{ThreadHandleTable, TransmitLocalState, Waitable};
47 pub use self::resources::{CallContext, ResourceTables, TypedResource, TypedResourceIndex};
48 
49 /// Represents the state of a (sub-)component instance.
50 #[derive(Default)]
51 pub struct InstanceState {
52     /// Represents the Component Model Async state of a (sub-)component instance.
53     #[cfg(feature = "component-model-async")]
54     concurrent_state: ConcurrentInstanceState,
55 
56     /// State of handles (e.g. resources, waitables, etc.) for this instance.
57     ///
58     /// For resource handles, this is paired with other information to create a
59     /// `ResourceTables` and manipulated through that.  For other handles, this
60     /// is used directly to translate guest handles to host representations and
61     /// vice-versa.
62     handle_table: HandleTable,
63 
64     /// Dedicated table for threads that is separate from `handle_table`. Part
65     /// of the component-model-threading proposal.
66     #[cfg(feature = "component-model-async")]
67     thread_handle_table: ThreadHandleTable,
68 }
69 
70 impl InstanceState {
71     /// Represents the Component Model Async state of a (sub-)component instance.
72     #[cfg(feature = "component-model-async")]
concurrent_state(&mut self) -> &mut ConcurrentInstanceState73     pub fn concurrent_state(&mut self) -> &mut ConcurrentInstanceState {
74         &mut self.concurrent_state
75     }
76 
77     /// State of handles (e.g. resources, waitables, etc.) for this instance.
handle_table(&mut self) -> &mut HandleTable78     pub fn handle_table(&mut self) -> &mut HandleTable {
79         &mut self.handle_table
80     }
81 
82     /// State of thread handles.
83     #[cfg(feature = "component-model-async")]
thread_handle_table(&mut self) -> &mut ThreadHandleTable84     pub fn thread_handle_table(&mut self) -> &mut ThreadHandleTable {
85         &mut self.thread_handle_table
86     }
87 }
88 
89 /// Runtime representation of a component instance and all state necessary for
90 /// the instance itself.
91 ///
92 /// This type never exists by-value, but rather it's always behind a pointer.
93 /// The size of the allocation for `ComponentInstance` includes the trailing
94 /// `VMComponentContext` which is variably sized based on the `offsets`
95 /// contained within.
96 ///
97 /// # Pin
98 ///
99 /// Note that this type is mutated through `Pin<&mut ComponentInstance>` in the
100 /// same manner as `vm::Instance` for core modules, and see more information
101 /// over there for documentation and rationale.
102 #[repr(C)]
103 pub struct ComponentInstance {
104     /// The index within the store of where to find this component instance.
105     id: ComponentInstanceId,
106 
107     /// Size and offset information for the trailing `VMComponentContext`.
108     offsets: VMComponentOffsets<HostPtr>,
109 
110     /// The component that this instance was created from.
111     //
112     // NB: in the future if necessary it would be possible to avoid storing an
113     // entire `Component` here and instead storing only information such as:
114     //
115     // * Some reference to `Arc<ComponentTypes>`
116     // * Necessary references to closed-over modules which are exported from the
117     //   component itself.
118     //
119     // Otherwise the full guts of this component should only ever be used during
120     // the instantiation of this instance, meaning that after instantiation much
121     // of the component can be thrown away (theoretically).
122     //
123     // SAFETY: this field cannot be overwritten after an instance is created. It
124     // must contain this exact same value for the entire lifetime of this
125     // instance. This enables borrowing the component and this instance at the
126     // same time (instance mutably, component not). Additionally it enables
127     // borrowing a store mutably at the same time as a contained instance.
128     component: Component,
129 
130     /// Contains state specific to each (sub-)component instance within this
131     /// top-level instance.
132     instance_states: PrimaryMap<RuntimeComponentInstanceIndex, InstanceState>,
133 
134     /// What all compile-time-identified core instances are mapped to within the
135     /// `Store` that this component belongs to.
136     instances: PrimaryMap<RuntimeInstanceIndex, InstanceId>,
137 
138     /// Storage for the type information about resources within this component
139     /// instance.
140     resource_types: Arc<PrimaryMap<ResourceIndex, ResourceType>>,
141 
142     /// Arguments that this instance used to be instantiated.
143     ///
144     /// Strong references are stored to these arguments since pointers are saved
145     /// into the structures such as functions within the
146     /// `OwnedComponentInstance` but it's our job to keep them alive.
147     ///
148     /// One purpose of this storage is to enable embedders to drop a `Linker`,
149     /// for example, after a component is instantiated. In that situation if the
150     /// arguments weren't held here then they might be dropped, and structures
151     /// such as `.lowering()` which point back into the original function would
152     /// become stale and use-after-free conditions when used. By preserving the
153     /// entire list here though we're guaranteed that nothing is lost for the
154     /// duration of the lifetime of this instance.
155     imports: Arc<PrimaryMap<RuntimeImportIndex, RuntimeImport>>,
156 
157     /// Self-pointer back to `Store<T>` and its functions.
158     store: VMStoreRawPtr,
159 
160     /// Required by `InstanceLayout`, also required to be the last field (with
161     /// repr(C))
162     vmctx: OwnedVMContext<VMComponentContext>,
163 }
164 
165 /// Type signature for host-defined trampolines that are called from
166 /// WebAssembly.
167 ///
168 /// This function signature is invoked from a cranelift-compiled trampoline that
169 /// adapts from the core wasm System-V ABI into the ABI provided here:
170 ///
171 /// * `vmctx` - this is the first argument to the wasm import, and should always
172 ///   end up being a `VMComponentContext`.
173 /// * `data` - this is the data pointer associated with the `VMLowering` for
174 ///   which this function pointer was registered.
175 /// * `ty` - the type index, relative to the tables in `vmctx`, that is the
176 ///   type of the function being called.
177 /// * `options` - the `OptionsIndex` which indicates the canonical ABI options
178 ///   in use for this call.
179 /// * `args_and_results` - pointer to stack-allocated space in the caller where
180 ///   all the arguments are stored as well as where the results will be written
181 ///   to. The size and initialized bytes of this depends on the core wasm type
182 ///   signature that this callee corresponds to.
183 /// * `nargs_and_results` - the size, in units of `ValRaw`, of
184 ///   `args_and_results`.
185 ///
186 /// This function returns a `bool` which indicates whether the call succeeded
187 /// or not. On failure this function records trap information in TLS which
188 /// should be suitable for reading later.
189 pub type VMLoweringCallee = unsafe extern "C" fn(
190     vmctx: NonNull<VMOpaqueContext>,
191     data: NonNull<u8>,
192     ty: u32,
193     options: u32,
194     args_and_results: NonNull<mem::MaybeUninit<ValRaw>>,
195     nargs_and_results: usize,
196 ) -> bool;
197 
198 /// An opaque function pointer which is a `VMLoweringFunction` under the hood
199 /// but this is stored as `VMPtr<VMLoweringFunction>` within `VMLowering` below
200 /// to handle provenance correctly when using Pulley.
201 #[repr(transparent)]
202 pub struct VMLoweringFunction(VMFunctionBody);
203 
204 /// Structure describing a lowered host function stored within a
205 /// `VMComponentContext` per-lowering.
206 #[derive(Copy, Clone)]
207 #[repr(C)]
208 pub struct VMLowering {
209     /// The host function pointer that is invoked when this lowering is
210     /// invoked.
211     pub callee: VmPtr<VMLoweringFunction>,
212     /// The host data pointer (think void* pointer) to get passed to `callee`.
213     pub data: VmPtr<u8>,
214 }
215 
216 // SAFETY: the above structure is repr(C) and only contains `VmSafe` fields.
217 unsafe impl VmSafe for VMLowering {}
218 
219 /// This is a marker type to represent the underlying allocation of a
220 /// `VMComponentContext`.
221 ///
222 /// This type is similar to `VMContext` for core wasm and is allocated once per
223 /// component instance in Wasmtime. While the static size of this type is 0 the
224 /// actual runtime size is variable depending on the shape of the component that
225 /// this corresponds to. This structure always trails a `ComponentInstance`
226 /// allocation and the allocation/lifetime of this allocation is managed by
227 /// `ComponentInstance`.
228 #[repr(C)]
229 // Set an appropriate alignment for this structure where the most-aligned value
230 // internally right now `VMGlobalDefinition` which has an alignment of 16 bytes.
231 #[repr(align(16))]
232 pub struct VMComponentContext;
233 
234 impl ComponentInstance {
235     /// Converts the `vmctx` provided into a `ComponentInstance` and runs the
236     /// provided closure with that instance.
237     ///
238     /// This function will also catch any failures that `f` produces and returns
239     /// an appropriate ABI value to return to wasm. This includes normal errors
240     /// such as traps as well as Rust-side panics which require wasm to unwind.
241     ///
242     /// # Unsafety
243     ///
244     /// This is `unsafe` because `vmctx` cannot be guaranteed to be a valid
245     /// pointer and it cannot be proven statically that it's safe to get a
246     /// mutable reference at this time to the instance from `vmctx`. Note that
247     /// it must be also safe to borrow the store mutably, meaning it can't
248     /// already be in use elsewhere.
enter_host_from_wasm<R>( vmctx: NonNull<VMComponentContext>, f: impl FnOnce(&mut dyn VMStore, Instance) -> R, ) -> R::Abi where R: HostResult,249     pub unsafe fn enter_host_from_wasm<R>(
250         vmctx: NonNull<VMComponentContext>,
251         f: impl FnOnce(&mut dyn VMStore, Instance) -> R,
252     ) -> R::Abi
253     where
254         R: HostResult,
255     {
256         // SAFETY: it's a contract of this function that `vmctx` is a valid
257         // allocation which can go backwards to a `ComponentInstance`.
258         let mut ptr = unsafe { Self::from_vmctx(vmctx) };
259 
260         // SAFETY: it's a contract of this function that it's safe to use `ptr`
261         // as a mutable reference.
262         let reference = unsafe { ptr.as_mut() };
263 
264         // SAFETY: it's a contract of this function that it's safe to use the
265         // store mutably at this time.
266         let store = unsafe { &mut *reference.store.0.as_ptr() };
267 
268         let instance = Instance::from_wasmtime(store, reference.id);
269         catch_unwind_and_record_trap(store, |store| f(store, instance))
270     }
271 
272     /// Returns the `InstanceId` associated with the `vmctx` provided.
273     ///
274     /// # Safety
275     ///
276     /// The `vmctx` pointer must be a valid pointer and allocation within a
277     /// `ComponentInstance`. See `Instance::from_vmctx` for some more
278     /// information.
from_vmctx(vmctx: NonNull<VMComponentContext>) -> NonNull<ComponentInstance>279     unsafe fn from_vmctx(vmctx: NonNull<VMComponentContext>) -> NonNull<ComponentInstance> {
280         // SAFETY: it's a contract of this function that `vmctx` is a valid
281         // pointer to do this pointer arithmetic on.
282         unsafe {
283             vmctx
284                 .byte_sub(mem::size_of::<ComponentInstance>())
285                 .cast::<ComponentInstance>()
286         }
287     }
288 
289     /// Returns the `InstanceId` associated with the `vmctx` provided.
290     ///
291     /// # Safety
292     ///
293     /// The `vmctx` pointer must be a valid pointer to read the
294     /// `ComponentInstanceId` from.
vmctx_instance_id( vmctx: NonNull<VMComponentContext>, ) -> ComponentInstanceId295     pub(crate) unsafe fn vmctx_instance_id(
296         vmctx: NonNull<VMComponentContext>,
297     ) -> ComponentInstanceId {
298         // SAFETY: it's a contract of this function that `vmctx` is a valid
299         // pointer with a `ComponentInstance` in front which can be read.
300         unsafe { Self::from_vmctx(vmctx).as_ref().id }
301     }
302 
303     /// Returns the layout corresponding to what would be an allocation of a
304     /// `ComponentInstance` for the `offsets` provided.
305     ///
306     /// The returned layout has space for both the `ComponentInstance` and the
307     /// trailing `VMComponentContext`.
alloc_layout(offsets: &VMComponentOffsets<HostPtr>) -> Layout308     fn alloc_layout(offsets: &VMComponentOffsets<HostPtr>) -> Layout {
309         let size = mem::size_of::<Self>()
310             .checked_add(usize::try_from(offsets.size_of_vmctx()).unwrap())
311             .unwrap();
312         let align = mem::align_of::<Self>();
313         Layout::from_size_align(size, align).unwrap()
314     }
315 
316     /// Allocates a new `ComponentInstance + VMComponentContext` pair on the
317     /// heap with `malloc` and configures it for the `component` specified.
new( id: ComponentInstanceId, component: &Component, resource_types: Arc<PrimaryMap<ResourceIndex, ResourceType>>, imports: &Arc<PrimaryMap<RuntimeImportIndex, RuntimeImport>>, store: NonNull<dyn VMStore>, ) -> Result<OwnedComponentInstance, OutOfMemory>318     pub(crate) fn new(
319         id: ComponentInstanceId,
320         component: &Component,
321         resource_types: Arc<PrimaryMap<ResourceIndex, ResourceType>>,
322         imports: &Arc<PrimaryMap<RuntimeImportIndex, RuntimeImport>>,
323         store: NonNull<dyn VMStore>,
324     ) -> Result<OwnedComponentInstance, OutOfMemory> {
325         let offsets = VMComponentOffsets::new(HostPtr, component.env_component());
326         let num_instances = component.env_component().num_runtime_component_instances;
327         let mut instance_states = PrimaryMap::with_capacity(num_instances.try_into().unwrap());
328         for _ in 0..num_instances {
329             instance_states.push(InstanceState::default());
330         }
331 
332         let mut ret = OwnedInstance::new(ComponentInstance {
333             id,
334             offsets,
335             instance_states,
336             instances: PrimaryMap::with_capacity(
337                 component
338                     .env_component()
339                     .num_runtime_instances
340                     .try_into()
341                     .unwrap(),
342             ),
343             component: component.clone(),
344             resource_types,
345             imports: imports.clone(),
346             store: VMStoreRawPtr(store),
347             vmctx: OwnedVMContext::new(),
348         })?;
349         unsafe {
350             ret.get_mut().initialize_vmctx();
351         }
352         Ok(ret)
353     }
354 
355     #[inline]
vmctx(&self) -> NonNull<VMComponentContext>356     pub fn vmctx(&self) -> NonNull<VMComponentContext> {
357         InstanceLayout::vmctx(self)
358     }
359 
360     /// Returns a pointer to the "may leave" flag for this instance specified
361     /// for canonical lowering and lifting operations.
362     #[inline]
instance_flags(&self, instance: RuntimeComponentInstanceIndex) -> InstanceFlags363     pub fn instance_flags(&self, instance: RuntimeComponentInstanceIndex) -> InstanceFlags {
364         unsafe {
365             let ptr = self
366                 .vmctx_plus_offset_raw::<VMGlobalDefinition>(self.offsets.instance_flags(instance));
367             InstanceFlags(SendSyncPtr::new(ptr))
368         }
369     }
370 
371     /// Returns the runtime memory definition corresponding to the index of the
372     /// memory provided.
373     ///
374     /// This can only be called after `idx` has been initialized at runtime
375     /// during the instantiation process of a component.
runtime_memory(&self, idx: RuntimeMemoryIndex) -> NonNull<VMMemoryDefinition>376     pub fn runtime_memory(&self, idx: RuntimeMemoryIndex) -> NonNull<VMMemoryDefinition> {
377         unsafe {
378             let ret = *self.vmctx_plus_offset::<VmPtr<_>>(self.offsets.runtime_memory(idx));
379             debug_assert!(ret.as_ptr() as usize != INVALID_PTR);
380             ret.as_non_null()
381         }
382     }
383 
384     /// Returns the runtime table definition and associated instance `VMContext`
385     /// corresponding to the index of the table provided.
386     ///
387     /// This can only be called after `idx` has been initialized at runtime
388     /// during the instantiation process of a component.
runtime_table(&self, idx: RuntimeTableIndex) -> VMTableImport389     pub fn runtime_table(&self, idx: RuntimeTableIndex) -> VMTableImport {
390         unsafe {
391             let ret = *self.vmctx_plus_offset::<VMTableImport>(self.offsets.runtime_table(idx));
392             debug_assert!(ret.from.as_ptr() as usize != INVALID_PTR);
393             debug_assert!(ret.vmctx.as_ptr() as usize != INVALID_PTR);
394             ret
395         }
396     }
397 
398     /// Returns the `Func` at index `func_idx` in the funcref table at `table_idx`.
index_runtime_func_table( &self, registry: &ModuleRegistry, table_idx: RuntimeTableIndex, func_idx: u64, ) -> Result<Option<Func>>399     pub fn index_runtime_func_table(
400         &self,
401         registry: &ModuleRegistry,
402         table_idx: RuntimeTableIndex,
403         func_idx: u64,
404     ) -> Result<Option<Func>> {
405         unsafe {
406             let store = self.store.0.as_ref();
407             let table = self.runtime_table(table_idx);
408             let vmctx = table.vmctx.as_non_null();
409             // SAFETY: it's a contract of this function that `vmctx` is a valid
410             // allocation which can go backwards to a `ComponentInstance`.
411             let mut instance_ptr = vm::Instance::from_vmctx(vmctx);
412             // SAFETY: We just constructed `instance_ptr` from a valid pointer. This pointer won't leave
413             // this call, so we don't need a lifetime to bind it to.
414             let instance = Pin::new_unchecked(instance_ptr.as_mut());
415             let table =
416                 instance.get_defined_table_with_lazy_init(registry, table.index, [func_idx]);
417             let func = table
418                 .get_func(func_idx)?
419                 .map(|funcref| Func::from_vm_func_ref(store.id(), funcref));
420             Ok(func)
421         }
422     }
423 
424     /// Returns the realloc pointer corresponding to the index provided.
425     ///
426     /// This can only be called after `idx` has been initialized at runtime
427     /// during the instantiation process of a component.
runtime_realloc(&self, idx: RuntimeReallocIndex) -> NonNull<VMFuncRef>428     pub fn runtime_realloc(&self, idx: RuntimeReallocIndex) -> NonNull<VMFuncRef> {
429         unsafe {
430             let ret = *self.vmctx_plus_offset::<VmPtr<_>>(self.offsets.runtime_realloc(idx));
431             debug_assert!(ret.as_ptr() as usize != INVALID_PTR);
432             ret.as_non_null()
433         }
434     }
435 
436     /// Returns the async callback pointer corresponding to the index provided.
437     ///
438     /// This can only be called after `idx` has been initialized at runtime
439     /// during the instantiation process of a component.
runtime_callback(&self, idx: RuntimeCallbackIndex) -> NonNull<VMFuncRef>440     pub fn runtime_callback(&self, idx: RuntimeCallbackIndex) -> NonNull<VMFuncRef> {
441         unsafe {
442             let ret = *self.vmctx_plus_offset::<VmPtr<_>>(self.offsets.runtime_callback(idx));
443             debug_assert!(ret.as_ptr() as usize != INVALID_PTR);
444             ret.as_non_null()
445         }
446     }
447 
448     /// Returns the post-return pointer corresponding to the index provided.
449     ///
450     /// This can only be called after `idx` has been initialized at runtime
451     /// during the instantiation process of a component.
runtime_post_return(&self, idx: RuntimePostReturnIndex) -> NonNull<VMFuncRef>452     pub fn runtime_post_return(&self, idx: RuntimePostReturnIndex) -> NonNull<VMFuncRef> {
453         unsafe {
454             let ret = *self.vmctx_plus_offset::<VmPtr<_>>(self.offsets.runtime_post_return(idx));
455             debug_assert!(ret.as_ptr() as usize != INVALID_PTR);
456             ret.as_non_null()
457         }
458     }
459 
460     /// Returns the host information for the lowered function at the index
461     /// specified.
462     ///
463     /// This can only be called after `idx` has been initialized at runtime
464     /// during the instantiation process of a component.
lowering(&self, idx: LoweredIndex) -> VMLowering465     pub fn lowering(&self, idx: LoweredIndex) -> VMLowering {
466         unsafe {
467             let ret = *self.vmctx_plus_offset::<VMLowering>(self.offsets.lowering(idx));
468             debug_assert!(ret.callee.as_ptr() as usize != INVALID_PTR);
469             debug_assert!(ret.data.as_ptr() as usize != INVALID_PTR);
470             ret
471         }
472     }
473 
474     /// Returns the core wasm `funcref` corresponding to the trampoline
475     /// specified.
476     ///
477     /// The returned function is suitable to pass directly to a wasm module
478     /// instantiation and the function contains cranelift-compiled trampolines.
479     ///
480     /// This can only be called after `idx` has been initialized at runtime
481     /// during the instantiation process of a component.
trampoline_func_ref(&self, idx: TrampolineIndex) -> NonNull<VMFuncRef>482     pub fn trampoline_func_ref(&self, idx: TrampolineIndex) -> NonNull<VMFuncRef> {
483         unsafe {
484             let offset = self.offsets.trampoline_func_ref(idx);
485             let ret = self.vmctx_plus_offset_raw::<VMFuncRef>(offset);
486             debug_assert!(
487                 mem::transmute::<Option<VmPtr<VMWasmCallFunction>>, usize>(ret.as_ref().wasm_call)
488                     != INVALID_PTR
489             );
490             debug_assert!(ret.as_ref().vmctx.as_ptr() as usize != INVALID_PTR);
491             ret
492         }
493     }
494 
495     /// Get the core Wasm function reference for the given unsafe intrinsic.
unsafe_intrinsic_func_ref(&self, idx: UnsafeIntrinsic) -> NonNull<VMFuncRef>496     pub fn unsafe_intrinsic_func_ref(&self, idx: UnsafeIntrinsic) -> NonNull<VMFuncRef> {
497         unsafe {
498             let offset = self.offsets.unsafe_intrinsic_func_ref(idx);
499             let ret = self.vmctx_plus_offset_raw::<VMFuncRef>(offset);
500             debug_assert!(
501                 mem::transmute::<Option<VmPtr<VMWasmCallFunction>>, usize>(ret.as_ref().wasm_call)
502                     != INVALID_PTR
503             );
504             debug_assert!(ret.as_ref().vmctx.as_ptr() as usize != INVALID_PTR);
505             ret
506         }
507     }
508 
509     /// Stores the runtime memory pointer at the index specified.
510     ///
511     /// This is intended to be called during the instantiation process of a
512     /// component once a memory is available, which may not be until part-way
513     /// through component instantiation.
514     ///
515     /// Note that it should be a property of the component model that the `ptr`
516     /// here is never needed prior to it being configured here in the instance.
set_runtime_memory( self: Pin<&mut Self>, idx: RuntimeMemoryIndex, ptr: NonNull<VMMemoryDefinition>, )517     pub fn set_runtime_memory(
518         self: Pin<&mut Self>,
519         idx: RuntimeMemoryIndex,
520         ptr: NonNull<VMMemoryDefinition>,
521     ) {
522         unsafe {
523             let offset = self.offsets.runtime_memory(idx);
524             let storage = self.vmctx_plus_offset_mut::<VmPtr<VMMemoryDefinition>>(offset);
525             debug_assert!((*storage).as_ptr() as usize == INVALID_PTR);
526             *storage = ptr.into();
527         }
528     }
529 
530     /// Same as `set_runtime_memory` but for realloc function pointers.
set_runtime_realloc( self: Pin<&mut Self>, idx: RuntimeReallocIndex, ptr: NonNull<VMFuncRef>, )531     pub fn set_runtime_realloc(
532         self: Pin<&mut Self>,
533         idx: RuntimeReallocIndex,
534         ptr: NonNull<VMFuncRef>,
535     ) {
536         unsafe {
537             let offset = self.offsets.runtime_realloc(idx);
538             let storage = self.vmctx_plus_offset_mut::<VmPtr<VMFuncRef>>(offset);
539             debug_assert!((*storage).as_ptr() as usize == INVALID_PTR);
540             *storage = ptr.into();
541         }
542     }
543 
544     /// Same as `set_runtime_memory` but for async callback function pointers.
set_runtime_callback( self: Pin<&mut Self>, idx: RuntimeCallbackIndex, ptr: NonNull<VMFuncRef>, )545     pub fn set_runtime_callback(
546         self: Pin<&mut Self>,
547         idx: RuntimeCallbackIndex,
548         ptr: NonNull<VMFuncRef>,
549     ) {
550         unsafe {
551             let offset = self.offsets.runtime_callback(idx);
552             let storage = self.vmctx_plus_offset_mut::<VmPtr<VMFuncRef>>(offset);
553             debug_assert!((*storage).as_ptr() as usize == INVALID_PTR);
554             *storage = ptr.into();
555         }
556     }
557 
558     /// Same as `set_runtime_memory` but for post-return function pointers.
set_runtime_post_return( self: Pin<&mut Self>, idx: RuntimePostReturnIndex, ptr: NonNull<VMFuncRef>, )559     pub fn set_runtime_post_return(
560         self: Pin<&mut Self>,
561         idx: RuntimePostReturnIndex,
562         ptr: NonNull<VMFuncRef>,
563     ) {
564         unsafe {
565             let offset = self.offsets.runtime_post_return(idx);
566             let storage = self.vmctx_plus_offset_mut::<VmPtr<VMFuncRef>>(offset);
567             debug_assert!((*storage).as_ptr() as usize == INVALID_PTR);
568             *storage = ptr.into();
569         }
570     }
571 
572     /// Stores the runtime table pointer at the index specified.
573     ///
574     /// This is intended to be called during the instantiation process of a
575     /// component once a table is available, which may not be until part-way
576     /// through component instantiation.
577     ///
578     /// Note that it should be a property of the component model that the `ptr`
579     /// here is never needed prior to it being configured here in the instance.
set_runtime_table(self: Pin<&mut Self>, idx: RuntimeTableIndex, import: VMTableImport)580     pub fn set_runtime_table(self: Pin<&mut Self>, idx: RuntimeTableIndex, import: VMTableImport) {
581         unsafe {
582             let offset = self.offsets.runtime_table(idx);
583             let storage = self.vmctx_plus_offset_mut::<VMTableImport>(offset);
584             debug_assert!((*storage).vmctx.as_ptr() as usize == INVALID_PTR);
585             debug_assert!((*storage).from.as_ptr() as usize == INVALID_PTR);
586             *storage = import;
587         }
588     }
589 
590     /// Configures host runtime lowering information associated with imported f
591     /// functions for the `idx` specified.
set_lowering(self: Pin<&mut Self>, idx: LoweredIndex, lowering: VMLowering)592     pub fn set_lowering(self: Pin<&mut Self>, idx: LoweredIndex, lowering: VMLowering) {
593         unsafe {
594             let callee = self.offsets.lowering_callee(idx);
595             debug_assert!(*self.vmctx_plus_offset::<usize>(callee) == INVALID_PTR);
596             let data = self.offsets.lowering_data(idx);
597             debug_assert!(*self.vmctx_plus_offset::<usize>(data) == INVALID_PTR);
598             let offset = self.offsets.lowering(idx);
599             *self.vmctx_plus_offset_mut(offset) = lowering;
600         }
601     }
602 
603     /// Same as `set_lowering` but for the resource.drop functions.
set_trampoline( self: Pin<&mut Self>, idx: TrampolineIndex, wasm_call: NonNull<VMWasmCallFunction>, array_call: NonNull<VMArrayCallFunction>, type_index: VMSharedTypeIndex, )604     pub fn set_trampoline(
605         self: Pin<&mut Self>,
606         idx: TrampolineIndex,
607         wasm_call: NonNull<VMWasmCallFunction>,
608         array_call: NonNull<VMArrayCallFunction>,
609         type_index: VMSharedTypeIndex,
610     ) {
611         unsafe {
612             let offset = self.offsets.trampoline_func_ref(idx);
613             debug_assert!(*self.vmctx_plus_offset::<usize>(offset) == INVALID_PTR);
614             let vmctx = VMOpaqueContext::from_vmcomponent(self.vmctx());
615             *self.vmctx_plus_offset_mut(offset) = VMFuncRef {
616                 wasm_call: Some(wasm_call.into()),
617                 array_call: array_call.into(),
618                 type_index,
619                 vmctx: vmctx.into(),
620             };
621         }
622     }
623 
624     /// Same as `set_trampoline` but for intrinsic functions.
set_intrinsic( self: Pin<&mut Self>, intrinsic: UnsafeIntrinsic, wasm_call: NonNull<VMWasmCallFunction>, array_call: NonNull<VMArrayCallFunction>, type_index: VMSharedTypeIndex, )625     pub fn set_intrinsic(
626         self: Pin<&mut Self>,
627         intrinsic: UnsafeIntrinsic,
628         wasm_call: NonNull<VMWasmCallFunction>,
629         array_call: NonNull<VMArrayCallFunction>,
630         type_index: VMSharedTypeIndex,
631     ) {
632         unsafe {
633             let offset = self.offsets.unsafe_intrinsic_func_ref(intrinsic);
634             debug_assert!(*self.vmctx_plus_offset::<usize>(offset) == INVALID_PTR);
635             let vmctx = VMOpaqueContext::from_vmcomponent(self.vmctx());
636             *self.vmctx_plus_offset_mut(offset) = VMFuncRef {
637                 wasm_call: Some(wasm_call.into()),
638                 array_call: array_call.into(),
639                 type_index,
640                 vmctx: vmctx.into(),
641             };
642         }
643     }
644 
645     /// Configures the destructor for a resource at the `idx` specified.
646     ///
647     /// This is required to be called for each resource as it's defined within a
648     /// component during the instantiation process.
set_resource_destructor( self: Pin<&mut Self>, idx: ResourceIndex, dtor: Option<NonNull<VMFuncRef>>, )649     pub fn set_resource_destructor(
650         self: Pin<&mut Self>,
651         idx: ResourceIndex,
652         dtor: Option<NonNull<VMFuncRef>>,
653     ) {
654         unsafe {
655             let offset = self.offsets.resource_destructor(idx);
656             debug_assert!(*self.vmctx_plus_offset::<usize>(offset) == INVALID_PTR);
657             *self.vmctx_plus_offset_mut(offset) = dtor.map(VmPtr::from);
658         }
659     }
660 
661     /// Returns the destructor, if any, for `idx`.
662     ///
663     /// This is only valid to call after `set_resource_destructor`, or typically
664     /// after instantiation.
resource_destructor(&self, idx: ResourceIndex) -> Option<NonNull<VMFuncRef>>665     pub fn resource_destructor(&self, idx: ResourceIndex) -> Option<NonNull<VMFuncRef>> {
666         unsafe {
667             let offset = self.offsets.resource_destructor(idx);
668             debug_assert!(*self.vmctx_plus_offset::<usize>(offset) != INVALID_PTR);
669             (*self.vmctx_plus_offset::<Option<VmPtr<VMFuncRef>>>(offset)).map(|p| p.as_non_null())
670         }
671     }
672 
initialize_vmctx(mut self: Pin<&mut Self>)673     unsafe fn initialize_vmctx(mut self: Pin<&mut Self>) {
674         let offset = self.offsets.magic();
675         // SAFETY: it's safe to write the magic value during initialization and
676         // this is also the right type of value to write.
677         unsafe {
678             *self.as_mut().vmctx_plus_offset_mut(offset) = VMCOMPONENT_MAGIC;
679         }
680 
681         // Initialize the built-in functions
682         //
683         // SAFETY: it's safe to initialize the vmctx in this function and this
684         // is also the right type of value to store in the vmctx.
685         static BUILTINS: libcalls::VMComponentBuiltins = libcalls::VMComponentBuiltins::INIT;
686         let ptr = BUILTINS.expose_provenance();
687         let offset = self.offsets.builtins();
688         unsafe {
689             *self.as_mut().vmctx_plus_offset_mut(offset) = VmPtr::from(ptr);
690         }
691 
692         // SAFETY: it's safe to initialize the vmctx in this function and this
693         // is also the right type of value to store in the vmctx.
694         let offset = self.offsets.vm_store_context();
695         unsafe {
696             *self.as_mut().vmctx_plus_offset_mut(offset) =
697                 VmPtr::from(self.store.0.as_ref().vm_store_context_ptr());
698         }
699 
700         for i in 0..self.offsets.num_runtime_component_instances {
701             let i = RuntimeComponentInstanceIndex::from_u32(i);
702             let mut def = VMGlobalDefinition::new();
703             // SAFETY: this is a valid initialization of all globals which are
704             // 32-bit values.
705             unsafe {
706                 *def.as_i32_mut() = FLAG_MAY_LEAVE;
707                 self.instance_flags(i).as_raw().write(def);
708             }
709         }
710 
711         // In debug mode set non-null bad values to all "pointer looking" bits
712         // and pieces related to lowering and such. This'll help detect any
713         // erroneous usage and enable debug assertions above as well to prevent
714         // loading these before they're configured or setting them twice.
715         //
716         // SAFETY: it's valid to write a garbage pointer during initialization
717         // when this is otherwise uninitialized memory
718         if cfg!(debug_assertions) {
719             for i in 0..self.offsets.num_lowerings {
720                 let i = LoweredIndex::from_u32(i);
721                 let offset = self.offsets.lowering_callee(i);
722                 // SAFETY: see above
723                 unsafe {
724                     *self.as_mut().vmctx_plus_offset_mut(offset) = INVALID_PTR;
725                 }
726                 let offset = self.offsets.lowering_data(i);
727                 // SAFETY: see above
728                 unsafe {
729                     *self.as_mut().vmctx_plus_offset_mut(offset) = INVALID_PTR;
730                 }
731             }
732             for i in 0..self.offsets.num_trampolines {
733                 let i = TrampolineIndex::from_u32(i);
734                 let offset = self.offsets.trampoline_func_ref(i);
735                 // SAFETY: see above
736                 unsafe {
737                     *self.as_mut().vmctx_plus_offset_mut(offset) = INVALID_PTR;
738                 }
739             }
740             for i in 0..self.offsets.num_unsafe_intrinsics {
741                 let i = UnsafeIntrinsic::from_u32(i);
742                 let offset = self.offsets.unsafe_intrinsic_func_ref(i);
743                 // SAFETY: see above
744                 unsafe {
745                     *self.as_mut().vmctx_plus_offset_mut(offset) = INVALID_PTR;
746                 }
747             }
748             for i in 0..self.offsets.num_runtime_memories {
749                 let i = RuntimeMemoryIndex::from_u32(i);
750                 let offset = self.offsets.runtime_memory(i);
751                 // SAFETY: see above
752                 unsafe {
753                     *self.as_mut().vmctx_plus_offset_mut(offset) = INVALID_PTR;
754                 }
755             }
756             for i in 0..self.offsets.num_runtime_reallocs {
757                 let i = RuntimeReallocIndex::from_u32(i);
758                 let offset = self.offsets.runtime_realloc(i);
759                 // SAFETY: see above
760                 unsafe {
761                     *self.as_mut().vmctx_plus_offset_mut(offset) = INVALID_PTR;
762                 }
763             }
764             for i in 0..self.offsets.num_runtime_callbacks {
765                 let i = RuntimeCallbackIndex::from_u32(i);
766                 let offset = self.offsets.runtime_callback(i);
767                 // SAFETY: see above
768                 unsafe {
769                     *self.as_mut().vmctx_plus_offset_mut(offset) = INVALID_PTR;
770                 }
771             }
772             for i in 0..self.offsets.num_runtime_post_returns {
773                 let i = RuntimePostReturnIndex::from_u32(i);
774                 let offset = self.offsets.runtime_post_return(i);
775                 // SAFETY: see above
776                 unsafe {
777                     *self.as_mut().vmctx_plus_offset_mut(offset) = INVALID_PTR;
778                 }
779             }
780             for i in 0..self.offsets.num_resources {
781                 let i = ResourceIndex::from_u32(i);
782                 let offset = self.offsets.resource_destructor(i);
783                 // SAFETY: see above
784                 unsafe {
785                     *self.as_mut().vmctx_plus_offset_mut(offset) = INVALID_PTR;
786                 }
787             }
788             for i in 0..self.offsets.num_runtime_tables {
789                 let i = RuntimeTableIndex::from_u32(i);
790                 let offset = self.offsets.runtime_table(i);
791                 // SAFETY: see above
792                 #[allow(clippy::cast_possible_truncation, reason = "known to not overflow")]
793                 unsafe {
794                     *self.as_mut().vmctx_plus_offset_mut::<usize>(
795                         offset + offset_of!(VMTableImport, from) as u32,
796                     ) = INVALID_PTR;
797                     *self.as_mut().vmctx_plus_offset_mut::<usize>(
798                         offset + offset_of!(VMTableImport, vmctx) as u32,
799                     ) = INVALID_PTR;
800                 }
801             }
802         }
803     }
804 
805     /// Returns a reference to the component type information for this
806     /// instance.
component(&self) -> &Component807     pub fn component(&self) -> &Component {
808         &self.component
809     }
810 
811     /// Same as [`Self::component`] but additionally returns the
812     /// `Pin<&mut Self>` with the same original lifetime.
component_and_self(self: Pin<&mut Self>) -> (&Component, Pin<&mut Self>)813     pub fn component_and_self(self: Pin<&mut Self>) -> (&Component, Pin<&mut Self>) {
814         // SAFETY: this function is projecting both `&Component` and the same
815         // pointer both connected to the same lifetime. This is safe because
816         // it's a contract of `Pin<&mut Self>` that the `Component` field is
817         // never written, meaning it's effectively unsafe to have `&mut
818         // Component` projected from `Pin<&mut Self>`. Consequently it's safe to
819         // have a read-only view of the field while still retaining mutable
820         // access to all other fields.
821         let component = unsafe { &*(&raw const self.component) };
822         (component, self)
823     }
824 
825     /// Returns a reference to the resource type information.
resource_types(&self) -> &Arc<PrimaryMap<ResourceIndex, ResourceType>>826     pub fn resource_types(&self) -> &Arc<PrimaryMap<ResourceIndex, ResourceType>> {
827         &self.resource_types
828     }
829 
830     /// Returns a mutable reference to the resource type information.
resource_types_mut( self: Pin<&mut Self>, ) -> &mut Arc<PrimaryMap<ResourceIndex, ResourceType>>831     pub fn resource_types_mut(
832         self: Pin<&mut Self>,
833     ) -> &mut Arc<PrimaryMap<ResourceIndex, ResourceType>> {
834         // SAFETY: we've chosen the `Pin` guarantee of `Self` to not apply to
835         // the map returned.
836         unsafe { &mut self.get_unchecked_mut().resource_types }
837     }
838 
839     /// Returns whether the resource that `ty` points to is owned by the
840     /// instance that `ty` correspond to.
841     ///
842     /// This is used when lowering borrows to skip table management and instead
843     /// thread through the underlying representation directly.
resource_owned_by_own_instance(&self, ty: TypeResourceTableIndex) -> bool844     pub fn resource_owned_by_own_instance(&self, ty: TypeResourceTableIndex) -> bool {
845         let (resource_ty, resource_instance) = match self.component.types()[ty] {
846             TypeResourceTable::Concrete { ty, instance } => (ty, instance),
847             TypeResourceTable::Abstract(_) => return false,
848         };
849         let component = self.component.env_component();
850         let idx = match component.defined_resource_index(resource_ty) {
851             Some(idx) => idx,
852             None => return false,
853         };
854         resource_instance == component.defined_resource_instances[idx]
855     }
856 
857     /// Returns the runtime state of resources and concurrency associated with
858     /// this component.
859     #[inline]
instance_states( self: Pin<&mut Self>, ) -> ( &mut PrimaryMap<RuntimeComponentInstanceIndex, InstanceState>, &ComponentTypes, )860     pub fn instance_states(
861         self: Pin<&mut Self>,
862     ) -> (
863         &mut PrimaryMap<RuntimeComponentInstanceIndex, InstanceState>,
864         &ComponentTypes,
865     ) {
866         // safety: we've chosen the `pin` guarantee of `self` to not apply to
867         // the map returned.
868         unsafe {
869             let me = self.get_unchecked_mut();
870             (&mut me.instance_states, me.component.types())
871         }
872     }
873 
instance_state( self: Pin<&mut Self>, instance: RuntimeComponentInstanceIndex, ) -> &mut InstanceState874     pub fn instance_state(
875         self: Pin<&mut Self>,
876         instance: RuntimeComponentInstanceIndex,
877     ) -> &mut InstanceState {
878         &mut self.instance_states().0[instance]
879     }
880 
881     /// Returns the destructor and instance flags for the specified resource
882     /// table type.
883     ///
884     /// This will lookup the origin definition of the `ty` table and return the
885     /// destructor/flags for that.
dtor_and_instance( &self, ty: TypeResourceTableIndex, ) -> (Option<NonNull<VMFuncRef>>, Option<RuntimeInstance>)886     pub fn dtor_and_instance(
887         &self,
888         ty: TypeResourceTableIndex,
889     ) -> (Option<NonNull<VMFuncRef>>, Option<RuntimeInstance>) {
890         let resource = self.component.types()[ty].unwrap_concrete_ty();
891         let dtor = self.resource_destructor(resource);
892         let component = self.component.env_component();
893         let instance = component
894             .defined_resource_index(resource)
895             .map(|i| RuntimeInstance {
896                 instance: self.id(),
897                 index: component.defined_resource_instances[i],
898             });
899         (dtor, instance)
900     }
901 
902     /// Returns the store-local id that points to this component.
id(&self) -> ComponentInstanceId903     pub fn id(&self) -> ComponentInstanceId {
904         self.id
905     }
906 
907     /// Pushes a new runtime instance that's been created into
908     /// `self.instances`.
push_instance_id(self: Pin<&mut Self>, id: InstanceId) -> RuntimeInstanceIndex909     pub fn push_instance_id(self: Pin<&mut Self>, id: InstanceId) -> RuntimeInstanceIndex {
910         self.instances_mut().push(id)
911     }
912 
913     /// Returns the [`InstanceId`] previously pushed by `push_instance_id`
914     /// above.
915     ///
916     /// # Panics
917     ///
918     /// Panics if `idx` hasn't been initialized yet.
instance(&self, idx: RuntimeInstanceIndex) -> InstanceId919     pub fn instance(&self, idx: RuntimeInstanceIndex) -> InstanceId {
920         self.instances[idx]
921     }
922 
instances_mut(self: Pin<&mut Self>) -> &mut PrimaryMap<RuntimeInstanceIndex, InstanceId>923     fn instances_mut(self: Pin<&mut Self>) -> &mut PrimaryMap<RuntimeInstanceIndex, InstanceId> {
924         // SAFETY: we've chosen the `Pin` guarantee of `Self` to not apply to
925         // the map returned.
926         unsafe { &mut self.get_unchecked_mut().instances }
927     }
928 
929     /// Looks up the value used for `import` at runtime.
930     ///
931     /// # Panics
932     ///
933     /// Panics of `import` is out of bounds for this component.
runtime_import(&self, import: RuntimeImportIndex) -> &RuntimeImport934     pub(crate) fn runtime_import(&self, import: RuntimeImportIndex) -> &RuntimeImport {
935         &self.imports[import]
936     }
937 
938     /// Returns an `InstancePre<T>` which can be used to re-instantiated this
939     /// component if desired.
940     ///
941     /// # Safety
942     ///
943     /// This function places no bounds on `T` so it's up to the caller to match
944     /// that up appropriately with the store that this instance resides within.
instance_pre<T>(&self) -> InstancePre<T>945     pub unsafe fn instance_pre<T>(&self) -> InstancePre<T> {
946         // SAFETY: The `T` part of `new_unchecked` is forwarded as a contract of
947         // this function, and otherwise the validity of the components of the
948         // InstancePre should be guaranteed as it's what we were built with
949         // ourselves.
950         unsafe {
951             InstancePre::new_unchecked(
952                 self.component.clone(),
953                 self.imports.clone(),
954                 self.resource_types.clone(),
955             )
956         }
957     }
958 
task_may_block(&self) -> NonNull<VMGlobalDefinition>959     pub(crate) fn task_may_block(&self) -> NonNull<VMGlobalDefinition> {
960         unsafe { self.vmctx_plus_offset_raw::<VMGlobalDefinition>(self.offsets.task_may_block()) }
961     }
962 
963     #[cfg(feature = "component-model-async")]
get_task_may_block(&self) -> bool964     pub(crate) fn get_task_may_block(&self) -> bool {
965         unsafe { *self.task_may_block().as_ref().as_i32() != 0 }
966     }
967 
968     #[cfg(feature = "component-model-async")]
set_task_may_block(self: Pin<&mut Self>, val: bool)969     pub(crate) fn set_task_may_block(self: Pin<&mut Self>, val: bool) {
970         unsafe { *self.task_may_block().as_mut().as_i32_mut() = if val { 1 } else { 0 } }
971     }
972 }
973 
974 // SAFETY: `layout` should describe this accurately and `OwnedVMContext` is the
975 // last field of `ComponentInstance`.
976 unsafe impl InstanceLayout for ComponentInstance {
977     /// Technically it is not required to `alloc_zeroed` here. The primary
978     /// reason for doing this is because a component context start is a "partly
979     /// initialized" state where pointers and such are configured as the
980     /// instantiation process continues. The component model should guarantee
981     /// that we never access uninitialized memory in the context, but to help
982     /// protect against possible bugs a zeroed allocation is done here to try to
983     /// contain use-before-initialized issues.
984     const INIT_ZEROED: bool = true;
985 
986     type VMContext = VMComponentContext;
987 
layout(&self) -> Layout988     fn layout(&self) -> Layout {
989         ComponentInstance::alloc_layout(&self.offsets)
990     }
991 
owned_vmctx(&self) -> &OwnedVMContext<VMComponentContext>992     fn owned_vmctx(&self) -> &OwnedVMContext<VMComponentContext> {
993         &self.vmctx
994     }
995 
owned_vmctx_mut(&mut self) -> &mut OwnedVMContext<VMComponentContext>996     fn owned_vmctx_mut(&mut self) -> &mut OwnedVMContext<VMComponentContext> {
997         &mut self.vmctx
998     }
999 }
1000 
1001 pub type OwnedComponentInstance = OwnedInstance<ComponentInstance>;
1002 
1003 impl VMComponentContext {
1004     /// Moves the `self` pointer backwards to the `ComponentInstance` pointer
1005     /// that this `VMComponentContext` trails.
instance(&self) -> *mut ComponentInstance1006     pub fn instance(&self) -> *mut ComponentInstance {
1007         unsafe {
1008             (self as *const Self as *mut u8)
1009                 .offset(-(offset_of!(ComponentInstance, vmctx) as isize))
1010                 as *mut ComponentInstance
1011         }
1012     }
1013 
1014     /// Helper function to cast between context types using a debug assertion to
1015     /// protect against some mistakes.
1016     ///
1017     /// # Safety
1018     ///
1019     /// The `opaque` value must be a valid pointer where it's safe to read its
1020     /// "magic" value.
1021     #[inline]
from_opaque(opaque: NonNull<VMOpaqueContext>) -> NonNull<VMComponentContext>1022     pub unsafe fn from_opaque(opaque: NonNull<VMOpaqueContext>) -> NonNull<VMComponentContext> {
1023         // See comments in `VMContext::from_opaque` for this debug assert
1024         //
1025         // SAFETY: it's a contract of this function that it's safe to read
1026         // `opaque`.
1027         unsafe {
1028             debug_assert_eq!(opaque.as_ref().magic, VMCOMPONENT_MAGIC);
1029         }
1030         opaque.cast()
1031     }
1032 }
1033 
1034 impl VMOpaqueContext {
1035     /// Helper function to clearly indicate the cast desired
1036     #[inline]
from_vmcomponent(ptr: NonNull<VMComponentContext>) -> NonNull<VMOpaqueContext>1037     pub fn from_vmcomponent(ptr: NonNull<VMComponentContext>) -> NonNull<VMOpaqueContext> {
1038         ptr.cast()
1039     }
1040 }
1041 
1042 #[repr(transparent)]
1043 #[derive(Copy, Clone)]
1044 pub struct InstanceFlags(SendSyncPtr<VMGlobalDefinition>);
1045 
1046 impl InstanceFlags {
1047     /// Wraps the given pointer as an `InstanceFlags`
1048     ///
1049     /// # Unsafety
1050     ///
1051     /// This is a raw pointer argument which needs to be valid for the lifetime
1052     /// that `InstanceFlags` is used.
from_raw(ptr: NonNull<VMGlobalDefinition>) -> InstanceFlags1053     pub unsafe fn from_raw(ptr: NonNull<VMGlobalDefinition>) -> InstanceFlags {
1054         InstanceFlags(SendSyncPtr::from(ptr))
1055     }
1056 
1057     #[inline]
may_leave(&self) -> bool1058     pub unsafe fn may_leave(&self) -> bool {
1059         unsafe { *self.as_raw().as_ref().as_i32() & FLAG_MAY_LEAVE != 0 }
1060     }
1061 
1062     #[inline]
set_may_leave(&mut self, val: bool)1063     pub unsafe fn set_may_leave(&mut self, val: bool) {
1064         unsafe {
1065             if val {
1066                 *self.as_raw().as_mut().as_i32_mut() |= FLAG_MAY_LEAVE;
1067             } else {
1068                 *self.as_raw().as_mut().as_i32_mut() &= !FLAG_MAY_LEAVE;
1069             }
1070         }
1071     }
1072 
1073     #[inline]
as_raw(&self) -> NonNull<VMGlobalDefinition>1074     pub fn as_raw(&self) -> NonNull<VMGlobalDefinition> {
1075         self.0.as_non_null()
1076     }
1077 }
1078