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::component::{Component, Instance, InstancePre, ResourceType, RuntimeImport};
10 use crate::runtime::component::ComponentInstanceId;
11 use crate::runtime::vm::instance::{InstanceLayout, OwnedInstance, OwnedVMContext};
12 use crate::runtime::vm::vmcontext::VMFunctionBody;
13 use crate::runtime::vm::{
14     SendSyncPtr, VMArrayCallFunction, VMContext, VMFuncRef, VMGlobalDefinition, VMMemoryDefinition,
15     VMOpaqueContext, VMStore, VMStoreRawPtr, VMTableDefinition, VMTableImport, VMWasmCallFunction,
16     ValRaw, VmPtr, VmSafe,
17 };
18 use crate::store::InstanceId;
19 use alloc::alloc::Layout;
20 use alloc::sync::Arc;
21 use core::mem;
22 use core::mem::offset_of;
23 use core::pin::Pin;
24 use core::ptr::NonNull;
25 use wasmtime_environ::component::*;
26 use wasmtime_environ::{DefinedTableIndex, HostPtr, PrimaryMap, VMSharedTypeIndex};
27 
28 #[allow(clippy::cast_possible_truncation)] // it's intended this is truncated on
29 // 32-bit platforms
30 const INVALID_PTR: usize = 0xdead_dead_beef_beef_u64 as usize;
31 
32 mod libcalls;
33 mod resources;
34 
35 pub use self::resources::{
36     CallContexts, ResourceTable, ResourceTables, TypedResource, TypedResourceIndex,
37 };
38 
39 /// Runtime representation of a component instance and all state necessary for
40 /// the instance itself.
41 ///
42 /// This type never exists by-value, but rather it's always behind a pointer.
43 /// The size of the allocation for `ComponentInstance` includes the trailing
44 /// `VMComponentContext` which is variably sized based on the `offsets`
45 /// contained within.
46 ///
47 /// # Pin
48 ///
49 /// Note that this type is mutated through `Pin<&mut ComponentInstance>` in the
50 /// same manner as `vm::Instance` for core modules, and see more information
51 /// over there for documentation and rationale.
52 #[repr(C)]
53 pub struct ComponentInstance {
54     /// The index within the store of where to find this component instance.
55     id: ComponentInstanceId,
56 
57     /// Size and offset information for the trailing `VMComponentContext`.
58     offsets: VMComponentOffsets<HostPtr>,
59 
60     /// The component that this instance was created from.
61     //
62     // NB: in the future if necessary it would be possible to avoid storing an
63     // entire `Component` here and instead storing only information such as:
64     //
65     // * Some reference to `Arc<ComponentTypes>`
66     // * Necessary references to closed-over modules which are exported from the
67     //   component itself.
68     //
69     // Otherwise the full guts of this component should only ever be used during
70     // the instantiation of this instance, meaning that after instantiation much
71     // of the component can be thrown away (theoretically).
72     component: Component,
73 
74     /// State of resources for this component.
75     ///
76     /// This is paired with other information to create a `ResourceTables` which
77     /// is how this field is manipulated.
78     instance_resource_tables: PrimaryMap<RuntimeComponentInstanceIndex, ResourceTable>,
79 
80     /// What all compile-time-identified core instances are mapped to within the
81     /// `Store` that this component belongs to.
82     instances: PrimaryMap<RuntimeInstanceIndex, InstanceId>,
83 
84     /// Storage for the type information about resources within this component
85     /// instance.
86     resource_types: Arc<PrimaryMap<ResourceIndex, ResourceType>>,
87 
88     /// Arguments that this instance used to be instantiated.
89     ///
90     /// Strong references are stored to these arguments since pointers are saved
91     /// into the structures such as functions within the
92     /// `OwnedComponentInstance` but it's our job to keep them alive.
93     ///
94     /// One purpose of this storage is to enable embedders to drop a `Linker`,
95     /// for example, after a component is instantiated. In that situation if the
96     /// arguments weren't held here then they might be dropped, and structures
97     /// such as `.lowering()` which point back into the original function would
98     /// become stale and use-after-free conditions when used. By preserving the
99     /// entire list here though we're guaranteed that nothing is lost for the
100     /// duration of the lifetime of this instance.
101     imports: Arc<PrimaryMap<RuntimeImportIndex, RuntimeImport>>,
102 
103     /// Self-pointer back to `Store<T>` and its functions.
104     store: VMStoreRawPtr,
105 
106     /// Cached ABI return value from the last-invoked function call along with
107     /// the function index that was invoked.
108     ///
109     /// Used in `post_return_arg_set` and `post_return_arg_take` below.
110     post_return_arg: Option<(ExportIndex, ValRaw)>,
111 
112     /// Required by `InstanceLayout`, also required to be the last field (with
113     /// repr(C))
114     vmctx: OwnedVMContext<VMComponentContext>,
115 }
116 
117 /// Type signature for host-defined trampolines that are called from
118 /// WebAssembly.
119 ///
120 /// This function signature is invoked from a cranelift-compiled trampoline that
121 /// adapts from the core wasm System-V ABI into the ABI provided here:
122 ///
123 /// * `vmctx` - this is the first argument to the wasm import, and should always
124 ///   end up being a `VMComponentContext`.
125 /// * `data` - this is the data pointer associated with the `VMLowering` for
126 ///   which this function pointer was registered.
127 /// * `ty` - the type index, relative to the tables in `vmctx`, that is the
128 ///   type of the function being called.
129 /// * `caller_instance` - the `RuntimeComponentInstanceIndex` representing the
130 ///   caller component instance, used to track the owner of an async host task.
131 /// * `flags` - the component flags for may_enter/leave corresponding to the
132 ///   component instance that the lowering happened within.
133 /// * `opt_memory` - this nullable pointer represents the memory configuration
134 ///   option for the canonical ABI options.
135 /// * `opt_realloc` - this nullable pointer represents the realloc configuration
136 ///   option for the canonical ABI options.
137 /// * `string_encoding` - this is the configured string encoding for the
138 ///   canonical ABI this lowering corresponds to.
139 /// * `async_` - whether the caller is using the async ABI.
140 /// * `args_and_results` - pointer to stack-allocated space in the caller where
141 ///   all the arguments are stored as well as where the results will be written
142 ///   to. The size and initialized bytes of this depends on the core wasm type
143 ///   signature that this callee corresponds to.
144 /// * `nargs_and_results` - the size, in units of `ValRaw`, of
145 ///   `args_and_results`.
146 ///
147 /// This function returns a `bool` which indicates whether the call succeeded
148 /// or not. On failure this function records trap information in TLS which
149 /// should be suitable for reading later.
150 //
151 // FIXME: 11 arguments is probably too many. The `data` through `string-encoding`
152 // parameters should probably get packaged up into the `VMComponentContext`.
153 // Needs benchmarking one way or another though to figure out what the best
154 // balance is here.
155 pub type VMLoweringCallee = extern "C" fn(
156     vmctx: NonNull<VMOpaqueContext>,
157     data: NonNull<u8>,
158     ty: u32,
159     caller_instance: u32,
160     flags: NonNull<VMGlobalDefinition>,
161     opt_memory: *mut VMMemoryDefinition,
162     opt_realloc: *mut VMFuncRef,
163     string_encoding: u8,
164     async_: u8,
165     args_and_results: NonNull<mem::MaybeUninit<ValRaw>>,
166     nargs_and_results: usize,
167 ) -> bool;
168 
169 /// An opaque function pointer which is a `VMLoweringFunction` under the hood
170 /// but this is stored as `VMPtr<VMLoweringFunction>` within `VMLowering` below
171 /// to handle provenance correctly when using Pulley.
172 #[repr(transparent)]
173 pub struct VMLoweringFunction(VMFunctionBody);
174 
175 /// Structure describing a lowered host function stored within a
176 /// `VMComponentContext` per-lowering.
177 #[derive(Copy, Clone)]
178 #[repr(C)]
179 pub struct VMLowering {
180     /// The host function pointer that is invoked when this lowering is
181     /// invoked.
182     pub callee: VmPtr<VMLoweringFunction>,
183     /// The host data pointer (think void* pointer) to get passed to `callee`.
184     pub data: VmPtr<u8>,
185 }
186 
187 // SAFETY: the above structure is repr(C) and only contains `VmSafe` fields.
188 unsafe impl VmSafe for VMLowering {}
189 
190 /// This is a marker type to represent the underlying allocation of a
191 /// `VMComponentContext`.
192 ///
193 /// This type is similar to `VMContext` for core wasm and is allocated once per
194 /// component instance in Wasmtime. While the static size of this type is 0 the
195 /// actual runtime size is variable depending on the shape of the component that
196 /// this corresponds to. This structure always trails a `ComponentInstance`
197 /// allocation and the allocation/lifetime of this allocation is managed by
198 /// `ComponentInstance`.
199 #[repr(C)]
200 // Set an appropriate alignment for this structure where the most-aligned value
201 // internally right now `VMGlobalDefinition` which has an alignment of 16 bytes.
202 #[repr(align(16))]
203 pub struct VMComponentContext;
204 
205 impl ComponentInstance {
206     /// Converts the `vmctx` provided into a `ComponentInstance` and runs the
207     /// provided closure with that instance.
208     ///
209     /// # Unsafety
210     ///
211     /// This is `unsafe` because `vmctx` cannot be guaranteed to be a valid
212     /// pointer and it cannot be proven statically that it's safe to get a
213     /// mutable reference at this time to the instance from `vmctx`.
214     pub unsafe fn from_vmctx<R>(
215         vmctx: NonNull<VMComponentContext>,
216         f: impl FnOnce(&mut dyn VMStore, Instance) -> R,
217     ) -> R {
218         let mut ptr = vmctx
219             .byte_sub(mem::size_of::<ComponentInstance>())
220             .cast::<ComponentInstance>();
221         let reference = ptr.as_mut();
222         let store = &mut *reference.store.0.as_ptr();
223         let instance = Instance::from_wasmtime(store, reference.id);
224         f(store, instance)
225     }
226 
227     /// Returns the layout corresponding to what would be an allocation of a
228     /// `ComponentInstance` for the `offsets` provided.
229     ///
230     /// The returned layout has space for both the `ComponentInstance` and the
231     /// trailing `VMComponentContext`.
232     fn alloc_layout(offsets: &VMComponentOffsets<HostPtr>) -> Layout {
233         let size = mem::size_of::<Self>()
234             .checked_add(usize::try_from(offsets.size_of_vmctx()).unwrap())
235             .unwrap();
236         let align = mem::align_of::<Self>();
237         Layout::from_size_align(size, align).unwrap()
238     }
239 
240     /// Allocates a new `ComponentInstance + VMComponentContext` pair on the
241     /// heap with `malloc` and configures it for the `component` specified.
242     pub(crate) fn new(
243         id: ComponentInstanceId,
244         component: &Component,
245         resource_types: Arc<PrimaryMap<ResourceIndex, ResourceType>>,
246         imports: &Arc<PrimaryMap<RuntimeImportIndex, RuntimeImport>>,
247         store: NonNull<dyn VMStore>,
248     ) -> OwnedComponentInstance {
249         let offsets = VMComponentOffsets::new(HostPtr, component.env_component());
250         let num_instances = component.env_component().num_runtime_component_instances;
251         let mut instance_resource_tables =
252             PrimaryMap::with_capacity(num_instances.try_into().unwrap());
253         for _ in 0..num_instances {
254             instance_resource_tables.push(ResourceTable::default());
255         }
256         let mut ret = OwnedInstance::new(ComponentInstance {
257             id,
258             offsets,
259             instance_resource_tables,
260             instances: PrimaryMap::with_capacity(
261                 component
262                     .env_component()
263                     .num_runtime_instances
264                     .try_into()
265                     .unwrap(),
266             ),
267             component: component.clone(),
268             resource_types,
269             imports: imports.clone(),
270             store: VMStoreRawPtr(store),
271             post_return_arg: None,
272             vmctx: OwnedVMContext::new(),
273         });
274         unsafe {
275             ret.get_mut().initialize_vmctx();
276         }
277         ret
278     }
279 
280     #[inline]
281     pub fn vmctx(&self) -> NonNull<VMComponentContext> {
282         InstanceLayout::vmctx(self)
283     }
284 
285     /// Returns a pointer to the "may leave" flag for this instance specified
286     /// for canonical lowering and lifting operations.
287     #[inline]
288     pub fn instance_flags(&self, instance: RuntimeComponentInstanceIndex) -> InstanceFlags {
289         unsafe {
290             let ptr = self
291                 .vmctx_plus_offset_raw::<VMGlobalDefinition>(self.offsets.instance_flags(instance));
292             InstanceFlags(SendSyncPtr::new(ptr))
293         }
294     }
295 
296     /// Returns the runtime memory definition corresponding to the index of the
297     /// memory provided.
298     ///
299     /// This can only be called after `idx` has been initialized at runtime
300     /// during the instantiation process of a component.
301     pub fn runtime_memory(&self, idx: RuntimeMemoryIndex) -> *mut VMMemoryDefinition {
302         unsafe {
303             let ret = *self.vmctx_plus_offset::<VmPtr<_>>(self.offsets.runtime_memory(idx));
304             debug_assert!(ret.as_ptr() as usize != INVALID_PTR);
305             ret.as_ptr()
306         }
307     }
308 
309     /// Returns the runtime table definition and associated instance `VMContext`
310     /// corresponding to the index of the table provided.
311     ///
312     /// This can only be called after `idx` has been initialized at runtime
313     /// during the instantiation process of a component.
314     pub fn runtime_table(&self, idx: RuntimeTableIndex) -> VMTableImport {
315         unsafe {
316             let ret = *self.vmctx_plus_offset::<VMTableImport>(self.offsets.runtime_table(idx));
317             debug_assert!(ret.from.as_ptr() as usize != INVALID_PTR);
318             debug_assert!(ret.vmctx.as_ptr() as usize != INVALID_PTR);
319             ret
320         }
321     }
322 
323     /// Returns the realloc pointer corresponding to the index provided.
324     ///
325     /// This can only be called after `idx` has been initialized at runtime
326     /// during the instantiation process of a component.
327     pub fn runtime_realloc(&self, idx: RuntimeReallocIndex) -> NonNull<VMFuncRef> {
328         unsafe {
329             let ret = *self.vmctx_plus_offset::<VmPtr<_>>(self.offsets.runtime_realloc(idx));
330             debug_assert!(ret.as_ptr() as usize != INVALID_PTR);
331             ret.as_non_null()
332         }
333     }
334 
335     /// Returns the post-return pointer corresponding to the index provided.
336     ///
337     /// This can only be called after `idx` has been initialized at runtime
338     /// during the instantiation process of a component.
339     pub fn runtime_post_return(&self, idx: RuntimePostReturnIndex) -> NonNull<VMFuncRef> {
340         unsafe {
341             let ret = *self.vmctx_plus_offset::<VmPtr<_>>(self.offsets.runtime_post_return(idx));
342             debug_assert!(ret.as_ptr() as usize != INVALID_PTR);
343             ret.as_non_null()
344         }
345     }
346 
347     /// Returns the host information for the lowered function at the index
348     /// specified.
349     ///
350     /// This can only be called after `idx` has been initialized at runtime
351     /// during the instantiation process of a component.
352     pub fn lowering(&self, idx: LoweredIndex) -> VMLowering {
353         unsafe {
354             let ret = *self.vmctx_plus_offset::<VMLowering>(self.offsets.lowering(idx));
355             debug_assert!(ret.callee.as_ptr() as usize != INVALID_PTR);
356             debug_assert!(ret.data.as_ptr() as usize != INVALID_PTR);
357             ret
358         }
359     }
360 
361     /// Returns the core wasm `funcref` corresponding to the trampoline
362     /// specified.
363     ///
364     /// The returned function is suitable to pass directly to a wasm module
365     /// instantiation and the function contains cranelift-compiled trampolines.
366     ///
367     /// This can only be called after `idx` has been initialized at runtime
368     /// during the instantiation process of a component.
369     pub fn trampoline_func_ref(&self, idx: TrampolineIndex) -> NonNull<VMFuncRef> {
370         unsafe {
371             let offset = self.offsets.trampoline_func_ref(idx);
372             let ret = self.vmctx_plus_offset_raw::<VMFuncRef>(offset);
373             debug_assert!(
374                 mem::transmute::<Option<VmPtr<VMWasmCallFunction>>, usize>(ret.as_ref().wasm_call)
375                     != INVALID_PTR
376             );
377             debug_assert!(ret.as_ref().vmctx.as_ptr() as usize != INVALID_PTR);
378             ret
379         }
380     }
381 
382     /// Stores the runtime memory pointer at the index specified.
383     ///
384     /// This is intended to be called during the instantiation process of a
385     /// component once a memory is available, which may not be until part-way
386     /// through component instantiation.
387     ///
388     /// Note that it should be a property of the component model that the `ptr`
389     /// here is never needed prior to it being configured here in the instance.
390     pub fn set_runtime_memory(
391         self: Pin<&mut Self>,
392         idx: RuntimeMemoryIndex,
393         ptr: NonNull<VMMemoryDefinition>,
394     ) {
395         unsafe {
396             let offset = self.offsets.runtime_memory(idx);
397             let storage = self.vmctx_plus_offset_mut::<VmPtr<VMMemoryDefinition>>(offset);
398             debug_assert!((*storage).as_ptr() as usize == INVALID_PTR);
399             *storage = ptr.into();
400         }
401     }
402 
403     /// Same as `set_runtime_memory` but for realloc function pointers.
404     pub fn set_runtime_realloc(
405         self: Pin<&mut Self>,
406         idx: RuntimeReallocIndex,
407         ptr: NonNull<VMFuncRef>,
408     ) {
409         unsafe {
410             let offset = self.offsets.runtime_realloc(idx);
411             let storage = self.vmctx_plus_offset_mut::<VmPtr<VMFuncRef>>(offset);
412             debug_assert!((*storage).as_ptr() as usize == INVALID_PTR);
413             *storage = ptr.into();
414         }
415     }
416 
417     /// Same as `set_runtime_memory` but for async callback function pointers.
418     pub fn set_runtime_callback(
419         self: Pin<&mut Self>,
420         idx: RuntimeCallbackIndex,
421         ptr: NonNull<VMFuncRef>,
422     ) {
423         unsafe {
424             let offset = self.offsets.runtime_callback(idx);
425             let storage = self.vmctx_plus_offset_mut::<VmPtr<VMFuncRef>>(offset);
426             debug_assert!((*storage).as_ptr() as usize == INVALID_PTR);
427             *storage = ptr.into();
428         }
429     }
430 
431     /// Same as `set_runtime_memory` but for post-return function pointers.
432     pub fn set_runtime_post_return(
433         self: Pin<&mut Self>,
434         idx: RuntimePostReturnIndex,
435         ptr: NonNull<VMFuncRef>,
436     ) {
437         unsafe {
438             let offset = self.offsets.runtime_post_return(idx);
439             let storage = self.vmctx_plus_offset_mut::<VmPtr<VMFuncRef>>(offset);
440             debug_assert!((*storage).as_ptr() as usize == INVALID_PTR);
441             *storage = ptr.into();
442         }
443     }
444 
445     /// Stores the runtime table pointer at the index specified.
446     ///
447     /// This is intended to be called during the instantiation process of a
448     /// component once a table is available, which may not be until part-way
449     /// through component instantiation.
450     ///
451     /// Note that it should be a property of the component model that the `ptr`
452     /// here is never needed prior to it being configured here in the instance.
453     pub fn set_runtime_table(
454         self: Pin<&mut Self>,
455         idx: RuntimeTableIndex,
456         ptr: NonNull<VMTableDefinition>,
457         vmctx: NonNull<VMContext>,
458         index: DefinedTableIndex,
459     ) {
460         unsafe {
461             let offset = self.offsets.runtime_table(idx);
462             let storage = self.vmctx_plus_offset_mut::<VMTableImport>(offset);
463             debug_assert!((*storage).vmctx.as_ptr() as usize == INVALID_PTR);
464             debug_assert!((*storage).from.as_ptr() as usize == INVALID_PTR);
465             *storage = VMTableImport {
466                 vmctx: vmctx.into(),
467                 from: ptr.into(),
468                 index,
469             };
470         }
471     }
472 
473     /// Configures host runtime lowering information associated with imported f
474     /// functions for the `idx` specified.
475     pub fn set_lowering(self: Pin<&mut Self>, idx: LoweredIndex, lowering: VMLowering) {
476         unsafe {
477             let callee = self.offsets.lowering_callee(idx);
478             debug_assert!(*self.vmctx_plus_offset::<usize>(callee) == INVALID_PTR);
479             let data = self.offsets.lowering_data(idx);
480             debug_assert!(*self.vmctx_plus_offset::<usize>(data) == INVALID_PTR);
481             let offset = self.offsets.lowering(idx);
482             *self.vmctx_plus_offset_mut(offset) = lowering;
483         }
484     }
485 
486     /// Same as `set_lowering` but for the resource.drop functions.
487     pub fn set_trampoline(
488         self: Pin<&mut Self>,
489         idx: TrampolineIndex,
490         wasm_call: NonNull<VMWasmCallFunction>,
491         array_call: NonNull<VMArrayCallFunction>,
492         type_index: VMSharedTypeIndex,
493     ) {
494         unsafe {
495             let offset = self.offsets.trampoline_func_ref(idx);
496             debug_assert!(*self.vmctx_plus_offset::<usize>(offset) == INVALID_PTR);
497             let vmctx = VMOpaqueContext::from_vmcomponent(self.vmctx());
498             *self.vmctx_plus_offset_mut(offset) = VMFuncRef {
499                 wasm_call: Some(wasm_call.into()),
500                 array_call: array_call.into(),
501                 type_index,
502                 vmctx: vmctx.into(),
503             };
504         }
505     }
506 
507     /// Configures the destructor for a resource at the `idx` specified.
508     ///
509     /// This is required to be called for each resource as it's defined within a
510     /// component during the instantiation process.
511     pub fn set_resource_destructor(
512         self: Pin<&mut Self>,
513         idx: ResourceIndex,
514         dtor: Option<NonNull<VMFuncRef>>,
515     ) {
516         unsafe {
517             let offset = self.offsets.resource_destructor(idx);
518             debug_assert!(*self.vmctx_plus_offset::<usize>(offset) == INVALID_PTR);
519             *self.vmctx_plus_offset_mut(offset) = dtor.map(VmPtr::from);
520         }
521     }
522 
523     /// Returns the destructor, if any, for `idx`.
524     ///
525     /// This is only valid to call after `set_resource_destructor`, or typically
526     /// after instantiation.
527     pub fn resource_destructor(&self, idx: ResourceIndex) -> Option<NonNull<VMFuncRef>> {
528         unsafe {
529             let offset = self.offsets.resource_destructor(idx);
530             debug_assert!(*self.vmctx_plus_offset::<usize>(offset) != INVALID_PTR);
531             (*self.vmctx_plus_offset::<Option<VmPtr<VMFuncRef>>>(offset)).map(|p| p.as_non_null())
532         }
533     }
534 
535     unsafe fn initialize_vmctx(mut self: Pin<&mut Self>) {
536         let offset = self.offsets.magic();
537         *self.as_mut().vmctx_plus_offset_mut(offset) = VMCOMPONENT_MAGIC;
538         // Initialize the built-in functions
539         static BUILTINS: libcalls::VMComponentBuiltins = libcalls::VMComponentBuiltins::INIT;
540         let ptr = BUILTINS.expose_provenance();
541         let offset = self.offsets.builtins();
542         *self.as_mut().vmctx_plus_offset_mut(offset) = VmPtr::from(ptr);
543         let offset = self.offsets.vm_store_context();
544         *self.as_mut().vmctx_plus_offset_mut(offset) =
545             VmPtr::from(self.store.0.as_ref().vm_store_context_ptr());
546 
547         for i in 0..self.offsets.num_runtime_component_instances {
548             let i = RuntimeComponentInstanceIndex::from_u32(i);
549             let mut def = VMGlobalDefinition::new();
550             *def.as_i32_mut() = FLAG_MAY_ENTER | FLAG_MAY_LEAVE;
551             self.instance_flags(i).as_raw().write(def);
552         }
553 
554         // In debug mode set non-null bad values to all "pointer looking" bits
555         // and pieces related to lowering and such. This'll help detect any
556         // erroneous usage and enable debug assertions above as well to prevent
557         // loading these before they're configured or setting them twice.
558         if cfg!(debug_assertions) {
559             for i in 0..self.offsets.num_lowerings {
560                 let i = LoweredIndex::from_u32(i);
561                 let offset = self.offsets.lowering_callee(i);
562                 *self.as_mut().vmctx_plus_offset_mut(offset) = INVALID_PTR;
563                 let offset = self.offsets.lowering_data(i);
564                 *self.as_mut().vmctx_plus_offset_mut(offset) = INVALID_PTR;
565             }
566             for i in 0..self.offsets.num_trampolines {
567                 let i = TrampolineIndex::from_u32(i);
568                 let offset = self.offsets.trampoline_func_ref(i);
569                 *self.as_mut().vmctx_plus_offset_mut(offset) = INVALID_PTR;
570             }
571             for i in 0..self.offsets.num_runtime_memories {
572                 let i = RuntimeMemoryIndex::from_u32(i);
573                 let offset = self.offsets.runtime_memory(i);
574                 *self.as_mut().vmctx_plus_offset_mut(offset) = INVALID_PTR;
575             }
576             for i in 0..self.offsets.num_runtime_reallocs {
577                 let i = RuntimeReallocIndex::from_u32(i);
578                 let offset = self.offsets.runtime_realloc(i);
579                 *self.as_mut().vmctx_plus_offset_mut(offset) = INVALID_PTR;
580             }
581             for i in 0..self.offsets.num_runtime_callbacks {
582                 let i = RuntimeCallbackIndex::from_u32(i);
583                 let offset = self.offsets.runtime_callback(i);
584                 *self.as_mut().vmctx_plus_offset_mut(offset) = INVALID_PTR;
585             }
586             for i in 0..self.offsets.num_runtime_post_returns {
587                 let i = RuntimePostReturnIndex::from_u32(i);
588                 let offset = self.offsets.runtime_post_return(i);
589                 *self.as_mut().vmctx_plus_offset_mut(offset) = INVALID_PTR;
590             }
591             for i in 0..self.offsets.num_resources {
592                 let i = ResourceIndex::from_u32(i);
593                 let offset = self.offsets.resource_destructor(i);
594                 *self.as_mut().vmctx_plus_offset_mut(offset) = INVALID_PTR;
595             }
596             for i in 0..self.offsets.num_runtime_tables {
597                 let i = RuntimeTableIndex::from_u32(i);
598                 let offset = self.offsets.runtime_table(i);
599                 *self.as_mut().vmctx_plus_offset_mut(offset) = INVALID_PTR;
600             }
601         }
602     }
603 
604     /// Returns a reference to the component type information for this
605     /// instance.
606     pub fn component(&self) -> &Component {
607         &self.component
608     }
609 
610     /// Returns a reference to the resource type information.
611     pub fn resource_types(&self) -> &Arc<PrimaryMap<ResourceIndex, ResourceType>> {
612         &self.resource_types
613     }
614 
615     /// Returns a mutable reference to the resource type information.
616     pub fn resource_types_mut(
617         self: Pin<&mut Self>,
618     ) -> &mut Arc<PrimaryMap<ResourceIndex, ResourceType>> {
619         // SAFETY: we've chosen the `Pin` guarantee of `Self` to not apply to
620         // the map returned.
621         unsafe { &mut self.get_unchecked_mut().resource_types }
622     }
623 
624     /// Returns whether the resource that `ty` points to is owned by the
625     /// instance that `ty` correspond to.
626     ///
627     /// This is used when lowering borrows to skip table management and instead
628     /// thread through the underlying representation directly.
629     pub fn resource_owned_by_own_instance(&self, ty: TypeResourceTableIndex) -> bool {
630         let resource = &self.component.types()[ty];
631         let component = self.component.env_component();
632         let idx = match component.defined_resource_index(resource.ty) {
633             Some(idx) => idx,
634             None => return false,
635         };
636         resource.instance == component.defined_resource_instances[idx]
637     }
638 
639     /// Returns the runtime state of resources associated with this component.
640     #[inline]
641     pub fn guest_tables(
642         self: Pin<&mut Self>,
643     ) -> (
644         &mut PrimaryMap<RuntimeComponentInstanceIndex, ResourceTable>,
645         &ComponentTypes,
646     ) {
647         // safety: we've chosen the `pin` guarantee of `self` to not apply to
648         // the map returned.
649         unsafe {
650             let me = self.get_unchecked_mut();
651             (&mut me.instance_resource_tables, me.component.types())
652         }
653     }
654 
655     /// Returns the destructor and instance flags for the specified resource
656     /// table type.
657     ///
658     /// This will lookup the origin definition of the `ty` table and return the
659     /// destructor/flags for that.
660     pub fn dtor_and_flags(
661         &self,
662         ty: TypeResourceTableIndex,
663     ) -> (Option<NonNull<VMFuncRef>>, Option<InstanceFlags>) {
664         let resource = self.component.types()[ty].ty;
665         let dtor = self.resource_destructor(resource);
666         let component = self.component.env_component();
667         let flags = component.defined_resource_index(resource).map(|i| {
668             let instance = component.defined_resource_instances[i];
669             self.instance_flags(instance)
670         });
671         (dtor, flags)
672     }
673 
674     /// Returns the store-local id that points to this component.
675     pub fn id(&self) -> ComponentInstanceId {
676         self.id
677     }
678 
679     /// Pushes a new runtime instance that's been created into
680     /// `self.instances`.
681     pub fn push_instance_id(self: Pin<&mut Self>, id: InstanceId) -> RuntimeInstanceIndex {
682         self.instances_mut().push(id)
683     }
684 
685     /// Returns the [`InstanceId`] previously pushed by `push_instance_id`
686     /// above.
687     ///
688     /// # Panics
689     ///
690     /// Panics if `idx` hasn't been initialized yet.
691     pub fn instance(&self, idx: RuntimeInstanceIndex) -> InstanceId {
692         self.instances[idx]
693     }
694 
695     fn instances_mut(self: Pin<&mut Self>) -> &mut PrimaryMap<RuntimeInstanceIndex, InstanceId> {
696         // SAFETY: we've chosen the `Pin` guarantee of `Self` to not apply to
697         // the map returned.
698         unsafe { &mut self.get_unchecked_mut().instances }
699     }
700 
701     /// Looks up the value used for `import` at runtime.
702     ///
703     /// # Panics
704     ///
705     /// Panics of `import` is out of bounds for this component.
706     pub(crate) fn runtime_import(&self, import: RuntimeImportIndex) -> &RuntimeImport {
707         &self.imports[import]
708     }
709 
710     /// Returns an `InstancePre<T>` which can be used to re-instantiated this
711     /// component if desired.
712     ///
713     /// # Safety
714     ///
715     /// This function places no bounds on `T` so it's up to the caller to match
716     /// that up appropriately with the store that this instance resides within.
717     pub unsafe fn instance_pre<T>(&self) -> InstancePre<T> {
718         // SAFETY: The `T` part of `new_unchecked` is forwarded as a contract of
719         // this function, and otherwise the validity of the components of the
720         // InstancePre should be guaranteed as it's what we were built with
721         // ourselves.
722         unsafe {
723             InstancePre::new_unchecked(
724                 self.component.clone(),
725                 self.imports.clone(),
726                 self.resource_types.clone(),
727             )
728         }
729     }
730 
731     /// Sets the cached argument for the canonical ABI option `post-return` to
732     /// the `arg` specified.
733     ///
734     /// This function is used in conjunction with function calls to record,
735     /// after a fuction call completes, the optional ABI return value. This
736     /// return value is cached within this instance for future use when the
737     /// `post_return` Rust-API-level function is invoked.
738     ///
739     /// Note that `index` here is the index of the export that was just
740     /// invoked, and this is used to ensure that `post_return` is called on the
741     /// same function afterwards. This restriction technically isn't necessary
742     /// though and may be one we want to lift in the future.
743     ///
744     /// # Panics
745     ///
746     /// This function will panic if `post_return_arg` is already set to `Some`.
747     pub fn post_return_arg_set(self: Pin<&mut Self>, index: ExportIndex, arg: ValRaw) {
748         assert!(self.post_return_arg.is_none());
749         *self.post_return_arg_mut() = Some((index, arg));
750     }
751 
752     /// Re-acquires the value originally saved via `post_return_arg_set`.
753     ///
754     /// This function will take a function `index` that's having its
755     /// `post_return` function called. If an argument was previously stored and
756     /// `index` matches the index that was stored then `Some(arg)` is returned.
757     /// Otherwise `None` is returned.
758     pub fn post_return_arg_take(self: Pin<&mut Self>, index: ExportIndex) -> Option<ValRaw> {
759         let post_return_arg = self.post_return_arg_mut();
760         let (expected_index, arg) = post_return_arg.take()?;
761         if index != expected_index {
762             *post_return_arg = Some((expected_index, arg));
763             None
764         } else {
765             Some(arg)
766         }
767     }
768 
769     fn post_return_arg_mut(self: Pin<&mut Self>) -> &mut Option<(ExportIndex, ValRaw)> {
770         // SAFETY: we've chosen the `Pin` guarantee of `Self` to not apply to
771         // the map returned.
772         unsafe { &mut self.get_unchecked_mut().post_return_arg }
773     }
774 }
775 
776 // SAFETY: `layout` should describe this accurately and `OwnedVMContext` is the
777 // last field of `ComponentInstance`.
778 unsafe impl InstanceLayout for ComponentInstance {
779     /// Technically it is not required to `alloc_zeroed` here. The primary
780     /// reason for doing this is because a component context start is a "partly
781     /// initialized" state where pointers and such are configured as the
782     /// instantiation process continues. The component model should guarantee
783     /// that we never access uninitialized memory in the context, but to help
784     /// protect against possible bugs a zeroed allocation is done here to try to
785     /// contain use-before-initialized issues.
786     const INIT_ZEROED: bool = true;
787 
788     type VMContext = VMComponentContext;
789 
790     fn layout(&self) -> Layout {
791         ComponentInstance::alloc_layout(&self.offsets)
792     }
793 
794     fn owned_vmctx(&self) -> &OwnedVMContext<VMComponentContext> {
795         &self.vmctx
796     }
797 
798     fn owned_vmctx_mut(&mut self) -> &mut OwnedVMContext<VMComponentContext> {
799         &mut self.vmctx
800     }
801 }
802 
803 pub type OwnedComponentInstance = OwnedInstance<ComponentInstance>;
804 
805 impl VMComponentContext {
806     /// Moves the `self` pointer backwards to the `ComponentInstance` pointer
807     /// that this `VMComponentContext` trails.
808     pub fn instance(&self) -> *mut ComponentInstance {
809         unsafe {
810             (self as *const Self as *mut u8)
811                 .offset(-(offset_of!(ComponentInstance, vmctx) as isize))
812                 as *mut ComponentInstance
813         }
814     }
815 
816     /// Helper function to cast between context types using a debug assertion to
817     /// protect against some mistakes.
818     #[inline]
819     pub unsafe fn from_opaque(opaque: NonNull<VMOpaqueContext>) -> NonNull<VMComponentContext> {
820         // See comments in `VMContext::from_opaque` for this debug assert
821         debug_assert_eq!(opaque.as_ref().magic, VMCOMPONENT_MAGIC);
822         opaque.cast()
823     }
824 }
825 
826 impl VMOpaqueContext {
827     /// Helper function to clearly indicate the cast desired
828     #[inline]
829     pub fn from_vmcomponent(ptr: NonNull<VMComponentContext>) -> NonNull<VMOpaqueContext> {
830         ptr.cast()
831     }
832 }
833 
834 #[allow(missing_docs)]
835 #[repr(transparent)]
836 #[derive(Copy, Clone)]
837 pub struct InstanceFlags(SendSyncPtr<VMGlobalDefinition>);
838 
839 #[allow(missing_docs)]
840 impl InstanceFlags {
841     /// Wraps the given pointer as an `InstanceFlags`
842     ///
843     /// # Unsafety
844     ///
845     /// This is a raw pointer argument which needs to be valid for the lifetime
846     /// that `InstanceFlags` is used.
847     pub unsafe fn from_raw(ptr: NonNull<VMGlobalDefinition>) -> InstanceFlags {
848         InstanceFlags(SendSyncPtr::from(ptr))
849     }
850 
851     #[inline]
852     pub unsafe fn may_leave(&self) -> bool {
853         *self.as_raw().as_ref().as_i32() & FLAG_MAY_LEAVE != 0
854     }
855 
856     #[inline]
857     pub unsafe fn set_may_leave(&mut self, val: bool) {
858         if val {
859             *self.as_raw().as_mut().as_i32_mut() |= FLAG_MAY_LEAVE;
860         } else {
861             *self.as_raw().as_mut().as_i32_mut() &= !FLAG_MAY_LEAVE;
862         }
863     }
864 
865     #[inline]
866     pub unsafe fn may_enter(&self) -> bool {
867         *self.as_raw().as_ref().as_i32() & FLAG_MAY_ENTER != 0
868     }
869 
870     #[inline]
871     pub unsafe fn set_may_enter(&mut self, val: bool) {
872         if val {
873             *self.as_raw().as_mut().as_i32_mut() |= FLAG_MAY_ENTER;
874         } else {
875             *self.as_raw().as_mut().as_i32_mut() &= !FLAG_MAY_ENTER;
876         }
877     }
878 
879     #[inline]
880     pub unsafe fn needs_post_return(&self) -> bool {
881         *self.as_raw().as_ref().as_i32() & FLAG_NEEDS_POST_RETURN != 0
882     }
883 
884     #[inline]
885     pub unsafe fn set_needs_post_return(&mut self, val: bool) {
886         if val {
887             *self.as_raw().as_mut().as_i32_mut() |= FLAG_NEEDS_POST_RETURN;
888         } else {
889             *self.as_raw().as_mut().as_i32_mut() &= !FLAG_NEEDS_POST_RETURN;
890         }
891     }
892 
893     #[inline]
894     pub fn as_raw(&self) -> NonNull<VMGlobalDefinition> {
895         self.0.as_non_null()
896     }
897 }
898