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