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