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