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