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