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