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