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