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::prelude::*; 10 use crate::runtime::vm::{ 11 SendSyncPtr, Store, VMArrayCallFunction, VMFuncRef, VMGlobalDefinition, VMMemoryDefinition, 12 VMOpaqueContext, VMWasmCallFunction, ValRaw, 13 }; 14 use alloc::alloc::Layout; 15 use alloc::sync::Arc; 16 use core::any::Any; 17 use core::marker; 18 use core::mem; 19 use core::mem::offset_of; 20 use core::ops::Deref; 21 use core::ptr::{self, NonNull}; 22 use sptr::Strict; 23 use wasmtime_environ::component::*; 24 use wasmtime_environ::{HostPtr, PrimaryMap, VMSharedTypeIndex}; 25 26 const INVALID_PTR: usize = 0xdead_dead_beef_beef_u64 as usize; 27 28 mod libcalls; 29 mod resources; 30 31 pub use self::resources::{CallContexts, ResourceTable, ResourceTables}; 32 33 /// Runtime representation of a component instance and all state necessary for 34 /// the instance itself. 35 /// 36 /// This type never exists by-value, but rather it's always behind a pointer. 37 /// The size of the allocation for `ComponentInstance` includes the trailing 38 /// `VMComponentContext` which is variably sized based on the `offsets` 39 /// contained within. 40 #[repr(C)] 41 pub struct ComponentInstance { 42 /// Size and offset information for the trailing `VMComponentContext`. 43 offsets: VMComponentOffsets<HostPtr>, 44 45 /// For more information about this see the documentation on 46 /// `Instance::vmctx_self_reference`. 47 vmctx_self_reference: SendSyncPtr<VMComponentContext>, 48 49 /// Runtime type information about this component. 50 runtime_info: Arc<dyn ComponentRuntimeInfo>, 51 52 /// State of resources for all `TypeResourceTableIndex` values for this 53 /// component. 54 /// 55 /// This is paired with other information to create a `ResourceTables` which 56 /// is how this field is manipulated. 57 component_resource_tables: PrimaryMap<TypeResourceTableIndex, ResourceTable>, 58 59 /// Storage for the type information about resources within this component 60 /// instance. 61 /// 62 /// This is actually `Arc<PrimaryMap<ResourceIndex, ResourceType>>` but that 63 /// can't be in this crate because `ResourceType` isn't here. Not using `dyn 64 /// Any` is left as an exercise for a future refactoring. 65 resource_types: Arc<dyn Any + Send + Sync>, 66 67 /// A zero-sized field which represents the end of the struct for the actual 68 /// `VMComponentContext` to be allocated behind. 69 vmctx: VMComponentContext, 70 } 71 72 /// Type signature for host-defined trampolines that are called from 73 /// WebAssembly. 74 /// 75 /// This function signature is invoked from a cranelift-compiled trampoline that 76 /// adapts from the core wasm System-V ABI into the ABI provided here: 77 /// 78 /// * `vmctx` - this is the first argument to the wasm import, and should always 79 /// end up being a `VMComponentContext`. 80 /// * `data` - this is the data pointer associated with the `VMLowering` for 81 /// which this function pointer was registered. 82 /// * `ty` - the type index, relative to the tables in `vmctx`, that is the 83 /// type of the function being called. 84 /// * `flags` - the component flags for may_enter/leave corresponding to the 85 /// component instance that the lowering happened within. 86 /// * `opt_memory` - this nullable pointer represents the memory configuration 87 /// option for the canonical ABI options. 88 /// * `opt_realloc` - this nullable pointer represents the realloc configuration 89 /// option for the canonical ABI options. 90 /// * `string_encoding` - this is the configured string encoding for the 91 /// canonical ABI this lowering corresponds to. 92 /// * `args_and_results` - pointer to stack-allocated space in the caller where 93 /// all the arguments are stored as well as where the results will be written 94 /// to. The size and initialized bytes of this depends on the core wasm type 95 /// signature that this callee corresponds to. 96 /// * `nargs_and_results` - the size, in units of `ValRaw`, of 97 /// `args_and_results`. 98 // 99 // FIXME: 9 arguments is probably too many. The `data` through `string-encoding` 100 // parameters should probably get packaged up into the `VMComponentContext`. 101 // Needs benchmarking one way or another though to figure out what the best 102 // balance is here. 103 pub type VMLoweringCallee = extern "C" fn( 104 vmctx: *mut VMOpaqueContext, 105 data: *mut u8, 106 ty: TypeFuncIndex, 107 flags: InstanceFlags, 108 opt_memory: *mut VMMemoryDefinition, 109 opt_realloc: *mut VMFuncRef, 110 string_encoding: StringEncoding, 111 args_and_results: *mut mem::MaybeUninit<ValRaw>, 112 nargs_and_results: usize, 113 ); 114 115 /// Structure describing a lowered host function stored within a 116 /// `VMComponentContext` per-lowering. 117 #[derive(Copy, Clone)] 118 #[repr(C)] 119 pub struct VMLowering { 120 /// The host function pointer that is invoked when this lowering is 121 /// invoked. 122 pub callee: VMLoweringCallee, 123 /// The host data pointer (think void* pointer) to get passed to `callee`. 124 pub data: *mut u8, 125 } 126 127 /// This is a marker type to represent the underlying allocation of a 128 /// `VMComponentContext`. 129 /// 130 /// This type is similar to `VMContext` for core wasm and is allocated once per 131 /// component instance in Wasmtime. While the static size of this type is 0 the 132 /// actual runtime size is variable depending on the shape of the component that 133 /// this corresponds to. This structure always trails a `ComponentInstance` 134 /// allocation and the allocation/liftetime of this allocation is managed by 135 /// `ComponentInstance`. 136 #[repr(C)] 137 // Set an appropriate alignment for this structure where the most-aligned value 138 // internally right now `VMGlobalDefinition` which has an alignment of 16 bytes. 139 #[repr(align(16))] 140 pub struct VMComponentContext { 141 /// For more information about this see the equivalent field in `VMContext` 142 _marker: marker::PhantomPinned, 143 } 144 145 impl ComponentInstance { 146 /// Converts the `vmctx` provided into a `ComponentInstance` and runs the 147 /// provided closure with that instance. 148 /// 149 /// # Unsafety 150 /// 151 /// This is `unsafe` because `vmctx` cannot be guaranteed to be a valid 152 /// pointer and it cannot be proven statically that it's safe to get a 153 /// mutable reference at this time to the instance from `vmctx`. 154 pub unsafe fn from_vmctx<R>( 155 vmctx: *mut VMComponentContext, 156 f: impl FnOnce(&mut ComponentInstance) -> R, 157 ) -> R { 158 let ptr = vmctx 159 .byte_sub(mem::size_of::<ComponentInstance>()) 160 .cast::<ComponentInstance>(); 161 f(&mut *ptr) 162 } 163 164 /// Returns the layout corresponding to what would be an allocation of a 165 /// `ComponentInstance` for the `offsets` provided. 166 /// 167 /// The returned layout has space for both the `ComponentInstance` and the 168 /// trailing `VMComponentContext`. 169 fn alloc_layout(offsets: &VMComponentOffsets<HostPtr>) -> Layout { 170 let size = mem::size_of::<Self>() 171 .checked_add(usize::try_from(offsets.size_of_vmctx()).unwrap()) 172 .unwrap(); 173 let align = mem::align_of::<Self>(); 174 Layout::from_size_align(size, align).unwrap() 175 } 176 177 /// Initializes an uninitialized pointer to a `ComponentInstance` in 178 /// addition to its trailing `VMComponentContext`. 179 /// 180 /// The `ptr` provided must be valid for `alloc_size` bytes and will be 181 /// entirely overwritten by this function call. The `offsets` correspond to 182 /// the shape of the component being instantiated and `store` is a pointer 183 /// back to the Wasmtime store for host functions to have access to. 184 unsafe fn new_at( 185 ptr: NonNull<ComponentInstance>, 186 alloc_size: usize, 187 offsets: VMComponentOffsets<HostPtr>, 188 runtime_info: Arc<dyn ComponentRuntimeInfo>, 189 resource_types: Arc<dyn Any + Send + Sync>, 190 store: *mut dyn Store, 191 ) { 192 assert!(alloc_size >= Self::alloc_layout(&offsets).size()); 193 194 let num_tables = runtime_info.component().num_resource_tables; 195 let mut component_resource_tables = PrimaryMap::with_capacity(num_tables); 196 for _ in 0..num_tables { 197 component_resource_tables.push(ResourceTable::default()); 198 } 199 200 ptr::write( 201 ptr.as_ptr(), 202 ComponentInstance { 203 offsets, 204 vmctx_self_reference: SendSyncPtr::new( 205 NonNull::new( 206 ptr.as_ptr() 207 .byte_add(mem::size_of::<ComponentInstance>()) 208 .cast(), 209 ) 210 .unwrap(), 211 ), 212 component_resource_tables, 213 runtime_info, 214 resource_types, 215 vmctx: VMComponentContext { 216 _marker: marker::PhantomPinned, 217 }, 218 }, 219 ); 220 221 (*ptr.as_ptr()).initialize_vmctx(store); 222 } 223 224 fn vmctx(&self) -> *mut VMComponentContext { 225 let addr = core::ptr::addr_of!(self.vmctx); 226 Strict::with_addr(self.vmctx_self_reference.as_ptr(), Strict::addr(addr)) 227 } 228 229 unsafe fn vmctx_plus_offset<T>(&self, offset: u32) -> *const T { 230 self.vmctx() 231 .byte_add(usize::try_from(offset).unwrap()) 232 .cast() 233 } 234 235 unsafe fn vmctx_plus_offset_mut<T>(&mut self, offset: u32) -> *mut T { 236 self.vmctx() 237 .byte_add(usize::try_from(offset).unwrap()) 238 .cast() 239 } 240 241 /// Returns a pointer to the "may leave" flag for this instance specified 242 /// for canonical lowering and lifting operations. 243 #[inline] 244 pub fn instance_flags(&self, instance: RuntimeComponentInstanceIndex) -> InstanceFlags { 245 unsafe { 246 let ptr = self 247 .vmctx_plus_offset::<VMGlobalDefinition>(self.offsets.instance_flags(instance)) 248 .cast_mut(); 249 InstanceFlags(SendSyncPtr::new(NonNull::new(ptr).unwrap())) 250 } 251 } 252 253 /// Returns the store that this component was created with. 254 pub fn store(&self) -> *mut dyn Store { 255 unsafe { 256 let ret = *self.vmctx_plus_offset::<*mut dyn Store>(self.offsets.store()); 257 assert!(!ret.is_null()); 258 ret 259 } 260 } 261 262 /// Returns the runtime memory definition corresponding to the index of the 263 /// memory provided. 264 /// 265 /// This can only be called after `idx` has been initialized at runtime 266 /// during the instantiation process of a component. 267 pub fn runtime_memory(&self, idx: RuntimeMemoryIndex) -> *mut VMMemoryDefinition { 268 unsafe { 269 let ret = *self.vmctx_plus_offset(self.offsets.runtime_memory(idx)); 270 debug_assert!(ret as usize != INVALID_PTR); 271 ret 272 } 273 } 274 275 /// Returns the realloc pointer corresponding to the index provided. 276 /// 277 /// This can only be called after `idx` has been initialized at runtime 278 /// during the instantiation process of a component. 279 pub fn runtime_realloc(&self, idx: RuntimeReallocIndex) -> NonNull<VMFuncRef> { 280 unsafe { 281 let ret = *self.vmctx_plus_offset::<NonNull<_>>(self.offsets.runtime_realloc(idx)); 282 debug_assert!(ret.as_ptr() as usize != INVALID_PTR); 283 ret 284 } 285 } 286 287 /// Returns the post-return pointer corresponding to the index provided. 288 /// 289 /// This can only be called after `idx` has been initialized at runtime 290 /// during the instantiation process of a component. 291 pub fn runtime_post_return(&self, idx: RuntimePostReturnIndex) -> NonNull<VMFuncRef> { 292 unsafe { 293 let ret = *self.vmctx_plus_offset::<NonNull<_>>(self.offsets.runtime_post_return(idx)); 294 debug_assert!(ret.as_ptr() as usize != INVALID_PTR); 295 ret 296 } 297 } 298 299 /// Returns the host information for the lowered function at the index 300 /// specified. 301 /// 302 /// This can only be called after `idx` has been initialized at runtime 303 /// during the instantiation process of a component. 304 pub fn lowering(&self, idx: LoweredIndex) -> VMLowering { 305 unsafe { 306 let ret = *self.vmctx_plus_offset::<VMLowering>(self.offsets.lowering(idx)); 307 debug_assert!(ret.callee as usize != INVALID_PTR); 308 debug_assert!(ret.data as usize != INVALID_PTR); 309 ret 310 } 311 } 312 313 /// Returns the core wasm `funcref` corresponding to the trampoline 314 /// specified. 315 /// 316 /// The returned function is suitable to pass directly to a wasm module 317 /// instantiation and the function contains cranelift-compiled trampolines. 318 /// 319 /// This can only be called after `idx` has been initialized at runtime 320 /// during the instantiation process of a component. 321 pub fn trampoline_func_ref(&self, idx: TrampolineIndex) -> NonNull<VMFuncRef> { 322 unsafe { 323 let offset = self.offsets.trampoline_func_ref(idx); 324 let ret = self.vmctx_plus_offset::<VMFuncRef>(offset); 325 debug_assert!( 326 mem::transmute::<Option<NonNull<VMWasmCallFunction>>, usize>((*ret).wasm_call) 327 != INVALID_PTR 328 ); 329 debug_assert!((*ret).vmctx as usize != INVALID_PTR); 330 NonNull::new(ret.cast_mut()).unwrap() 331 } 332 } 333 334 /// Stores the runtime memory pointer at the index specified. 335 /// 336 /// This is intended to be called during the instantiation process of a 337 /// component once a memory is available, which may not be until part-way 338 /// through component instantiation. 339 /// 340 /// Note that it should be a property of the component model that the `ptr` 341 /// here is never needed prior to it being configured here in the instance. 342 pub fn set_runtime_memory(&mut self, idx: RuntimeMemoryIndex, ptr: *mut VMMemoryDefinition) { 343 unsafe { 344 debug_assert!(!ptr.is_null()); 345 let storage = self.vmctx_plus_offset_mut(self.offsets.runtime_memory(idx)); 346 debug_assert!(*storage as usize == INVALID_PTR); 347 *storage = ptr; 348 } 349 } 350 351 /// Same as `set_runtime_memory` but for realloc function pointers. 352 pub fn set_runtime_realloc(&mut self, idx: RuntimeReallocIndex, ptr: NonNull<VMFuncRef>) { 353 unsafe { 354 let storage = self.vmctx_plus_offset_mut(self.offsets.runtime_realloc(idx)); 355 debug_assert!(*storage as usize == INVALID_PTR); 356 *storage = ptr.as_ptr(); 357 } 358 } 359 360 /// Same as `set_runtime_memory` but for post-return function pointers. 361 pub fn set_runtime_post_return( 362 &mut self, 363 idx: RuntimePostReturnIndex, 364 ptr: NonNull<VMFuncRef>, 365 ) { 366 unsafe { 367 let storage = self.vmctx_plus_offset_mut(self.offsets.runtime_post_return(idx)); 368 debug_assert!(*storage as usize == INVALID_PTR); 369 *storage = ptr.as_ptr(); 370 } 371 } 372 373 /// Configures host runtime lowering information associated with imported f 374 /// functions for the `idx` specified. 375 pub fn set_lowering(&mut self, idx: LoweredIndex, lowering: VMLowering) { 376 unsafe { 377 debug_assert!( 378 *self.vmctx_plus_offset::<usize>(self.offsets.lowering_callee(idx)) == INVALID_PTR 379 ); 380 debug_assert!( 381 *self.vmctx_plus_offset::<usize>(self.offsets.lowering_data(idx)) == INVALID_PTR 382 ); 383 *self.vmctx_plus_offset_mut(self.offsets.lowering(idx)) = lowering; 384 } 385 } 386 387 /// Same as `set_lowering` but for the resource.drop functions. 388 pub fn set_trampoline( 389 &mut self, 390 idx: TrampolineIndex, 391 wasm_call: NonNull<VMWasmCallFunction>, 392 array_call: VMArrayCallFunction, 393 type_index: VMSharedTypeIndex, 394 ) { 395 unsafe { 396 let offset = self.offsets.trampoline_func_ref(idx); 397 debug_assert!(*self.vmctx_plus_offset::<usize>(offset) == INVALID_PTR); 398 let vmctx = VMOpaqueContext::from_vmcomponent(self.vmctx()); 399 *self.vmctx_plus_offset_mut(offset) = VMFuncRef { 400 wasm_call: Some(wasm_call), 401 array_call, 402 type_index, 403 vmctx, 404 }; 405 } 406 } 407 408 /// Configures the destructor for a resource at the `idx` specified. 409 /// 410 /// This is required to be called for each resource as it's defined within a 411 /// component during the instantiation process. 412 pub fn set_resource_destructor( 413 &mut self, 414 idx: ResourceIndex, 415 dtor: Option<NonNull<VMFuncRef>>, 416 ) { 417 unsafe { 418 let offset = self.offsets.resource_destructor(idx); 419 debug_assert!(*self.vmctx_plus_offset::<usize>(offset) == INVALID_PTR); 420 *self.vmctx_plus_offset_mut(offset) = dtor; 421 } 422 } 423 424 /// Returns the destructor, if any, for `idx`. 425 /// 426 /// This is only valid to call after `set_resource_destructor`, or typically 427 /// after instantiation. 428 pub fn resource_destructor(&self, idx: ResourceIndex) -> Option<NonNull<VMFuncRef>> { 429 unsafe { 430 let offset = self.offsets.resource_destructor(idx); 431 debug_assert!(*self.vmctx_plus_offset::<usize>(offset) != INVALID_PTR); 432 *self.vmctx_plus_offset(offset) 433 } 434 } 435 436 unsafe fn initialize_vmctx(&mut self, store: *mut dyn Store) { 437 *self.vmctx_plus_offset_mut(self.offsets.magic()) = VMCOMPONENT_MAGIC; 438 *self.vmctx_plus_offset_mut(self.offsets.libcalls()) = &libcalls::VMComponentLibcalls::INIT; 439 *self.vmctx_plus_offset_mut(self.offsets.store()) = store; 440 *self.vmctx_plus_offset_mut(self.offsets.limits()) = (*store).vmruntime_limits(); 441 442 for i in 0..self.offsets.num_runtime_component_instances { 443 let i = RuntimeComponentInstanceIndex::from_u32(i); 444 let mut def = VMGlobalDefinition::new(); 445 *def.as_i32_mut() = FLAG_MAY_ENTER | FLAG_MAY_LEAVE; 446 *self.instance_flags(i).as_raw() = def; 447 } 448 449 // In debug mode set non-null bad values to all "pointer looking" bits 450 // and pices related to lowering and such. This'll help detect any 451 // erroneous usage and enable debug assertions above as well to prevent 452 // loading these before they're configured or setting them twice. 453 if cfg!(debug_assertions) { 454 for i in 0..self.offsets.num_lowerings { 455 let i = LoweredIndex::from_u32(i); 456 let offset = self.offsets.lowering_callee(i); 457 *self.vmctx_plus_offset_mut(offset) = INVALID_PTR; 458 let offset = self.offsets.lowering_data(i); 459 *self.vmctx_plus_offset_mut(offset) = INVALID_PTR; 460 } 461 for i in 0..self.offsets.num_trampolines { 462 let i = TrampolineIndex::from_u32(i); 463 let offset = self.offsets.trampoline_func_ref(i); 464 *self.vmctx_plus_offset_mut(offset) = INVALID_PTR; 465 } 466 for i in 0..self.offsets.num_runtime_memories { 467 let i = RuntimeMemoryIndex::from_u32(i); 468 let offset = self.offsets.runtime_memory(i); 469 *self.vmctx_plus_offset_mut(offset) = INVALID_PTR; 470 } 471 for i in 0..self.offsets.num_runtime_reallocs { 472 let i = RuntimeReallocIndex::from_u32(i); 473 let offset = self.offsets.runtime_realloc(i); 474 *self.vmctx_plus_offset_mut(offset) = INVALID_PTR; 475 } 476 for i in 0..self.offsets.num_runtime_post_returns { 477 let i = RuntimePostReturnIndex::from_u32(i); 478 let offset = self.offsets.runtime_post_return(i); 479 *self.vmctx_plus_offset_mut(offset) = INVALID_PTR; 480 } 481 for i in 0..self.offsets.num_resources { 482 let i = ResourceIndex::from_u32(i); 483 let offset = self.offsets.resource_destructor(i); 484 *self.vmctx_plus_offset_mut(offset) = INVALID_PTR; 485 } 486 } 487 } 488 489 /// Returns a reference to the component type information for this instance. 490 pub fn component(&self) -> &Component { 491 self.runtime_info.component() 492 } 493 494 /// Returns the type information that this instance is instantiated with. 495 pub fn component_types(&self) -> &Arc<ComponentTypes> { 496 self.runtime_info.component_types() 497 } 498 499 /// Get the canonical ABI's `realloc` function's runtime type. 500 pub fn realloc_func_ty(&self) -> &Arc<dyn Any + Send + Sync> { 501 self.runtime_info.realloc_func_type() 502 } 503 504 /// Returns a reference to the resource type information as a `dyn Any`. 505 /// 506 /// Wasmtime is the one which then downcasts this to the appropriate type. 507 pub fn resource_types(&self) -> &Arc<dyn Any + Send + Sync> { 508 &self.resource_types 509 } 510 511 /// Returns whether the resource that `ty` points to is owned by the 512 /// instance that `ty` correspond to. 513 /// 514 /// This is used when lowering borrows to skip table management and instead 515 /// thread through the underlying representation directly. 516 pub fn resource_owned_by_own_instance(&self, ty: TypeResourceTableIndex) -> bool { 517 let resource = &self.component_types()[ty]; 518 let component = self.component(); 519 let idx = match component.defined_resource_index(resource.ty) { 520 Some(idx) => idx, 521 None => return false, 522 }; 523 resource.instance == component.defined_resource_instances[idx] 524 } 525 526 /// Implementation of the `resource.new` intrinsic for `i32` 527 /// representations. 528 pub fn resource_new32(&mut self, resource: TypeResourceTableIndex, rep: u32) -> Result<u32> { 529 self.resource_tables().resource_new(Some(resource), rep) 530 } 531 532 /// Implementation of the `resource.rep` intrinsic for `i32` 533 /// representations. 534 pub fn resource_rep32(&mut self, resource: TypeResourceTableIndex, idx: u32) -> Result<u32> { 535 self.resource_tables().resource_rep(Some(resource), idx) 536 } 537 538 /// Implementation of the `resource.drop` intrinsic. 539 pub fn resource_drop( 540 &mut self, 541 resource: TypeResourceTableIndex, 542 idx: u32, 543 ) -> Result<Option<u32>> { 544 self.resource_tables().resource_drop(Some(resource), idx) 545 } 546 547 /// NB: this is intended to be a private method. This does not have 548 /// `host_table` information at this time meaning it's only suitable for 549 /// working with resources specified to this component which is currently 550 /// all that this is used for. 551 /// 552 /// If necessary though it's possible to enhance the `Store` trait to thread 553 /// through the relevant information and get `host_table` to be `Some` here. 554 fn resource_tables(&mut self) -> ResourceTables<'_> { 555 ResourceTables { 556 host_table: None, 557 calls: unsafe { (&mut *self.store()).component_calls() }, 558 tables: Some(&mut self.component_resource_tables), 559 } 560 } 561 562 /// Returns the runtime state of resources associated with this component. 563 #[inline] 564 pub fn component_resource_tables( 565 &mut self, 566 ) -> &mut PrimaryMap<TypeResourceTableIndex, ResourceTable> { 567 &mut self.component_resource_tables 568 } 569 570 /// Returns the destructor and instance flags for the specified resource 571 /// table type. 572 /// 573 /// This will lookup the origin definition of the `ty` table and return the 574 /// destructor/flags for that. 575 pub fn dtor_and_flags( 576 &self, 577 ty: TypeResourceTableIndex, 578 ) -> (Option<NonNull<VMFuncRef>>, Option<InstanceFlags>) { 579 let resource = self.component_types()[ty].ty; 580 let dtor = self.resource_destructor(resource); 581 let component = self.component(); 582 let flags = component.defined_resource_index(resource).map(|i| { 583 let instance = component.defined_resource_instances[i]; 584 self.instance_flags(instance) 585 }); 586 (dtor, flags) 587 } 588 589 pub(crate) fn resource_transfer_own( 590 &mut self, 591 idx: u32, 592 src: TypeResourceTableIndex, 593 dst: TypeResourceTableIndex, 594 ) -> Result<u32> { 595 let mut tables = self.resource_tables(); 596 let rep = tables.resource_lift_own(Some(src), idx)?; 597 tables.resource_lower_own(Some(dst), rep) 598 } 599 600 pub(crate) fn resource_transfer_borrow( 601 &mut self, 602 idx: u32, 603 src: TypeResourceTableIndex, 604 dst: TypeResourceTableIndex, 605 ) -> Result<u32> { 606 let dst_owns_resource = self.resource_owned_by_own_instance(dst); 607 let mut tables = self.resource_tables(); 608 let rep = tables.resource_lift_borrow(Some(src), idx)?; 609 // Implement `lower_borrow`'s special case here where if a borrow's 610 // resource type is owned by `dst` then the destination receives the 611 // representation directly rather than a handle to the representation. 612 // 613 // This can perhaps become a different libcall in the future to avoid 614 // this check at runtime since we know at compile time whether the 615 // destination type owns the resource, but that's left as a future 616 // refactoring if truly necessary. 617 if dst_owns_resource { 618 return Ok(rep); 619 } 620 tables.resource_lower_borrow(Some(dst), rep) 621 } 622 623 pub(crate) fn resource_enter_call(&mut self) { 624 self.resource_tables().enter_call() 625 } 626 627 pub(crate) fn resource_exit_call(&mut self) -> Result<()> { 628 self.resource_tables().exit_call() 629 } 630 } 631 632 impl VMComponentContext { 633 /// Moves the `self` pointer backwards to the `ComponentInstance` pointer 634 /// that this `VMComponentContext` trails. 635 pub fn instance(&self) -> *mut ComponentInstance { 636 unsafe { 637 (self as *const Self as *mut u8) 638 .offset(-(offset_of!(ComponentInstance, vmctx) as isize)) 639 as *mut ComponentInstance 640 } 641 } 642 } 643 644 /// An owned version of `ComponentInstance` which is akin to 645 /// `Box<ComponentInstance>`. 646 /// 647 /// This type can be dereferenced to `ComponentInstance` to access the 648 /// underlying methods. 649 pub struct OwnedComponentInstance { 650 ptr: SendSyncPtr<ComponentInstance>, 651 } 652 653 impl OwnedComponentInstance { 654 /// Allocates a new `ComponentInstance + VMComponentContext` pair on the 655 /// heap with `malloc` and configures it for the `component` specified. 656 pub fn new( 657 runtime_info: Arc<dyn ComponentRuntimeInfo>, 658 resource_types: Arc<dyn Any + Send + Sync>, 659 store: *mut dyn Store, 660 ) -> OwnedComponentInstance { 661 let component = runtime_info.component(); 662 let offsets = VMComponentOffsets::new(HostPtr, component); 663 let layout = ComponentInstance::alloc_layout(&offsets); 664 unsafe { 665 // Technically it is not required to `alloc_zeroed` here. The 666 // primary reason for doing this is because a component context 667 // start is a "partly initialized" state where pointers and such are 668 // configured as the instantiation process continues. The component 669 // model should guarantee that we never access uninitialized memory 670 // in the context, but to help protect against possible bugs a 671 // zeroed allocation is done here to try to contain 672 // use-before-initialized issues. 673 let ptr = alloc::alloc::alloc_zeroed(layout) as *mut ComponentInstance; 674 let ptr = NonNull::new(ptr).unwrap(); 675 676 ComponentInstance::new_at( 677 ptr, 678 layout.size(), 679 offsets, 680 runtime_info, 681 resource_types, 682 store, 683 ); 684 685 let ptr = SendSyncPtr::new(ptr); 686 OwnedComponentInstance { ptr } 687 } 688 } 689 690 // Note that this is technically unsafe due to the fact that it enables 691 // `mem::swap`-ing two component instances which would get all the offsets 692 // mixed up and cause issues. This is scoped to just this module though as a 693 // convenience to forward to `&mut` methods on `ComponentInstance`. 694 unsafe fn instance_mut(&mut self) -> &mut ComponentInstance { 695 &mut *self.ptr.as_ptr() 696 } 697 698 /// Returns the underlying component instance's raw pointer. 699 pub fn instance_ptr(&self) -> *mut ComponentInstance { 700 self.ptr.as_ptr() 701 } 702 703 /// See `ComponentInstance::set_runtime_memory` 704 pub fn set_runtime_memory(&mut self, idx: RuntimeMemoryIndex, ptr: *mut VMMemoryDefinition) { 705 unsafe { self.instance_mut().set_runtime_memory(idx, ptr) } 706 } 707 708 /// See `ComponentInstance::set_runtime_realloc` 709 pub fn set_runtime_realloc(&mut self, idx: RuntimeReallocIndex, ptr: NonNull<VMFuncRef>) { 710 unsafe { self.instance_mut().set_runtime_realloc(idx, ptr) } 711 } 712 713 /// See `ComponentInstance::set_runtime_post_return` 714 pub fn set_runtime_post_return( 715 &mut self, 716 idx: RuntimePostReturnIndex, 717 ptr: NonNull<VMFuncRef>, 718 ) { 719 unsafe { self.instance_mut().set_runtime_post_return(idx, ptr) } 720 } 721 722 /// See `ComponentInstance::set_lowering` 723 pub fn set_lowering(&mut self, idx: LoweredIndex, lowering: VMLowering) { 724 unsafe { self.instance_mut().set_lowering(idx, lowering) } 725 } 726 727 /// See `ComponentInstance::set_resource_drop` 728 pub fn set_trampoline( 729 &mut self, 730 idx: TrampolineIndex, 731 wasm_call: NonNull<VMWasmCallFunction>, 732 array_call: VMArrayCallFunction, 733 type_index: VMSharedTypeIndex, 734 ) { 735 unsafe { 736 self.instance_mut() 737 .set_trampoline(idx, wasm_call, array_call, type_index) 738 } 739 } 740 741 /// See `ComponentInstance::set_resource_destructor` 742 pub fn set_resource_destructor( 743 &mut self, 744 idx: ResourceIndex, 745 dtor: Option<NonNull<VMFuncRef>>, 746 ) { 747 unsafe { self.instance_mut().set_resource_destructor(idx, dtor) } 748 } 749 750 /// See `ComponentInstance::resource_types` 751 pub fn resource_types_mut(&mut self) -> &mut Arc<dyn Any + Send + Sync> { 752 unsafe { &mut (*self.ptr.as_ptr()).resource_types } 753 } 754 } 755 756 impl Deref for OwnedComponentInstance { 757 type Target = ComponentInstance; 758 fn deref(&self) -> &ComponentInstance { 759 unsafe { &*self.ptr.as_ptr() } 760 } 761 } 762 763 impl Drop for OwnedComponentInstance { 764 fn drop(&mut self) { 765 let layout = ComponentInstance::alloc_layout(&self.offsets); 766 unsafe { 767 ptr::drop_in_place(self.ptr.as_ptr()); 768 alloc::alloc::dealloc(self.ptr.as_ptr().cast(), layout); 769 } 770 } 771 } 772 773 impl VMComponentContext { 774 /// Helper function to cast between context types using a debug assertion to 775 /// protect against some mistakes. 776 #[inline] 777 pub unsafe fn from_opaque(opaque: *mut VMOpaqueContext) -> *mut VMComponentContext { 778 // See comments in `VMContext::from_opaque` for this debug assert 779 debug_assert_eq!((*opaque).magic, VMCOMPONENT_MAGIC); 780 opaque.cast() 781 } 782 } 783 784 impl VMOpaqueContext { 785 /// Helper function to clearly indicate the cast desired 786 #[inline] 787 pub fn from_vmcomponent(ptr: *mut VMComponentContext) -> *mut VMOpaqueContext { 788 ptr.cast() 789 } 790 } 791 792 #[allow(missing_docs)] 793 #[repr(transparent)] 794 #[derive(Copy, Clone)] 795 pub struct InstanceFlags(SendSyncPtr<VMGlobalDefinition>); 796 797 #[allow(missing_docs)] 798 impl InstanceFlags { 799 #[inline] 800 pub unsafe fn may_leave(&self) -> bool { 801 *(*self.as_raw()).as_i32() & FLAG_MAY_LEAVE != 0 802 } 803 804 #[inline] 805 pub unsafe fn set_may_leave(&mut self, val: bool) { 806 if val { 807 *(*self.as_raw()).as_i32_mut() |= FLAG_MAY_LEAVE; 808 } else { 809 *(*self.as_raw()).as_i32_mut() &= !FLAG_MAY_LEAVE; 810 } 811 } 812 813 #[inline] 814 pub unsafe fn may_enter(&self) -> bool { 815 *(*self.as_raw()).as_i32() & FLAG_MAY_ENTER != 0 816 } 817 818 #[inline] 819 pub unsafe fn set_may_enter(&mut self, val: bool) { 820 if val { 821 *(*self.as_raw()).as_i32_mut() |= FLAG_MAY_ENTER; 822 } else { 823 *(*self.as_raw()).as_i32_mut() &= !FLAG_MAY_ENTER; 824 } 825 } 826 827 #[inline] 828 pub unsafe fn needs_post_return(&self) -> bool { 829 *(*self.as_raw()).as_i32() & FLAG_NEEDS_POST_RETURN != 0 830 } 831 832 #[inline] 833 pub unsafe fn set_needs_post_return(&mut self, val: bool) { 834 if val { 835 *(*self.as_raw()).as_i32_mut() |= FLAG_NEEDS_POST_RETURN; 836 } else { 837 *(*self.as_raw()).as_i32_mut() &= !FLAG_NEEDS_POST_RETURN; 838 } 839 } 840 841 #[inline] 842 pub fn as_raw(&self) -> *mut VMGlobalDefinition { 843 self.0.as_ptr() 844 } 845 } 846 847 /// Runtime information about a component stored locally for reflection. 848 pub trait ComponentRuntimeInfo: Send + Sync + 'static { 849 /// Returns the type information about the compiled component. 850 fn component(&self) -> &Component; 851 852 /// Returns a handle to the tables of type information for this component. 853 fn component_types(&self) -> &Arc<ComponentTypes>; 854 855 /// Get the `wasmtime::FuncType` for the canonical ABI's `realloc` function. 856 fn realloc_func_type(&self) -> &Arc<dyn Any + Send + Sync>; 857 } 858