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     SendSyncPtr, VMArrayCallFunction, VMFuncRef, VMGlobalDefinition, VMMemoryDefinition,
15     VMOpaqueContext, VMStore, VMStoreRawPtr, VMTableImport, VMWasmCallFunction, ValRaw, VmPtr,
16     VmSafe,
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     /// # 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`. Note that
211     /// it must be also safe to borrow the store mutably, meaning it can't
212     /// already be in use elsewhere.
213     pub unsafe fn from_vmctx<R>(
214         vmctx: NonNull<VMComponentContext>,
215         f: impl FnOnce(&mut dyn VMStore, Instance) -> R,
216     ) -> R {
217         // SAFETY: it's a contract of this function that `vmctx` is a valid
218         // allocation which can go backwards to a `ComponentInstance`.
219         let mut ptr = unsafe {
220             vmctx
221                 .byte_sub(mem::size_of::<ComponentInstance>())
222                 .cast::<ComponentInstance>()
223         };
224         // SAFETY: it's a contract of this function that it's safe to use `ptr`
225         // as a mutable reference.
226         let reference = unsafe { ptr.as_mut() };
227 
228         // SAFETY: it's a contract of this function that it's safe to use the
229         // store mutably at this time.
230         let store = unsafe { &mut *reference.store.0.as_ptr() };
231 
232         let instance = Instance::from_wasmtime(store, reference.id);
233         f(store, instance)
234     }
235 
236     /// Returns the `InstanceId` associated with the `vmctx` provided.
237     ///
238     /// # Safety
239     ///
240     /// The `vmctx` pointer must be a valid pointer to read the
241     /// `ComponentInstanceId` from.
242     pub(crate) unsafe fn vmctx_instance_id(
243         vmctx: NonNull<VMComponentContext>,
244     ) -> ComponentInstanceId {
245         // SAFETY: it's a contract of this function that `vmctx` is a valid
246         // pointer with a `ComponentInstance` in front which can be read.
247         unsafe {
248             vmctx
249                 .byte_sub(mem::size_of::<ComponentInstance>())
250                 .cast::<ComponentInstance>()
251                 .as_ref()
252                 .id
253         }
254     }
255 
256     /// Returns the layout corresponding to what would be an allocation of a
257     /// `ComponentInstance` for the `offsets` provided.
258     ///
259     /// The returned layout has space for both the `ComponentInstance` and the
260     /// trailing `VMComponentContext`.
261     fn alloc_layout(offsets: &VMComponentOffsets<HostPtr>) -> Layout {
262         let size = mem::size_of::<Self>()
263             .checked_add(usize::try_from(offsets.size_of_vmctx()).unwrap())
264             .unwrap();
265         let align = mem::align_of::<Self>();
266         Layout::from_size_align(size, align).unwrap()
267     }
268 
269     /// Allocates a new `ComponentInstance + VMComponentContext` pair on the
270     /// heap with `malloc` and configures it for the `component` specified.
271     pub(crate) fn new(
272         id: ComponentInstanceId,
273         component: &Component,
274         resource_types: Arc<PrimaryMap<ResourceIndex, ResourceType>>,
275         imports: &Arc<PrimaryMap<RuntimeImportIndex, RuntimeImport>>,
276         store: NonNull<dyn VMStore>,
277     ) -> OwnedComponentInstance {
278         let offsets = VMComponentOffsets::new(HostPtr, component.env_component());
279         let num_instances = component.env_component().num_runtime_component_instances;
280         let mut instance_handle_tables =
281             PrimaryMap::with_capacity(num_instances.try_into().unwrap());
282         for _ in 0..num_instances {
283             instance_handle_tables.push(HandleTable::default());
284         }
285 
286         let mut ret = OwnedInstance::new(ComponentInstance {
287             id,
288             offsets,
289             instance_handle_tables,
290             instances: PrimaryMap::with_capacity(
291                 component
292                     .env_component()
293                     .num_runtime_instances
294                     .try_into()
295                     .unwrap(),
296             ),
297             component: component.clone(),
298             resource_types,
299             imports: imports.clone(),
300             store: VMStoreRawPtr(store),
301             post_return_arg: None,
302             #[cfg(feature = "component-model-async")]
303             concurrent_state: concurrent::ConcurrentState::new(component),
304             vmctx: OwnedVMContext::new(),
305         });
306         unsafe {
307             ret.get_mut().initialize_vmctx();
308         }
309         ret
310     }
311 
312     #[inline]
313     pub fn vmctx(&self) -> NonNull<VMComponentContext> {
314         InstanceLayout::vmctx(self)
315     }
316 
317     /// Returns a pointer to the "may leave" flag for this instance specified
318     /// for canonical lowering and lifting operations.
319     #[inline]
320     pub fn instance_flags(&self, instance: RuntimeComponentInstanceIndex) -> InstanceFlags {
321         unsafe {
322             let ptr = self
323                 .vmctx_plus_offset_raw::<VMGlobalDefinition>(self.offsets.instance_flags(instance));
324             InstanceFlags(SendSyncPtr::new(ptr))
325         }
326     }
327 
328     /// Returns the runtime memory definition corresponding to the index of the
329     /// memory provided.
330     ///
331     /// This can only be called after `idx` has been initialized at runtime
332     /// during the instantiation process of a component.
333     pub fn runtime_memory(&self, idx: RuntimeMemoryIndex) -> *mut VMMemoryDefinition {
334         unsafe {
335             let ret = *self.vmctx_plus_offset::<VmPtr<_>>(self.offsets.runtime_memory(idx));
336             debug_assert!(ret.as_ptr() as usize != INVALID_PTR);
337             ret.as_ptr()
338         }
339     }
340 
341     /// Returns the runtime table definition and associated instance `VMContext`
342     /// corresponding to the index of the table provided.
343     ///
344     /// This can only be called after `idx` has been initialized at runtime
345     /// during the instantiation process of a component.
346     pub fn runtime_table(&self, idx: RuntimeTableIndex) -> VMTableImport {
347         unsafe {
348             let ret = *self.vmctx_plus_offset::<VMTableImport>(self.offsets.runtime_table(idx));
349             debug_assert!(ret.from.as_ptr() as usize != INVALID_PTR);
350             debug_assert!(ret.vmctx.as_ptr() as usize != INVALID_PTR);
351             ret
352         }
353     }
354 
355     /// Returns the realloc pointer corresponding to the index provided.
356     ///
357     /// This can only be called after `idx` has been initialized at runtime
358     /// during the instantiation process of a component.
359     pub fn runtime_realloc(&self, idx: RuntimeReallocIndex) -> NonNull<VMFuncRef> {
360         unsafe {
361             let ret = *self.vmctx_plus_offset::<VmPtr<_>>(self.offsets.runtime_realloc(idx));
362             debug_assert!(ret.as_ptr() as usize != INVALID_PTR);
363             ret.as_non_null()
364         }
365     }
366 
367     /// Returns the async callback pointer corresponding to the index provided.
368     ///
369     /// This can only be called after `idx` has been initialized at runtime
370     /// during the instantiation process of a component.
371     pub fn runtime_callback(&self, idx: RuntimeCallbackIndex) -> NonNull<VMFuncRef> {
372         unsafe {
373             let ret = *self.vmctx_plus_offset::<VmPtr<_>>(self.offsets.runtime_callback(idx));
374             debug_assert!(ret.as_ptr() as usize != INVALID_PTR);
375             ret.as_non_null()
376         }
377     }
378 
379     /// Returns the post-return pointer corresponding to the index provided.
380     ///
381     /// This can only be called after `idx` has been initialized at runtime
382     /// during the instantiation process of a component.
383     pub fn runtime_post_return(&self, idx: RuntimePostReturnIndex) -> NonNull<VMFuncRef> {
384         unsafe {
385             let ret = *self.vmctx_plus_offset::<VmPtr<_>>(self.offsets.runtime_post_return(idx));
386             debug_assert!(ret.as_ptr() as usize != INVALID_PTR);
387             ret.as_non_null()
388         }
389     }
390 
391     /// Returns the host information for the lowered function at the index
392     /// specified.
393     ///
394     /// This can only be called after `idx` has been initialized at runtime
395     /// during the instantiation process of a component.
396     pub fn lowering(&self, idx: LoweredIndex) -> VMLowering {
397         unsafe {
398             let ret = *self.vmctx_plus_offset::<VMLowering>(self.offsets.lowering(idx));
399             debug_assert!(ret.callee.as_ptr() as usize != INVALID_PTR);
400             debug_assert!(ret.data.as_ptr() as usize != INVALID_PTR);
401             ret
402         }
403     }
404 
405     /// Returns the core wasm `funcref` corresponding to the trampoline
406     /// specified.
407     ///
408     /// The returned function is suitable to pass directly to a wasm module
409     /// instantiation and the function contains cranelift-compiled trampolines.
410     ///
411     /// This can only be called after `idx` has been initialized at runtime
412     /// during the instantiation process of a component.
413     pub fn trampoline_func_ref(&self, idx: TrampolineIndex) -> NonNull<VMFuncRef> {
414         unsafe {
415             let offset = self.offsets.trampoline_func_ref(idx);
416             let ret = self.vmctx_plus_offset_raw::<VMFuncRef>(offset);
417             debug_assert!(
418                 mem::transmute::<Option<VmPtr<VMWasmCallFunction>>, usize>(ret.as_ref().wasm_call)
419                     != INVALID_PTR
420             );
421             debug_assert!(ret.as_ref().vmctx.as_ptr() as usize != INVALID_PTR);
422             ret
423         }
424     }
425 
426     /// Stores the runtime memory pointer at the index specified.
427     ///
428     /// This is intended to be called during the instantiation process of a
429     /// component once a memory is available, which may not be until part-way
430     /// through component instantiation.
431     ///
432     /// Note that it should be a property of the component model that the `ptr`
433     /// here is never needed prior to it being configured here in the instance.
434     pub fn set_runtime_memory(
435         self: Pin<&mut Self>,
436         idx: RuntimeMemoryIndex,
437         ptr: NonNull<VMMemoryDefinition>,
438     ) {
439         unsafe {
440             let offset = self.offsets.runtime_memory(idx);
441             let storage = self.vmctx_plus_offset_mut::<VmPtr<VMMemoryDefinition>>(offset);
442             debug_assert!((*storage).as_ptr() as usize == INVALID_PTR);
443             *storage = ptr.into();
444         }
445     }
446 
447     /// Same as `set_runtime_memory` but for realloc function pointers.
448     pub fn set_runtime_realloc(
449         self: Pin<&mut Self>,
450         idx: RuntimeReallocIndex,
451         ptr: NonNull<VMFuncRef>,
452     ) {
453         unsafe {
454             let offset = self.offsets.runtime_realloc(idx);
455             let storage = self.vmctx_plus_offset_mut::<VmPtr<VMFuncRef>>(offset);
456             debug_assert!((*storage).as_ptr() as usize == INVALID_PTR);
457             *storage = ptr.into();
458         }
459     }
460 
461     /// Same as `set_runtime_memory` but for async callback function pointers.
462     pub fn set_runtime_callback(
463         self: Pin<&mut Self>,
464         idx: RuntimeCallbackIndex,
465         ptr: NonNull<VMFuncRef>,
466     ) {
467         unsafe {
468             let offset = self.offsets.runtime_callback(idx);
469             let storage = self.vmctx_plus_offset_mut::<VmPtr<VMFuncRef>>(offset);
470             debug_assert!((*storage).as_ptr() as usize == INVALID_PTR);
471             *storage = ptr.into();
472         }
473     }
474 
475     /// Same as `set_runtime_memory` but for post-return function pointers.
476     pub fn set_runtime_post_return(
477         self: Pin<&mut Self>,
478         idx: RuntimePostReturnIndex,
479         ptr: NonNull<VMFuncRef>,
480     ) {
481         unsafe {
482             let offset = self.offsets.runtime_post_return(idx);
483             let storage = self.vmctx_plus_offset_mut::<VmPtr<VMFuncRef>>(offset);
484             debug_assert!((*storage).as_ptr() as usize == INVALID_PTR);
485             *storage = ptr.into();
486         }
487     }
488 
489     /// Stores the runtime table pointer at the index specified.
490     ///
491     /// This is intended to be called during the instantiation process of a
492     /// component once a table is available, which may not be until part-way
493     /// through component instantiation.
494     ///
495     /// Note that it should be a property of the component model that the `ptr`
496     /// here is never needed prior to it being configured here in the instance.
497     pub fn set_runtime_table(self: Pin<&mut Self>, idx: RuntimeTableIndex, import: VMTableImport) {
498         unsafe {
499             let offset = self.offsets.runtime_table(idx);
500             let storage = self.vmctx_plus_offset_mut::<VMTableImport>(offset);
501             debug_assert!((*storage).vmctx.as_ptr() as usize == INVALID_PTR);
502             debug_assert!((*storage).from.as_ptr() as usize == INVALID_PTR);
503             *storage = import;
504         }
505     }
506 
507     /// Configures host runtime lowering information associated with imported f
508     /// functions for the `idx` specified.
509     pub fn set_lowering(self: Pin<&mut Self>, idx: LoweredIndex, lowering: VMLowering) {
510         unsafe {
511             let callee = self.offsets.lowering_callee(idx);
512             debug_assert!(*self.vmctx_plus_offset::<usize>(callee) == INVALID_PTR);
513             let data = self.offsets.lowering_data(idx);
514             debug_assert!(*self.vmctx_plus_offset::<usize>(data) == INVALID_PTR);
515             let offset = self.offsets.lowering(idx);
516             *self.vmctx_plus_offset_mut(offset) = lowering;
517         }
518     }
519 
520     /// Same as `set_lowering` but for the resource.drop functions.
521     pub fn set_trampoline(
522         self: Pin<&mut Self>,
523         idx: TrampolineIndex,
524         wasm_call: NonNull<VMWasmCallFunction>,
525         array_call: NonNull<VMArrayCallFunction>,
526         type_index: VMSharedTypeIndex,
527     ) {
528         unsafe {
529             let offset = self.offsets.trampoline_func_ref(idx);
530             debug_assert!(*self.vmctx_plus_offset::<usize>(offset) == INVALID_PTR);
531             let vmctx = VMOpaqueContext::from_vmcomponent(self.vmctx());
532             *self.vmctx_plus_offset_mut(offset) = VMFuncRef {
533                 wasm_call: Some(wasm_call.into()),
534                 array_call: array_call.into(),
535                 type_index,
536                 vmctx: vmctx.into(),
537             };
538         }
539     }
540 
541     /// Configures the destructor for a resource at the `idx` specified.
542     ///
543     /// This is required to be called for each resource as it's defined within a
544     /// component during the instantiation process.
545     pub fn set_resource_destructor(
546         self: Pin<&mut Self>,
547         idx: ResourceIndex,
548         dtor: Option<NonNull<VMFuncRef>>,
549     ) {
550         unsafe {
551             let offset = self.offsets.resource_destructor(idx);
552             debug_assert!(*self.vmctx_plus_offset::<usize>(offset) == INVALID_PTR);
553             *self.vmctx_plus_offset_mut(offset) = dtor.map(VmPtr::from);
554         }
555     }
556 
557     /// Returns the destructor, if any, for `idx`.
558     ///
559     /// This is only valid to call after `set_resource_destructor`, or typically
560     /// after instantiation.
561     pub fn resource_destructor(&self, idx: ResourceIndex) -> Option<NonNull<VMFuncRef>> {
562         unsafe {
563             let offset = self.offsets.resource_destructor(idx);
564             debug_assert!(*self.vmctx_plus_offset::<usize>(offset) != INVALID_PTR);
565             (*self.vmctx_plus_offset::<Option<VmPtr<VMFuncRef>>>(offset)).map(|p| p.as_non_null())
566         }
567     }
568 
569     unsafe fn initialize_vmctx(mut self: Pin<&mut Self>) {
570         let offset = self.offsets.magic();
571         // SAFETY: it's safe to write the magic value during initialization and
572         // this is also the right type of value to write.
573         unsafe {
574             *self.as_mut().vmctx_plus_offset_mut(offset) = VMCOMPONENT_MAGIC;
575         }
576 
577         // Initialize the built-in functions
578         //
579         // SAFETY: it's safe to initialize the vmctx in this function and this
580         // is also the right type of value to store in the vmctx.
581         static BUILTINS: libcalls::VMComponentBuiltins = libcalls::VMComponentBuiltins::INIT;
582         let ptr = BUILTINS.expose_provenance();
583         let offset = self.offsets.builtins();
584         unsafe {
585             *self.as_mut().vmctx_plus_offset_mut(offset) = VmPtr::from(ptr);
586         }
587 
588         // SAFETY: it's safe to initialize the vmctx in this function and this
589         // is also the right type of value to store in the vmctx.
590         let offset = self.offsets.vm_store_context();
591         unsafe {
592             *self.as_mut().vmctx_plus_offset_mut(offset) =
593                 VmPtr::from(self.store.0.as_ref().vm_store_context_ptr());
594         }
595 
596         for i in 0..self.offsets.num_runtime_component_instances {
597             let i = RuntimeComponentInstanceIndex::from_u32(i);
598             let mut def = VMGlobalDefinition::new();
599             // SAFETY: this is a valid initialization of all globals which are
600             // 32-bit values.
601             unsafe {
602                 *def.as_i32_mut() = FLAG_MAY_ENTER | FLAG_MAY_LEAVE;
603                 self.instance_flags(i).as_raw().write(def);
604             }
605         }
606 
607         // In debug mode set non-null bad values to all "pointer looking" bits
608         // and pieces related to lowering and such. This'll help detect any
609         // erroneous usage and enable debug assertions above as well to prevent
610         // loading these before they're configured or setting them twice.
611         //
612         // SAFETY: it's valid to write a garbage pointer during initialization
613         // when this is otherwise uninitialized memory
614         if cfg!(debug_assertions) {
615             for i in 0..self.offsets.num_lowerings {
616                 let i = LoweredIndex::from_u32(i);
617                 let offset = self.offsets.lowering_callee(i);
618                 // SAFETY: see above
619                 unsafe {
620                     *self.as_mut().vmctx_plus_offset_mut(offset) = INVALID_PTR;
621                 }
622                 let offset = self.offsets.lowering_data(i);
623                 // SAFETY: see above
624                 unsafe {
625                     *self.as_mut().vmctx_plus_offset_mut(offset) = INVALID_PTR;
626                 }
627             }
628             for i in 0..self.offsets.num_trampolines {
629                 let i = TrampolineIndex::from_u32(i);
630                 let offset = self.offsets.trampoline_func_ref(i);
631                 // SAFETY: see above
632                 unsafe {
633                     *self.as_mut().vmctx_plus_offset_mut(offset) = INVALID_PTR;
634                 }
635             }
636             for i in 0..self.offsets.num_runtime_memories {
637                 let i = RuntimeMemoryIndex::from_u32(i);
638                 let offset = self.offsets.runtime_memory(i);
639                 // SAFETY: see above
640                 unsafe {
641                     *self.as_mut().vmctx_plus_offset_mut(offset) = INVALID_PTR;
642                 }
643             }
644             for i in 0..self.offsets.num_runtime_reallocs {
645                 let i = RuntimeReallocIndex::from_u32(i);
646                 let offset = self.offsets.runtime_realloc(i);
647                 // SAFETY: see above
648                 unsafe {
649                     *self.as_mut().vmctx_plus_offset_mut(offset) = INVALID_PTR;
650                 }
651             }
652             for i in 0..self.offsets.num_runtime_callbacks {
653                 let i = RuntimeCallbackIndex::from_u32(i);
654                 let offset = self.offsets.runtime_callback(i);
655                 // SAFETY: see above
656                 unsafe {
657                     *self.as_mut().vmctx_plus_offset_mut(offset) = INVALID_PTR;
658                 }
659             }
660             for i in 0..self.offsets.num_runtime_post_returns {
661                 let i = RuntimePostReturnIndex::from_u32(i);
662                 let offset = self.offsets.runtime_post_return(i);
663                 // SAFETY: see above
664                 unsafe {
665                     *self.as_mut().vmctx_plus_offset_mut(offset) = INVALID_PTR;
666                 }
667             }
668             for i in 0..self.offsets.num_resources {
669                 let i = ResourceIndex::from_u32(i);
670                 let offset = self.offsets.resource_destructor(i);
671                 // SAFETY: see above
672                 unsafe {
673                     *self.as_mut().vmctx_plus_offset_mut(offset) = INVALID_PTR;
674                 }
675             }
676             for i in 0..self.offsets.num_runtime_tables {
677                 let i = RuntimeTableIndex::from_u32(i);
678                 let offset = self.offsets.runtime_table(i);
679                 // SAFETY: see above
680                 unsafe {
681                     *self.as_mut().vmctx_plus_offset_mut(offset) = INVALID_PTR;
682                 }
683             }
684         }
685     }
686 
687     /// Returns a reference to the component type information for this
688     /// instance.
689     pub fn component(&self) -> &Component {
690         &self.component
691     }
692 
693     /// Same as [`Self::component`] but additionally returns the
694     /// `Pin<&mut Self>` with the same original lifetime.
695     pub fn component_and_self(self: Pin<&mut Self>) -> (&Component, Pin<&mut Self>) {
696         // SAFETY: this function is projecting both `&Component` and the same
697         // pointer both connected to the same lifetime. This is safe because
698         // it's a contract of `Pin<&mut Self>` that the `Component` field is
699         // never written, meaning it's effectively unsafe to have `&mut
700         // Component` projected from `Pin<&mut Self>`. Consequently it's safe to
701         // have a read-only view of the field while still retaining mutable
702         // access to all other fields.
703         let component = unsafe { &*(&raw const self.component) };
704         (component, self)
705     }
706 
707     /// Returns a reference to the resource type information.
708     pub fn resource_types(&self) -> &Arc<PrimaryMap<ResourceIndex, ResourceType>> {
709         &self.resource_types
710     }
711 
712     /// Returns a mutable reference to the resource type information.
713     pub fn resource_types_mut(
714         self: Pin<&mut Self>,
715     ) -> &mut Arc<PrimaryMap<ResourceIndex, ResourceType>> {
716         // SAFETY: we've chosen the `Pin` guarantee of `Self` to not apply to
717         // the map returned.
718         unsafe { &mut self.get_unchecked_mut().resource_types }
719     }
720 
721     /// Returns whether the resource that `ty` points to is owned by the
722     /// instance that `ty` correspond to.
723     ///
724     /// This is used when lowering borrows to skip table management and instead
725     /// thread through the underlying representation directly.
726     pub fn resource_owned_by_own_instance(&self, ty: TypeResourceTableIndex) -> bool {
727         let resource = &self.component.types()[ty];
728         let component = self.component.env_component();
729         let idx = match component.defined_resource_index(resource.ty) {
730             Some(idx) => idx,
731             None => return false,
732         };
733         resource.instance == component.defined_resource_instances[idx]
734     }
735 
736     /// Returns the runtime state of resources associated with this component.
737     #[inline]
738     pub fn guest_tables(
739         self: Pin<&mut Self>,
740     ) -> (
741         &mut PrimaryMap<RuntimeComponentInstanceIndex, HandleTable>,
742         &ComponentTypes,
743     ) {
744         // safety: we've chosen the `pin` guarantee of `self` to not apply to
745         // the map returned.
746         unsafe {
747             let me = self.get_unchecked_mut();
748             (&mut me.instance_handle_tables, me.component.types())
749         }
750     }
751 
752     /// Returns the destructor and instance flags for the specified resource
753     /// table type.
754     ///
755     /// This will lookup the origin definition of the `ty` table and return the
756     /// destructor/flags for that.
757     pub fn dtor_and_flags(
758         &self,
759         ty: TypeResourceTableIndex,
760     ) -> (Option<NonNull<VMFuncRef>>, Option<InstanceFlags>) {
761         let resource = self.component.types()[ty].ty;
762         let dtor = self.resource_destructor(resource);
763         let component = self.component.env_component();
764         let flags = component.defined_resource_index(resource).map(|i| {
765             let instance = component.defined_resource_instances[i];
766             self.instance_flags(instance)
767         });
768         (dtor, flags)
769     }
770 
771     /// Returns the store-local id that points to this component.
772     pub fn id(&self) -> ComponentInstanceId {
773         self.id
774     }
775 
776     /// Pushes a new runtime instance that's been created into
777     /// `self.instances`.
778     pub fn push_instance_id(self: Pin<&mut Self>, id: InstanceId) -> RuntimeInstanceIndex {
779         self.instances_mut().push(id)
780     }
781 
782     /// Returns the [`InstanceId`] previously pushed by `push_instance_id`
783     /// above.
784     ///
785     /// # Panics
786     ///
787     /// Panics if `idx` hasn't been initialized yet.
788     pub fn instance(&self, idx: RuntimeInstanceIndex) -> InstanceId {
789         self.instances[idx]
790     }
791 
792     fn instances_mut(self: Pin<&mut Self>) -> &mut PrimaryMap<RuntimeInstanceIndex, InstanceId> {
793         // SAFETY: we've chosen the `Pin` guarantee of `Self` to not apply to
794         // the map returned.
795         unsafe { &mut self.get_unchecked_mut().instances }
796     }
797 
798     /// Looks up the value used for `import` at runtime.
799     ///
800     /// # Panics
801     ///
802     /// Panics of `import` is out of bounds for this component.
803     pub(crate) fn runtime_import(&self, import: RuntimeImportIndex) -> &RuntimeImport {
804         &self.imports[import]
805     }
806 
807     /// Returns an `InstancePre<T>` which can be used to re-instantiated this
808     /// component if desired.
809     ///
810     /// # Safety
811     ///
812     /// This function places no bounds on `T` so it's up to the caller to match
813     /// that up appropriately with the store that this instance resides within.
814     pub unsafe fn instance_pre<T>(&self) -> InstancePre<T> {
815         // SAFETY: The `T` part of `new_unchecked` is forwarded as a contract of
816         // this function, and otherwise the validity of the components of the
817         // InstancePre should be guaranteed as it's what we were built with
818         // ourselves.
819         unsafe {
820             InstancePre::new_unchecked(
821                 self.component.clone(),
822                 self.imports.clone(),
823                 self.resource_types.clone(),
824             )
825         }
826     }
827 
828     /// Sets the cached argument for the canonical ABI option `post-return` to
829     /// the `arg` specified.
830     ///
831     /// This function is used in conjunction with function calls to record,
832     /// after a function call completes, the optional ABI return value. This
833     /// return value is cached within this instance for future use when the
834     /// `post_return` Rust-API-level function is invoked.
835     ///
836     /// Note that `index` here is the index of the export that was just
837     /// invoked, and this is used to ensure that `post_return` is called on the
838     /// same function afterwards. This restriction technically isn't necessary
839     /// though and may be one we want to lift in the future.
840     ///
841     /// # Panics
842     ///
843     /// This function will panic if `post_return_arg` is already set to `Some`.
844     pub fn post_return_arg_set(self: Pin<&mut Self>, index: ExportIndex, arg: ValRaw) {
845         assert!(self.post_return_arg.is_none());
846         *self.post_return_arg_mut() = Some((index, arg));
847     }
848 
849     /// Re-acquires the value originally saved via `post_return_arg_set`.
850     ///
851     /// This function will take a function `index` that's having its
852     /// `post_return` function called. If an argument was previously stored and
853     /// `index` matches the index that was stored then `Some(arg)` is returned.
854     /// Otherwise `None` is returned.
855     pub fn post_return_arg_take(self: Pin<&mut Self>, index: ExportIndex) -> Option<ValRaw> {
856         let post_return_arg = self.post_return_arg_mut();
857         let (expected_index, arg) = post_return_arg.take()?;
858         if index != expected_index {
859             *post_return_arg = Some((expected_index, arg));
860             None
861         } else {
862             Some(arg)
863         }
864     }
865 
866     fn post_return_arg_mut(self: Pin<&mut Self>) -> &mut Option<(ExportIndex, ValRaw)> {
867         // SAFETY: we've chosen the `Pin` guarantee of `Self` to not apply to
868         // the map returned.
869         unsafe { &mut self.get_unchecked_mut().post_return_arg }
870     }
871 
872     #[cfg(feature = "component-model-async")]
873     pub(crate) fn concurrent_state_mut(self: Pin<&mut Self>) -> &mut concurrent::ConcurrentState {
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().concurrent_state }
877     }
878 }
879 
880 // SAFETY: `layout` should describe this accurately and `OwnedVMContext` is the
881 // last field of `ComponentInstance`.
882 unsafe impl InstanceLayout for ComponentInstance {
883     /// Technically it is not required to `alloc_zeroed` here. The primary
884     /// reason for doing this is because a component context start is a "partly
885     /// initialized" state where pointers and such are configured as the
886     /// instantiation process continues. The component model should guarantee
887     /// that we never access uninitialized memory in the context, but to help
888     /// protect against possible bugs a zeroed allocation is done here to try to
889     /// contain use-before-initialized issues.
890     const INIT_ZEROED: bool = true;
891 
892     type VMContext = VMComponentContext;
893 
894     fn layout(&self) -> Layout {
895         ComponentInstance::alloc_layout(&self.offsets)
896     }
897 
898     fn owned_vmctx(&self) -> &OwnedVMContext<VMComponentContext> {
899         &self.vmctx
900     }
901 
902     fn owned_vmctx_mut(&mut self) -> &mut OwnedVMContext<VMComponentContext> {
903         &mut self.vmctx
904     }
905 }
906 
907 pub type OwnedComponentInstance = OwnedInstance<ComponentInstance>;
908 
909 impl VMComponentContext {
910     /// Moves the `self` pointer backwards to the `ComponentInstance` pointer
911     /// that this `VMComponentContext` trails.
912     pub fn instance(&self) -> *mut ComponentInstance {
913         unsafe {
914             (self as *const Self as *mut u8)
915                 .offset(-(offset_of!(ComponentInstance, vmctx) as isize))
916                 as *mut ComponentInstance
917         }
918     }
919 
920     /// Helper function to cast between context types using a debug assertion to
921     /// protect against some mistakes.
922     ///
923     /// # Safety
924     ///
925     /// The `opaque` value must be a valid pointer where it's safe to read its
926     /// "magic" value.
927     #[inline]
928     pub unsafe fn from_opaque(opaque: NonNull<VMOpaqueContext>) -> NonNull<VMComponentContext> {
929         // See comments in `VMContext::from_opaque` for this debug assert
930         //
931         // SAFETY: it's a contract of this function that it's safe to read
932         // `opaque`.
933         unsafe {
934             debug_assert_eq!(opaque.as_ref().magic, VMCOMPONENT_MAGIC);
935         }
936         opaque.cast()
937     }
938 }
939 
940 impl VMOpaqueContext {
941     /// Helper function to clearly indicate the cast desired
942     #[inline]
943     pub fn from_vmcomponent(ptr: NonNull<VMComponentContext>) -> NonNull<VMOpaqueContext> {
944         ptr.cast()
945     }
946 }
947 
948 #[repr(transparent)]
949 #[derive(Copy, Clone)]
950 pub struct InstanceFlags(SendSyncPtr<VMGlobalDefinition>);
951 
952 impl InstanceFlags {
953     /// Wraps the given pointer as an `InstanceFlags`
954     ///
955     /// # Unsafety
956     ///
957     /// This is a raw pointer argument which needs to be valid for the lifetime
958     /// that `InstanceFlags` is used.
959     pub unsafe fn from_raw(ptr: NonNull<VMGlobalDefinition>) -> InstanceFlags {
960         InstanceFlags(SendSyncPtr::from(ptr))
961     }
962 
963     #[inline]
964     pub unsafe fn may_leave(&self) -> bool {
965         unsafe { *self.as_raw().as_ref().as_i32() & FLAG_MAY_LEAVE != 0 }
966     }
967 
968     #[inline]
969     pub unsafe fn set_may_leave(&mut self, val: bool) {
970         unsafe {
971             if val {
972                 *self.as_raw().as_mut().as_i32_mut() |= FLAG_MAY_LEAVE;
973             } else {
974                 *self.as_raw().as_mut().as_i32_mut() &= !FLAG_MAY_LEAVE;
975             }
976         }
977     }
978 
979     #[inline]
980     pub unsafe fn may_enter(&self) -> bool {
981         unsafe { *self.as_raw().as_ref().as_i32() & FLAG_MAY_ENTER != 0 }
982     }
983 
984     #[inline]
985     pub unsafe fn set_may_enter(&mut self, val: bool) {
986         unsafe {
987             if val {
988                 *self.as_raw().as_mut().as_i32_mut() |= FLAG_MAY_ENTER;
989             } else {
990                 *self.as_raw().as_mut().as_i32_mut() &= !FLAG_MAY_ENTER;
991             }
992         }
993     }
994 
995     #[inline]
996     pub unsafe fn needs_post_return(&self) -> bool {
997         unsafe { *self.as_raw().as_ref().as_i32() & FLAG_NEEDS_POST_RETURN != 0 }
998     }
999 
1000     #[inline]
1001     pub unsafe fn set_needs_post_return(&mut self, val: bool) {
1002         unsafe {
1003             if val {
1004                 *self.as_raw().as_mut().as_i32_mut() |= FLAG_NEEDS_POST_RETURN;
1005             } else {
1006                 *self.as_raw().as_mut().as_i32_mut() &= !FLAG_NEEDS_POST_RETURN;
1007             }
1008         }
1009     }
1010 
1011     #[inline]
1012     pub fn as_raw(&self) -> NonNull<VMGlobalDefinition> {
1013         self.0.as_non_null()
1014     }
1015 }
1016