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