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