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