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