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 #[cfg(feature = "component-model-async")] 46 use crate::component::concurrent; 47 48 /// Runtime representation of a component instance and all state necessary for 49 /// the instance itself. 50 /// 51 /// This type never exists by-value, but rather it's always behind a pointer. 52 /// The size of the allocation for `ComponentInstance` includes the trailing 53 /// `VMComponentContext` which is variably sized based on the `offsets` 54 /// contained within. 55 /// 56 /// # Pin 57 /// 58 /// Note that this type is mutated through `Pin<&mut ComponentInstance>` in the 59 /// same manner as `vm::Instance` for core modules, and see more information 60 /// over there for documentation and rationale. 61 #[repr(C)] 62 pub struct ComponentInstance { 63 /// The index within the store of where to find this component instance. 64 id: ComponentInstanceId, 65 66 /// Size and offset information for the trailing `VMComponentContext`. 67 offsets: VMComponentOffsets<HostPtr>, 68 69 /// The component that this instance was created from. 70 // 71 // NB: in the future if necessary it would be possible to avoid storing an 72 // entire `Component` here and instead storing only information such as: 73 // 74 // * Some reference to `Arc<ComponentTypes>` 75 // * Necessary references to closed-over modules which are exported from the 76 // component itself. 77 // 78 // Otherwise the full guts of this component should only ever be used during 79 // the instantiation of this instance, meaning that after instantiation much 80 // of the component can be thrown away (theoretically). 81 component: Component, 82 83 /// State of handles (e.g. resources, waitables, etc.) for this component. 84 /// 85 /// For resource handles, this is paired with other information to create a 86 /// `ResourceTables` and manipulated through that. For other handles, this 87 /// is used directly to translate guest handles to host representations and 88 /// vice-versa. 89 instance_handle_tables: PrimaryMap<RuntimeComponentInstanceIndex, HandleTable>, 90 91 /// State related to async for this component, e.g. futures, streams, tasks, 92 /// etc. 93 #[cfg(feature = "component-model-async")] 94 concurrent_state: concurrent::ConcurrentState, 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 { 227 vmctx 228 .byte_sub(mem::size_of::<ComponentInstance>()) 229 .cast::<ComponentInstance>() 230 }; 231 // SAFETY: it's a contract of this function that it's safe to use `ptr` 232 // as a mutable reference. 233 let reference = unsafe { ptr.as_mut() }; 234 235 // SAFETY: it's a contract of this function that it's safe to use the 236 // store mutably at this time. 237 let store = unsafe { &mut *reference.store.0.as_ptr() }; 238 239 let instance = Instance::from_wasmtime(store, reference.id); 240 catch_unwind_and_record_trap(store, |store| f(store, instance)) 241 } 242 243 /// Returns the `InstanceId` associated with the `vmctx` provided. 244 /// 245 /// # Safety 246 /// 247 /// The `vmctx` pointer must be a valid pointer to read the 248 /// `ComponentInstanceId` from. 249 pub(crate) unsafe fn vmctx_instance_id( 250 vmctx: NonNull<VMComponentContext>, 251 ) -> ComponentInstanceId { 252 // SAFETY: it's a contract of this function that `vmctx` is a valid 253 // pointer with a `ComponentInstance` in front which can be read. 254 unsafe { 255 vmctx 256 .byte_sub(mem::size_of::<ComponentInstance>()) 257 .cast::<ComponentInstance>() 258 .as_ref() 259 .id 260 } 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 #[cfg(feature = "component-model-async")] 310 concurrent_state: concurrent::ConcurrentState::new(component), 311 vmctx: OwnedVMContext::new(), 312 }); 313 unsafe { 314 ret.get_mut().initialize_vmctx(); 315 } 316 ret 317 } 318 319 #[inline] 320 pub fn vmctx(&self) -> NonNull<VMComponentContext> { 321 InstanceLayout::vmctx(self) 322 } 323 324 /// Returns a pointer to the "may leave" flag for this instance specified 325 /// for canonical lowering and lifting operations. 326 #[inline] 327 pub fn instance_flags(&self, instance: RuntimeComponentInstanceIndex) -> InstanceFlags { 328 unsafe { 329 let ptr = self 330 .vmctx_plus_offset_raw::<VMGlobalDefinition>(self.offsets.instance_flags(instance)); 331 InstanceFlags(SendSyncPtr::new(ptr)) 332 } 333 } 334 335 /// Returns the runtime memory definition corresponding to the index of the 336 /// memory provided. 337 /// 338 /// This can only be called after `idx` has been initialized at runtime 339 /// during the instantiation process of a component. 340 pub fn runtime_memory(&self, idx: RuntimeMemoryIndex) -> *mut VMMemoryDefinition { 341 unsafe { 342 let ret = *self.vmctx_plus_offset::<VmPtr<_>>(self.offsets.runtime_memory(idx)); 343 debug_assert!(ret.as_ptr() as usize != INVALID_PTR); 344 ret.as_ptr() 345 } 346 } 347 348 /// Returns the runtime table definition and associated instance `VMContext` 349 /// corresponding to the index of the table provided. 350 /// 351 /// This can only be called after `idx` has been initialized at runtime 352 /// during the instantiation process of a component. 353 pub fn runtime_table(&self, idx: RuntimeTableIndex) -> VMTableImport { 354 unsafe { 355 let ret = *self.vmctx_plus_offset::<VMTableImport>(self.offsets.runtime_table(idx)); 356 debug_assert!(ret.from.as_ptr() as usize != INVALID_PTR); 357 debug_assert!(ret.vmctx.as_ptr() as usize != INVALID_PTR); 358 ret 359 } 360 } 361 362 /// Returns the realloc pointer corresponding to the index provided. 363 /// 364 /// This can only be called after `idx` has been initialized at runtime 365 /// during the instantiation process of a component. 366 pub fn runtime_realloc(&self, idx: RuntimeReallocIndex) -> NonNull<VMFuncRef> { 367 unsafe { 368 let ret = *self.vmctx_plus_offset::<VmPtr<_>>(self.offsets.runtime_realloc(idx)); 369 debug_assert!(ret.as_ptr() as usize != INVALID_PTR); 370 ret.as_non_null() 371 } 372 } 373 374 /// Returns the async callback pointer corresponding to the index 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_callback(&self, idx: RuntimeCallbackIndex) -> NonNull<VMFuncRef> { 379 unsafe { 380 let ret = *self.vmctx_plus_offset::<VmPtr<_>>(self.offsets.runtime_callback(idx)); 381 debug_assert!(ret.as_ptr() as usize != INVALID_PTR); 382 ret.as_non_null() 383 } 384 } 385 386 /// Returns the post-return pointer corresponding to the index provided. 387 /// 388 /// This can only be called after `idx` has been initialized at runtime 389 /// during the instantiation process of a component. 390 pub fn runtime_post_return(&self, idx: RuntimePostReturnIndex) -> NonNull<VMFuncRef> { 391 unsafe { 392 let ret = *self.vmctx_plus_offset::<VmPtr<_>>(self.offsets.runtime_post_return(idx)); 393 debug_assert!(ret.as_ptr() as usize != INVALID_PTR); 394 ret.as_non_null() 395 } 396 } 397 398 /// Returns the host information for the lowered function at the index 399 /// specified. 400 /// 401 /// This can only be called after `idx` has been initialized at runtime 402 /// during the instantiation process of a component. 403 pub fn lowering(&self, idx: LoweredIndex) -> VMLowering { 404 unsafe { 405 let ret = *self.vmctx_plus_offset::<VMLowering>(self.offsets.lowering(idx)); 406 debug_assert!(ret.callee.as_ptr() as usize != INVALID_PTR); 407 debug_assert!(ret.data.as_ptr() as usize != INVALID_PTR); 408 ret 409 } 410 } 411 412 /// Returns the core wasm `funcref` corresponding to the trampoline 413 /// specified. 414 /// 415 /// The returned function is suitable to pass directly to a wasm module 416 /// instantiation and the function contains cranelift-compiled trampolines. 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 trampoline_func_ref(&self, idx: TrampolineIndex) -> NonNull<VMFuncRef> { 421 unsafe { 422 let offset = self.offsets.trampoline_func_ref(idx); 423 let ret = self.vmctx_plus_offset_raw::<VMFuncRef>(offset); 424 debug_assert!( 425 mem::transmute::<Option<VmPtr<VMWasmCallFunction>>, usize>(ret.as_ref().wasm_call) 426 != INVALID_PTR 427 ); 428 debug_assert!(ret.as_ref().vmctx.as_ptr() as usize != INVALID_PTR); 429 ret 430 } 431 } 432 433 /// Stores the runtime memory pointer at the index specified. 434 /// 435 /// This is intended to be called during the instantiation process of a 436 /// component once a memory is available, which may not be until part-way 437 /// through component instantiation. 438 /// 439 /// Note that it should be a property of the component model that the `ptr` 440 /// here is never needed prior to it being configured here in the instance. 441 pub fn set_runtime_memory( 442 self: Pin<&mut Self>, 443 idx: RuntimeMemoryIndex, 444 ptr: NonNull<VMMemoryDefinition>, 445 ) { 446 unsafe { 447 let offset = self.offsets.runtime_memory(idx); 448 let storage = self.vmctx_plus_offset_mut::<VmPtr<VMMemoryDefinition>>(offset); 449 debug_assert!((*storage).as_ptr() as usize == INVALID_PTR); 450 *storage = ptr.into(); 451 } 452 } 453 454 /// Same as `set_runtime_memory` but for realloc function pointers. 455 pub fn set_runtime_realloc( 456 self: Pin<&mut Self>, 457 idx: RuntimeReallocIndex, 458 ptr: NonNull<VMFuncRef>, 459 ) { 460 unsafe { 461 let offset = self.offsets.runtime_realloc(idx); 462 let storage = self.vmctx_plus_offset_mut::<VmPtr<VMFuncRef>>(offset); 463 debug_assert!((*storage).as_ptr() as usize == INVALID_PTR); 464 *storage = ptr.into(); 465 } 466 } 467 468 /// Same as `set_runtime_memory` but for async callback function pointers. 469 pub fn set_runtime_callback( 470 self: Pin<&mut Self>, 471 idx: RuntimeCallbackIndex, 472 ptr: NonNull<VMFuncRef>, 473 ) { 474 unsafe { 475 let offset = self.offsets.runtime_callback(idx); 476 let storage = self.vmctx_plus_offset_mut::<VmPtr<VMFuncRef>>(offset); 477 debug_assert!((*storage).as_ptr() as usize == INVALID_PTR); 478 *storage = ptr.into(); 479 } 480 } 481 482 /// Same as `set_runtime_memory` but for post-return function pointers. 483 pub fn set_runtime_post_return( 484 self: Pin<&mut Self>, 485 idx: RuntimePostReturnIndex, 486 ptr: NonNull<VMFuncRef>, 487 ) { 488 unsafe { 489 let offset = self.offsets.runtime_post_return(idx); 490 let storage = self.vmctx_plus_offset_mut::<VmPtr<VMFuncRef>>(offset); 491 debug_assert!((*storage).as_ptr() as usize == INVALID_PTR); 492 *storage = ptr.into(); 493 } 494 } 495 496 /// Stores the runtime table pointer at the index specified. 497 /// 498 /// This is intended to be called during the instantiation process of a 499 /// component once a table is available, which may not be until part-way 500 /// through component instantiation. 501 /// 502 /// Note that it should be a property of the component model that the `ptr` 503 /// here is never needed prior to it being configured here in the instance. 504 pub fn set_runtime_table(self: Pin<&mut Self>, idx: RuntimeTableIndex, import: VMTableImport) { 505 unsafe { 506 let offset = self.offsets.runtime_table(idx); 507 let storage = self.vmctx_plus_offset_mut::<VMTableImport>(offset); 508 debug_assert!((*storage).vmctx.as_ptr() as usize == INVALID_PTR); 509 debug_assert!((*storage).from.as_ptr() as usize == INVALID_PTR); 510 *storage = import; 511 } 512 } 513 514 /// Configures host runtime lowering information associated with imported f 515 /// functions for the `idx` specified. 516 pub fn set_lowering(self: Pin<&mut Self>, idx: LoweredIndex, lowering: VMLowering) { 517 unsafe { 518 let callee = self.offsets.lowering_callee(idx); 519 debug_assert!(*self.vmctx_plus_offset::<usize>(callee) == INVALID_PTR); 520 let data = self.offsets.lowering_data(idx); 521 debug_assert!(*self.vmctx_plus_offset::<usize>(data) == INVALID_PTR); 522 let offset = self.offsets.lowering(idx); 523 *self.vmctx_plus_offset_mut(offset) = lowering; 524 } 525 } 526 527 /// Same as `set_lowering` but for the resource.drop functions. 528 pub fn set_trampoline( 529 self: Pin<&mut Self>, 530 idx: TrampolineIndex, 531 wasm_call: NonNull<VMWasmCallFunction>, 532 array_call: NonNull<VMArrayCallFunction>, 533 type_index: VMSharedTypeIndex, 534 ) { 535 unsafe { 536 let offset = self.offsets.trampoline_func_ref(idx); 537 debug_assert!(*self.vmctx_plus_offset::<usize>(offset) == INVALID_PTR); 538 let vmctx = VMOpaqueContext::from_vmcomponent(self.vmctx()); 539 *self.vmctx_plus_offset_mut(offset) = VMFuncRef { 540 wasm_call: Some(wasm_call.into()), 541 array_call: array_call.into(), 542 type_index, 543 vmctx: vmctx.into(), 544 }; 545 } 546 } 547 548 /// Configures the destructor for a resource at the `idx` specified. 549 /// 550 /// This is required to be called for each resource as it's defined within a 551 /// component during the instantiation process. 552 pub fn set_resource_destructor( 553 self: Pin<&mut Self>, 554 idx: ResourceIndex, 555 dtor: Option<NonNull<VMFuncRef>>, 556 ) { 557 unsafe { 558 let offset = self.offsets.resource_destructor(idx); 559 debug_assert!(*self.vmctx_plus_offset::<usize>(offset) == INVALID_PTR); 560 *self.vmctx_plus_offset_mut(offset) = dtor.map(VmPtr::from); 561 } 562 } 563 564 /// Returns the destructor, if any, for `idx`. 565 /// 566 /// This is only valid to call after `set_resource_destructor`, or typically 567 /// after instantiation. 568 pub fn resource_destructor(&self, idx: ResourceIndex) -> Option<NonNull<VMFuncRef>> { 569 unsafe { 570 let offset = self.offsets.resource_destructor(idx); 571 debug_assert!(*self.vmctx_plus_offset::<usize>(offset) != INVALID_PTR); 572 (*self.vmctx_plus_offset::<Option<VmPtr<VMFuncRef>>>(offset)).map(|p| p.as_non_null()) 573 } 574 } 575 576 unsafe fn initialize_vmctx(mut self: Pin<&mut Self>) { 577 let offset = self.offsets.magic(); 578 // SAFETY: it's safe to write the magic value during initialization and 579 // this is also the right type of value to write. 580 unsafe { 581 *self.as_mut().vmctx_plus_offset_mut(offset) = VMCOMPONENT_MAGIC; 582 } 583 584 // Initialize the built-in functions 585 // 586 // SAFETY: it's safe to initialize the vmctx in this function and this 587 // is also the right type of value to store in the vmctx. 588 static BUILTINS: libcalls::VMComponentBuiltins = libcalls::VMComponentBuiltins::INIT; 589 let ptr = BUILTINS.expose_provenance(); 590 let offset = self.offsets.builtins(); 591 unsafe { 592 *self.as_mut().vmctx_plus_offset_mut(offset) = VmPtr::from(ptr); 593 } 594 595 // SAFETY: it's safe to initialize the vmctx in this function and this 596 // is also the right type of value to store in the vmctx. 597 let offset = self.offsets.vm_store_context(); 598 unsafe { 599 *self.as_mut().vmctx_plus_offset_mut(offset) = 600 VmPtr::from(self.store.0.as_ref().vm_store_context_ptr()); 601 } 602 603 for i in 0..self.offsets.num_runtime_component_instances { 604 let i = RuntimeComponentInstanceIndex::from_u32(i); 605 let mut def = VMGlobalDefinition::new(); 606 // SAFETY: this is a valid initialization of all globals which are 607 // 32-bit values. 608 unsafe { 609 *def.as_i32_mut() = FLAG_MAY_ENTER | FLAG_MAY_LEAVE; 610 self.instance_flags(i).as_raw().write(def); 611 } 612 } 613 614 // In debug mode set non-null bad values to all "pointer looking" bits 615 // and pieces related to lowering and such. This'll help detect any 616 // erroneous usage and enable debug assertions above as well to prevent 617 // loading these before they're configured or setting them twice. 618 // 619 // SAFETY: it's valid to write a garbage pointer during initialization 620 // when this is otherwise uninitialized memory 621 if cfg!(debug_assertions) { 622 for i in 0..self.offsets.num_lowerings { 623 let i = LoweredIndex::from_u32(i); 624 let offset = self.offsets.lowering_callee(i); 625 // SAFETY: see above 626 unsafe { 627 *self.as_mut().vmctx_plus_offset_mut(offset) = INVALID_PTR; 628 } 629 let offset = self.offsets.lowering_data(i); 630 // SAFETY: see above 631 unsafe { 632 *self.as_mut().vmctx_plus_offset_mut(offset) = INVALID_PTR; 633 } 634 } 635 for i in 0..self.offsets.num_trampolines { 636 let i = TrampolineIndex::from_u32(i); 637 let offset = self.offsets.trampoline_func_ref(i); 638 // SAFETY: see above 639 unsafe { 640 *self.as_mut().vmctx_plus_offset_mut(offset) = INVALID_PTR; 641 } 642 } 643 for i in 0..self.offsets.num_runtime_memories { 644 let i = RuntimeMemoryIndex::from_u32(i); 645 let offset = self.offsets.runtime_memory(i); 646 // SAFETY: see above 647 unsafe { 648 *self.as_mut().vmctx_plus_offset_mut(offset) = INVALID_PTR; 649 } 650 } 651 for i in 0..self.offsets.num_runtime_reallocs { 652 let i = RuntimeReallocIndex::from_u32(i); 653 let offset = self.offsets.runtime_realloc(i); 654 // SAFETY: see above 655 unsafe { 656 *self.as_mut().vmctx_plus_offset_mut(offset) = INVALID_PTR; 657 } 658 } 659 for i in 0..self.offsets.num_runtime_callbacks { 660 let i = RuntimeCallbackIndex::from_u32(i); 661 let offset = self.offsets.runtime_callback(i); 662 // SAFETY: see above 663 unsafe { 664 *self.as_mut().vmctx_plus_offset_mut(offset) = INVALID_PTR; 665 } 666 } 667 for i in 0..self.offsets.num_runtime_post_returns { 668 let i = RuntimePostReturnIndex::from_u32(i); 669 let offset = self.offsets.runtime_post_return(i); 670 // SAFETY: see above 671 unsafe { 672 *self.as_mut().vmctx_plus_offset_mut(offset) = INVALID_PTR; 673 } 674 } 675 for i in 0..self.offsets.num_resources { 676 let i = ResourceIndex::from_u32(i); 677 let offset = self.offsets.resource_destructor(i); 678 // SAFETY: see above 679 unsafe { 680 *self.as_mut().vmctx_plus_offset_mut(offset) = INVALID_PTR; 681 } 682 } 683 for i in 0..self.offsets.num_runtime_tables { 684 let i = RuntimeTableIndex::from_u32(i); 685 let offset = self.offsets.runtime_table(i); 686 // SAFETY: see above 687 unsafe { 688 *self.as_mut().vmctx_plus_offset_mut(offset) = INVALID_PTR; 689 } 690 } 691 } 692 } 693 694 /// Returns a reference to the component type information for this 695 /// instance. 696 pub fn component(&self) -> &Component { 697 &self.component 698 } 699 700 /// Same as [`Self::component`] but additionally returns the 701 /// `Pin<&mut Self>` with the same original lifetime. 702 pub fn component_and_self(self: Pin<&mut Self>) -> (&Component, Pin<&mut Self>) { 703 // SAFETY: this function is projecting both `&Component` and the same 704 // pointer both connected to the same lifetime. This is safe because 705 // it's a contract of `Pin<&mut Self>` that the `Component` field is 706 // never written, meaning it's effectively unsafe to have `&mut 707 // Component` projected from `Pin<&mut Self>`. Consequently it's safe to 708 // have a read-only view of the field while still retaining mutable 709 // access to all other fields. 710 let component = unsafe { &*(&raw const self.component) }; 711 (component, self) 712 } 713 714 /// Returns a reference to the resource type information. 715 pub fn resource_types(&self) -> &Arc<PrimaryMap<ResourceIndex, ResourceType>> { 716 &self.resource_types 717 } 718 719 /// Returns a mutable reference to the resource type information. 720 pub fn resource_types_mut( 721 self: Pin<&mut Self>, 722 ) -> &mut Arc<PrimaryMap<ResourceIndex, ResourceType>> { 723 // SAFETY: we've chosen the `Pin` guarantee of `Self` to not apply to 724 // the map returned. 725 unsafe { &mut self.get_unchecked_mut().resource_types } 726 } 727 728 /// Returns whether the resource that `ty` points to is owned by the 729 /// instance that `ty` correspond to. 730 /// 731 /// This is used when lowering borrows to skip table management and instead 732 /// thread through the underlying representation directly. 733 pub fn resource_owned_by_own_instance(&self, ty: TypeResourceTableIndex) -> bool { 734 let resource = &self.component.types()[ty]; 735 let component = self.component.env_component(); 736 let idx = match component.defined_resource_index(resource.ty) { 737 Some(idx) => idx, 738 None => return false, 739 }; 740 resource.instance == component.defined_resource_instances[idx] 741 } 742 743 /// Returns the runtime state of resources associated with this component. 744 #[inline] 745 pub fn guest_tables( 746 self: Pin<&mut Self>, 747 ) -> ( 748 &mut PrimaryMap<RuntimeComponentInstanceIndex, HandleTable>, 749 &ComponentTypes, 750 ) { 751 // safety: we've chosen the `pin` guarantee of `self` to not apply to 752 // the map returned. 753 unsafe { 754 let me = self.get_unchecked_mut(); 755 (&mut me.instance_handle_tables, me.component.types()) 756 } 757 } 758 759 /// Returns the destructor and instance flags for the specified resource 760 /// table type. 761 /// 762 /// This will lookup the origin definition of the `ty` table and return the 763 /// destructor/flags for that. 764 pub fn dtor_and_flags( 765 &self, 766 ty: TypeResourceTableIndex, 767 ) -> (Option<NonNull<VMFuncRef>>, Option<InstanceFlags>) { 768 let resource = self.component.types()[ty].ty; 769 let dtor = self.resource_destructor(resource); 770 let component = self.component.env_component(); 771 let flags = component.defined_resource_index(resource).map(|i| { 772 let instance = component.defined_resource_instances[i]; 773 self.instance_flags(instance) 774 }); 775 (dtor, flags) 776 } 777 778 /// Returns the store-local id that points to this component. 779 pub fn id(&self) -> ComponentInstanceId { 780 self.id 781 } 782 783 /// Pushes a new runtime instance that's been created into 784 /// `self.instances`. 785 pub fn push_instance_id(self: Pin<&mut Self>, id: InstanceId) -> RuntimeInstanceIndex { 786 self.instances_mut().push(id) 787 } 788 789 /// Returns the [`InstanceId`] previously pushed by `push_instance_id` 790 /// above. 791 /// 792 /// # Panics 793 /// 794 /// Panics if `idx` hasn't been initialized yet. 795 pub fn instance(&self, idx: RuntimeInstanceIndex) -> InstanceId { 796 self.instances[idx] 797 } 798 799 fn instances_mut(self: Pin<&mut Self>) -> &mut PrimaryMap<RuntimeInstanceIndex, InstanceId> { 800 // SAFETY: we've chosen the `Pin` guarantee of `Self` to not apply to 801 // the map returned. 802 unsafe { &mut self.get_unchecked_mut().instances } 803 } 804 805 /// Looks up the value used for `import` at runtime. 806 /// 807 /// # Panics 808 /// 809 /// Panics of `import` is out of bounds for this component. 810 pub(crate) fn runtime_import(&self, import: RuntimeImportIndex) -> &RuntimeImport { 811 &self.imports[import] 812 } 813 814 /// Returns an `InstancePre<T>` which can be used to re-instantiated this 815 /// component if desired. 816 /// 817 /// # Safety 818 /// 819 /// This function places no bounds on `T` so it's up to the caller to match 820 /// that up appropriately with the store that this instance resides within. 821 pub unsafe fn instance_pre<T>(&self) -> InstancePre<T> { 822 // SAFETY: The `T` part of `new_unchecked` is forwarded as a contract of 823 // this function, and otherwise the validity of the components of the 824 // InstancePre should be guaranteed as it's what we were built with 825 // ourselves. 826 unsafe { 827 InstancePre::new_unchecked( 828 self.component.clone(), 829 self.imports.clone(), 830 self.resource_types.clone(), 831 ) 832 } 833 } 834 835 /// Sets the cached argument for the canonical ABI option `post-return` to 836 /// the `arg` specified. 837 /// 838 /// This function is used in conjunction with function calls to record, 839 /// after a function call completes, the optional ABI return value. This 840 /// return value is cached within this instance for future use when the 841 /// `post_return` Rust-API-level function is invoked. 842 /// 843 /// Note that `index` here is the index of the export that was just 844 /// invoked, and this is used to ensure that `post_return` is called on the 845 /// same function afterwards. This restriction technically isn't necessary 846 /// though and may be one we want to lift in the future. 847 /// 848 /// # Panics 849 /// 850 /// This function will panic if `post_return_arg` is already set to `Some`. 851 pub fn post_return_arg_set(self: Pin<&mut Self>, index: ExportIndex, arg: ValRaw) { 852 assert!(self.post_return_arg.is_none()); 853 *self.post_return_arg_mut() = Some((index, arg)); 854 } 855 856 /// Re-acquires the value originally saved via `post_return_arg_set`. 857 /// 858 /// This function will take a function `index` that's having its 859 /// `post_return` function called. If an argument was previously stored and 860 /// `index` matches the index that was stored then `Some(arg)` is returned. 861 /// Otherwise `None` is returned. 862 pub fn post_return_arg_take(self: Pin<&mut Self>, index: ExportIndex) -> Option<ValRaw> { 863 let post_return_arg = self.post_return_arg_mut(); 864 let (expected_index, arg) = post_return_arg.take()?; 865 if index != expected_index { 866 *post_return_arg = Some((expected_index, arg)); 867 None 868 } else { 869 Some(arg) 870 } 871 } 872 873 fn post_return_arg_mut(self: Pin<&mut Self>) -> &mut Option<(ExportIndex, ValRaw)> { 874 // SAFETY: we've chosen the `Pin` guarantee of `Self` to not apply to 875 // the map returned. 876 unsafe { &mut self.get_unchecked_mut().post_return_arg } 877 } 878 879 #[cfg(feature = "component-model-async")] 880 pub(crate) fn concurrent_state_mut(self: Pin<&mut Self>) -> &mut concurrent::ConcurrentState { 881 // SAFETY: we've chosen the `Pin` guarantee of `Self` to not apply to 882 // the map returned. 883 unsafe { &mut self.get_unchecked_mut().concurrent_state } 884 } 885 } 886 887 // SAFETY: `layout` should describe this accurately and `OwnedVMContext` is the 888 // last field of `ComponentInstance`. 889 unsafe impl InstanceLayout for ComponentInstance { 890 /// Technically it is not required to `alloc_zeroed` here. The primary 891 /// reason for doing this is because a component context start is a "partly 892 /// initialized" state where pointers and such are configured as the 893 /// instantiation process continues. The component model should guarantee 894 /// that we never access uninitialized memory in the context, but to help 895 /// protect against possible bugs a zeroed allocation is done here to try to 896 /// contain use-before-initialized issues. 897 const INIT_ZEROED: bool = true; 898 899 type VMContext = VMComponentContext; 900 901 fn layout(&self) -> Layout { 902 ComponentInstance::alloc_layout(&self.offsets) 903 } 904 905 fn owned_vmctx(&self) -> &OwnedVMContext<VMComponentContext> { 906 &self.vmctx 907 } 908 909 fn owned_vmctx_mut(&mut self) -> &mut OwnedVMContext<VMComponentContext> { 910 &mut self.vmctx 911 } 912 } 913 914 pub type OwnedComponentInstance = OwnedInstance<ComponentInstance>; 915 916 impl VMComponentContext { 917 /// Moves the `self` pointer backwards to the `ComponentInstance` pointer 918 /// that this `VMComponentContext` trails. 919 pub fn instance(&self) -> *mut ComponentInstance { 920 unsafe { 921 (self as *const Self as *mut u8) 922 .offset(-(offset_of!(ComponentInstance, vmctx) as isize)) 923 as *mut ComponentInstance 924 } 925 } 926 927 /// Helper function to cast between context types using a debug assertion to 928 /// protect against some mistakes. 929 /// 930 /// # Safety 931 /// 932 /// The `opaque` value must be a valid pointer where it's safe to read its 933 /// "magic" value. 934 #[inline] 935 pub unsafe fn from_opaque(opaque: NonNull<VMOpaqueContext>) -> NonNull<VMComponentContext> { 936 // See comments in `VMContext::from_opaque` for this debug assert 937 // 938 // SAFETY: it's a contract of this function that it's safe to read 939 // `opaque`. 940 unsafe { 941 debug_assert_eq!(opaque.as_ref().magic, VMCOMPONENT_MAGIC); 942 } 943 opaque.cast() 944 } 945 } 946 947 impl VMOpaqueContext { 948 /// Helper function to clearly indicate the cast desired 949 #[inline] 950 pub fn from_vmcomponent(ptr: NonNull<VMComponentContext>) -> NonNull<VMOpaqueContext> { 951 ptr.cast() 952 } 953 } 954 955 #[repr(transparent)] 956 #[derive(Copy, Clone)] 957 pub struct InstanceFlags(SendSyncPtr<VMGlobalDefinition>); 958 959 impl InstanceFlags { 960 /// Wraps the given pointer as an `InstanceFlags` 961 /// 962 /// # Unsafety 963 /// 964 /// This is a raw pointer argument which needs to be valid for the lifetime 965 /// that `InstanceFlags` is used. 966 pub unsafe fn from_raw(ptr: NonNull<VMGlobalDefinition>) -> InstanceFlags { 967 InstanceFlags(SendSyncPtr::from(ptr)) 968 } 969 970 #[inline] 971 pub unsafe fn may_leave(&self) -> bool { 972 unsafe { *self.as_raw().as_ref().as_i32() & FLAG_MAY_LEAVE != 0 } 973 } 974 975 #[inline] 976 pub unsafe fn set_may_leave(&mut self, val: bool) { 977 unsafe { 978 if val { 979 *self.as_raw().as_mut().as_i32_mut() |= FLAG_MAY_LEAVE; 980 } else { 981 *self.as_raw().as_mut().as_i32_mut() &= !FLAG_MAY_LEAVE; 982 } 983 } 984 } 985 986 #[inline] 987 pub unsafe fn may_enter(&self) -> bool { 988 unsafe { *self.as_raw().as_ref().as_i32() & FLAG_MAY_ENTER != 0 } 989 } 990 991 #[inline] 992 pub unsafe fn set_may_enter(&mut self, val: bool) { 993 unsafe { 994 if val { 995 *self.as_raw().as_mut().as_i32_mut() |= FLAG_MAY_ENTER; 996 } else { 997 *self.as_raw().as_mut().as_i32_mut() &= !FLAG_MAY_ENTER; 998 } 999 } 1000 } 1001 1002 #[inline] 1003 pub unsafe fn needs_post_return(&self) -> bool { 1004 unsafe { *self.as_raw().as_ref().as_i32() & FLAG_NEEDS_POST_RETURN != 0 } 1005 } 1006 1007 #[inline] 1008 pub unsafe fn set_needs_post_return(&mut self, val: bool) { 1009 unsafe { 1010 if val { 1011 *self.as_raw().as_mut().as_i32_mut() |= FLAG_NEEDS_POST_RETURN; 1012 } else { 1013 *self.as_raw().as_mut().as_i32_mut() &= !FLAG_NEEDS_POST_RETURN; 1014 } 1015 } 1016 } 1017 1018 #[inline] 1019 pub fn as_raw(&self) -> NonNull<VMGlobalDefinition> { 1020 self.0.as_non_null() 1021 } 1022 } 1023