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