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