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