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