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