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