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