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