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