172004aadSNick Fitzgerald //! An `Instance` contains all the runtime state used by execution of a 272004aadSNick Fitzgerald //! wasm module (except its callstack and register state). An 372004aadSNick Fitzgerald //! `InstanceHandle` is a reference-counting handle for an `Instance`. 472004aadSNick Fitzgerald 5*b052dee0SAlex Crichton #![warn( 6*b052dee0SAlex Crichton unsafe_op_in_unsafe_fn, 7*b052dee0SAlex Crichton reason = "opt-in until the crate opts-in as a whole -- #11180" 8*b052dee0SAlex Crichton )] 9*b052dee0SAlex Crichton 104233014bSAlex Crichton use crate::prelude::*; 1172004aadSNick Fitzgerald use crate::runtime::vm::const_expr::{ConstEvalContext, ConstExprEvaluator}; 1272004aadSNick Fitzgerald use crate::runtime::vm::export::Export; 1372004aadSNick Fitzgerald use crate::runtime::vm::memory::{Memory, RuntimeMemoryCreator}; 1472004aadSNick Fitzgerald use crate::runtime::vm::table::{Table, TableElement, TableElementType}; 1572004aadSNick Fitzgerald use crate::runtime::vm::vmcontext::{ 1672004aadSNick Fitzgerald VMBuiltinFunctionsArray, VMContext, VMFuncRef, VMFunctionImport, VMGlobalDefinition, 1746306693SAlex Crichton VMGlobalImport, VMMemoryDefinition, VMMemoryImport, VMOpaqueContext, VMStoreContext, 1846306693SAlex Crichton VMTableDefinition, VMTableImport, VMTagDefinition, VMTagImport, 1972004aadSNick Fitzgerald }; 2072004aadSNick Fitzgerald use crate::runtime::vm::{ 212b832281SAlex Crichton GcStore, Imports, ModuleRuntimeInfo, SendSyncPtr, VMGcRef, VMGlobalKind, VMStore, 222b832281SAlex Crichton VMStoreRawPtr, VmPtr, VmSafe, WasmFault, 2372004aadSNick Fitzgerald }; 242b832281SAlex Crichton use crate::store::{InstanceId, StoreId, StoreInstanceId, StoreOpaque}; 2581a89169SAlex Crichton use alloc::sync::Arc; 2681a89169SAlex Crichton use core::alloc::Layout; 277e28c254SAlex Crichton use core::marker; 2881a89169SAlex Crichton use core::ops::Range; 29aad93a48SAlex Crichton use core::pin::Pin; 3081a89169SAlex Crichton use core::ptr::NonNull; 3110eda1cfSAlex Crichton #[cfg(target_has_atomic = "64")] 3281a89169SAlex Crichton use core::sync::atomic::AtomicU64; 3381a89169SAlex Crichton use core::{mem, ptr}; 34cb235ecfSNick Fitzgerald #[cfg(feature = "gc")] 35cb235ecfSNick Fitzgerald use wasmtime_environ::ModuleInternedTypeIndex; 3672004aadSNick Fitzgerald use wasmtime_environ::{ 3790ac295eSAlex Crichton DataIndex, DefinedGlobalIndex, DefinedMemoryIndex, DefinedTableIndex, DefinedTagIndex, 3890ac295eSAlex Crichton ElemIndex, EntityIndex, EntityRef, EntitySet, FuncIndex, GlobalIndex, HostPtr, MemoryIndex, 3990ac295eSAlex Crichton Module, PrimaryMap, PtrSize, TableIndex, TableInitialValue, TableSegmentElements, TagIndex, 4090ac295eSAlex Crichton Trap, VMCONTEXT_MAGIC, VMOffsets, VMSharedTypeIndex, WasmHeapTopType, 4190ac295eSAlex Crichton packed_option::ReservedValue, 4272004aadSNick Fitzgerald }; 4372004aadSNick Fitzgerald #[cfg(feature = "wmemcheck")] 4472004aadSNick Fitzgerald use wasmtime_wmemcheck::Wmemcheck; 4572004aadSNick Fitzgerald 4672004aadSNick Fitzgerald mod allocator; 4772004aadSNick Fitzgerald pub use allocator::*; 4872004aadSNick Fitzgerald 498818b251SNick Fitzgerald /// The pair of an instance and a raw pointer its associated store. 508818b251SNick Fitzgerald /// 518818b251SNick Fitzgerald /// ### Safety 528818b251SNick Fitzgerald /// 53aad93a48SAlex Crichton /// > **Note**: it's known that the documentation below is documenting an 54aad93a48SAlex Crichton /// > unsound pattern and we're in the process of fixing it, but it'll take 55aad93a48SAlex Crichton /// > some time to refactor. Notably `unpack_mut` is not sound because the 56aad93a48SAlex Crichton /// > returned store pointer can be used to accidentally alias the instance 57aad93a48SAlex Crichton /// > pointer returned as well. 58aad93a48SAlex Crichton /// 598818b251SNick Fitzgerald /// Getting a borrow of a vmctx's store is one of the fundamental bits of unsafe 608818b251SNick Fitzgerald /// code in Wasmtime. No matter how we architect the runtime, some kind of 618818b251SNick Fitzgerald /// unsafe conversion from a raw vmctx pointer that Wasm is using into a Rust 628818b251SNick Fitzgerald /// struct must happen. 638818b251SNick Fitzgerald /// 648818b251SNick Fitzgerald /// It is our responsibility to ensure that multiple (exclusive) borrows of the 658818b251SNick Fitzgerald /// vmctx's store never exist at the same time. The distinction between the 668818b251SNick Fitzgerald /// `Instance` type (which doesn't expose its underlying vmctx pointer or a way 678818b251SNick Fitzgerald /// to get a borrow of its associated store) and this type (which does) is 688818b251SNick Fitzgerald /// designed to help with that. 698818b251SNick Fitzgerald /// 708818b251SNick Fitzgerald /// Going from a `*mut VMContext` to a `&mut StoreInner<T>` is naturally unsafe 718818b251SNick Fitzgerald /// due to the raw pointer usage, but additionally the `T` type parameter needs 728818b251SNick Fitzgerald /// to be the same `T` that was used to define the `dyn VMStore` trait object 738818b251SNick Fitzgerald /// that was stuffed into the vmctx. 748818b251SNick Fitzgerald /// 758818b251SNick Fitzgerald /// ### Usage 768818b251SNick Fitzgerald /// 778818b251SNick Fitzgerald /// Usage generally looks like: 788818b251SNick Fitzgerald /// 798818b251SNick Fitzgerald /// 1. You get a raw `*mut VMContext` from Wasm 808818b251SNick Fitzgerald /// 818818b251SNick Fitzgerald /// 2. You call `InstanceAndStore::from_vmctx` on that raw pointer 828818b251SNick Fitzgerald /// 838818b251SNick Fitzgerald /// 3. You then call `InstanceAndStore::unpack_mut` (or another helper) to get 84aad93a48SAlex Crichton /// the underlying `Pin<&mut Instance>` and `&mut dyn VMStore` (or `&mut 858818b251SNick Fitzgerald /// StoreInner<T>`). 868818b251SNick Fitzgerald /// 878818b251SNick Fitzgerald /// 4. You then use whatever `Instance` methods you need to, each of which take 888818b251SNick Fitzgerald /// a store argument as necessary. 898818b251SNick Fitzgerald /// 908818b251SNick Fitzgerald /// In step (4) you no longer need to worry about double exclusive borrows of 918818b251SNick Fitzgerald /// the store, so long as you don't do (1-2) again. Note also that the borrow 928818b251SNick Fitzgerald /// checker prevents repeating step (3) if you never repeat (1-2). In general, 938818b251SNick Fitzgerald /// steps (1-3) should be done in a single, common, internally-unsafe, 948818b251SNick Fitzgerald /// plumbing-code bottleneck and the raw pointer should never be exposed to Rust 958818b251SNick Fitzgerald /// code that does (4) after the `InstanceAndStore` is created. Follow this 968818b251SNick Fitzgerald /// pattern, and everything using the resulting `Instance` and `Store` can be 978818b251SNick Fitzgerald /// safe code (at least, with regards to accessing the store itself). 988818b251SNick Fitzgerald /// 998818b251SNick Fitzgerald /// As an illustrative example, the common plumbing code for our various 1008818b251SNick Fitzgerald /// libcalls performs steps (1-3) before calling into each actual libcall 1018818b251SNick Fitzgerald /// implementation function that does (4). The plumbing code hides the raw vmctx 1028818b251SNick Fitzgerald /// pointer and never gives out access to it to the libcall implementation 1038818b251SNick Fitzgerald /// functions, nor does an `Instance` expose its internal vmctx pointer, which 1048818b251SNick Fitzgerald /// would allow unsafely repeating steps (1-2). 1058818b251SNick Fitzgerald #[repr(transparent)] 1068818b251SNick Fitzgerald pub struct InstanceAndStore { 1078818b251SNick Fitzgerald instance: Instance, 1088818b251SNick Fitzgerald } 1098818b251SNick Fitzgerald 1108818b251SNick Fitzgerald impl InstanceAndStore { 1118818b251SNick Fitzgerald /// Converts the provided `*mut VMContext` to an `InstanceAndStore` 1128818b251SNick Fitzgerald /// reference and calls the provided closure with it. 1138818b251SNick Fitzgerald /// 1148818b251SNick Fitzgerald /// This method will move the `vmctx` pointer backwards to point to the 1158818b251SNick Fitzgerald /// original `Instance` that precedes it. The closure is provided a 1168818b251SNick Fitzgerald /// temporary reference to the `InstanceAndStore` with a constrained 1178818b251SNick Fitzgerald /// lifetime to ensure that it doesn't accidentally escape. 1188818b251SNick Fitzgerald /// 1198818b251SNick Fitzgerald /// # Safety 1208818b251SNick Fitzgerald /// 1218818b251SNick Fitzgerald /// Callers must validate that the `vmctx` pointer is a valid allocation and 1228818b251SNick Fitzgerald /// that it's valid to acquire `&mut InstanceAndStore` at this time. For 1238818b251SNick Fitzgerald /// example this can't be called twice on the same `VMContext` to get two 1248818b251SNick Fitzgerald /// active mutable borrows to the same `InstanceAndStore`. 1258818b251SNick Fitzgerald /// 1268818b251SNick Fitzgerald /// See also the safety discussion in this type's documentation. 1278818b251SNick Fitzgerald #[inline] 1288818b251SNick Fitzgerald pub(crate) unsafe fn from_vmctx<R>( 129b86b9682SAlex Crichton vmctx: NonNull<VMContext>, 1308818b251SNick Fitzgerald f: impl for<'a> FnOnce(&'a mut Self) -> R, 1318818b251SNick Fitzgerald ) -> R { 1328818b251SNick Fitzgerald const _: () = assert!(mem::size_of::<InstanceAndStore>() == mem::size_of::<Instance>()); 133*b052dee0SAlex Crichton // SAFETY: The validity of this `byte_sub` relies on `vmctx` being a 134*b052dee0SAlex Crichton // valid allocation which is itself a contract of this function. 135*b052dee0SAlex Crichton let mut ptr = unsafe { 136*b052dee0SAlex Crichton vmctx 1378818b251SNick Fitzgerald .byte_sub(mem::size_of::<Instance>()) 138*b052dee0SAlex Crichton .cast::<InstanceAndStore>() 139*b052dee0SAlex Crichton }; 1408818b251SNick Fitzgerald 141*b052dee0SAlex Crichton // SAFETY: the ability to interpret `vmctx` as a safe pointer and 142*b052dee0SAlex Crichton // continue on is a contract of this function itself, so the safety here 143*b052dee0SAlex Crichton // is effectively up to callers. 144*b052dee0SAlex Crichton unsafe { f(ptr.as_mut()) } 1458818b251SNick Fitzgerald } 1468818b251SNick Fitzgerald 1478818b251SNick Fitzgerald /// Unpacks this `InstanceAndStore` into its underlying `Instance` and `dyn 1488818b251SNick Fitzgerald /// VMStore`. 1498818b251SNick Fitzgerald #[inline] 150aad93a48SAlex Crichton pub(crate) fn unpack_mut(&mut self) -> (Pin<&mut Instance>, &mut dyn VMStore) { 1518818b251SNick Fitzgerald unsafe { 1528818b251SNick Fitzgerald let store = &mut *self.store_ptr(); 153aad93a48SAlex Crichton (Pin::new_unchecked(&mut self.instance), store) 1548818b251SNick Fitzgerald } 1558818b251SNick Fitzgerald } 1568818b251SNick Fitzgerald 1578818b251SNick Fitzgerald /// Gets a pointer to this instance's `Store` which was originally 1588818b251SNick Fitzgerald /// configured on creation. 1598818b251SNick Fitzgerald /// 1608818b251SNick Fitzgerald /// # Panics 1618818b251SNick Fitzgerald /// 1628818b251SNick Fitzgerald /// May panic if the originally configured store was `None`. That can happen 1638818b251SNick Fitzgerald /// for host functions so host functions can't be queried what their 1648818b251SNick Fitzgerald /// original `Store` was since it's just retained as null (since host 1658818b251SNick Fitzgerald /// functions are shared amongst threads and don't all share the same 1668818b251SNick Fitzgerald /// store). 1678818b251SNick Fitzgerald #[inline] 1688818b251SNick Fitzgerald fn store_ptr(&self) -> *mut dyn VMStore { 169c3559d4aSAlex Crichton self.instance.store.unwrap().0.as_ptr() 1708818b251SNick Fitzgerald } 1718818b251SNick Fitzgerald } 1728818b251SNick Fitzgerald 17372004aadSNick Fitzgerald /// A type that roughly corresponds to a WebAssembly instance, but is also used 17472004aadSNick Fitzgerald /// for host-defined objects. 17572004aadSNick Fitzgerald /// 17672004aadSNick Fitzgerald /// Instances here can correspond to actual instantiated modules, but it's also 17772004aadSNick Fitzgerald /// used ubiquitously for host-defined objects. For example creating a 17872004aadSNick Fitzgerald /// host-defined memory will have a `module` that looks like it exports a single 17972004aadSNick Fitzgerald /// memory (and similar for other constructs). 18072004aadSNick Fitzgerald /// 18172004aadSNick Fitzgerald /// This `Instance` type is used as a ubiquitous representation for WebAssembly 18272004aadSNick Fitzgerald /// values, whether or not they were created on the host or through a module. 183aad93a48SAlex Crichton /// 184aad93a48SAlex Crichton /// # Ownership 185aad93a48SAlex Crichton /// 186aad93a48SAlex Crichton /// This structure is never allocated directly but is instead managed through 187aad93a48SAlex Crichton /// an `InstanceHandle`. This structure ends with a `VMContext` which has a 188aad93a48SAlex Crichton /// dynamic size corresponding to the `module` configured within. Memory 189aad93a48SAlex Crichton /// management of this structure is always done through `InstanceHandle` as the 190aad93a48SAlex Crichton /// sole owner of an instance. 191aad93a48SAlex Crichton /// 192aad93a48SAlex Crichton /// # `Instance` and `Pin` 193aad93a48SAlex Crichton /// 194aad93a48SAlex Crichton /// Given an instance it is accompanied with trailing memory for the 195aad93a48SAlex Crichton /// appropriate `VMContext`. The `Instance` also holds `runtime_info` and other 196aad93a48SAlex Crichton /// information pointing to relevant offsets for the `VMContext`. Thus it is 197aad93a48SAlex Crichton /// not sound to mutate `runtime_info` after an instance is created. More 198aad93a48SAlex Crichton /// generally it's also not safe to "swap" instances, for example given two 199aad93a48SAlex Crichton /// `&mut Instance` values it's not sound to swap them as then the `VMContext` 200aad93a48SAlex Crichton /// values are inaccurately described. 201aad93a48SAlex Crichton /// 202aad93a48SAlex Crichton /// To encapsulate this guarantee this type is only ever mutated through Rust's 203aad93a48SAlex Crichton /// `Pin` type. All mutable methods here take `self: Pin<&mut Self>` which 204aad93a48SAlex Crichton /// statically disallows safe access to `&mut Instance`. There are assorted 205aad93a48SAlex Crichton /// "projection methods" to go from `Pin<&mut Instance>` to `&mut T` for 206aad93a48SAlex Crichton /// individual fields, for example `memories_mut`. More methods can be added as 207aad93a48SAlex Crichton /// necessary or methods may also be added to project multiple fields at a time 208aad93a48SAlex Crichton /// if necessary to. The precise ergonomics around getting mutable access to 209aad93a48SAlex Crichton /// some fields (but notably not `runtime_info`) is probably going to evolve 210aad93a48SAlex Crichton /// over time. 211aad93a48SAlex Crichton /// 212aad93a48SAlex Crichton /// Note that is is not sound to basically ever pass around `&mut Instance`. 213aad93a48SAlex Crichton /// That should always instead be `Pin<&mut Instance>`. All usage of 214aad93a48SAlex Crichton /// `Pin::new_unchecked` should be here in this module in just a few `unsafe` 215aad93a48SAlex Crichton /// locations and it's recommended to use existing helpers if you can. 21672004aadSNick Fitzgerald #[repr(C)] // ensure that the vmctx field is last. 21772004aadSNick Fitzgerald pub struct Instance { 218ed20d93dSAlex Crichton /// The index, within a `Store` that this instance lives at 219ed20d93dSAlex Crichton id: InstanceId, 220ed20d93dSAlex Crichton 22172004aadSNick Fitzgerald /// The runtime info (corresponding to the "compiled module" 22272004aadSNick Fitzgerald /// abstraction in higher layers) that is retained and needed for 22372004aadSNick Fitzgerald /// lazy initialization. This provides access to the underlying 22472004aadSNick Fitzgerald /// Wasm module entities, the compiled JIT code, metadata about 22572004aadSNick Fitzgerald /// functions, lazy initialization state, etc. 2262835a34bSAlex Crichton runtime_info: ModuleRuntimeInfo, 22772004aadSNick Fitzgerald 22872004aadSNick Fitzgerald /// WebAssembly linear memory data. 22972004aadSNick Fitzgerald /// 23072004aadSNick Fitzgerald /// This is where all runtime information about defined linear memories in 23172004aadSNick Fitzgerald /// this module lives. 23272004aadSNick Fitzgerald /// 23372004aadSNick Fitzgerald /// The `MemoryAllocationIndex` was given from our `InstanceAllocator` and 23472004aadSNick Fitzgerald /// must be given back to the instance allocator when deallocating each 23572004aadSNick Fitzgerald /// memory. 23672004aadSNick Fitzgerald memories: PrimaryMap<DefinedMemoryIndex, (MemoryAllocationIndex, Memory)>, 23772004aadSNick Fitzgerald 23872004aadSNick Fitzgerald /// WebAssembly table data. 23972004aadSNick Fitzgerald /// 24072004aadSNick Fitzgerald /// Like memories, this is only for defined tables in the module and 24172004aadSNick Fitzgerald /// contains all of their runtime state. 24272004aadSNick Fitzgerald /// 24372004aadSNick Fitzgerald /// The `TableAllocationIndex` was given from our `InstanceAllocator` and 24472004aadSNick Fitzgerald /// must be given back to the instance allocator when deallocating each 24572004aadSNick Fitzgerald /// table. 24672004aadSNick Fitzgerald tables: PrimaryMap<DefinedTableIndex, (TableAllocationIndex, Table)>, 24772004aadSNick Fitzgerald 24872004aadSNick Fitzgerald /// Stores the dropped passive element segments in this instantiation by index. 24972004aadSNick Fitzgerald /// If the index is present in the set, the segment has been dropped. 25072004aadSNick Fitzgerald dropped_elements: EntitySet<ElemIndex>, 25172004aadSNick Fitzgerald 25272004aadSNick Fitzgerald /// Stores the dropped passive data segments in this instantiation by index. 25372004aadSNick Fitzgerald /// If the index is present in the set, the segment has been dropped. 25472004aadSNick Fitzgerald dropped_data: EntitySet<DataIndex>, 25572004aadSNick Fitzgerald 25672004aadSNick Fitzgerald // TODO: add support for multiple memories; `wmemcheck_state` corresponds to 25772004aadSNick Fitzgerald // memory 0. 25872004aadSNick Fitzgerald #[cfg(feature = "wmemcheck")] 25972004aadSNick Fitzgerald pub(crate) wmemcheck_state: Option<Wmemcheck>, 26072004aadSNick Fitzgerald 261c3559d4aSAlex Crichton /// Self-pointer back to `Store<T>` and its functions. Not present for 262c3559d4aSAlex Crichton /// the brief time that `Store<T>` is itself being created. Also not 263c3559d4aSAlex Crichton /// present for some niche uses that are disconnected from stores (e.g. 264c3559d4aSAlex Crichton /// cross-thread stuff used in `InstancePre`) 265c3559d4aSAlex Crichton store: Option<VMStoreRawPtr>, 266c3559d4aSAlex Crichton 26772004aadSNick Fitzgerald /// Additional context used by compiled wasm code. This field is last, and 26872004aadSNick Fitzgerald /// represents a dynamically-sized array that extends beyond the nominal 26972004aadSNick Fitzgerald /// end of the struct (similar to a flexible array member). 2707e28c254SAlex Crichton vmctx: OwnedVMContext<VMContext>, 27172004aadSNick Fitzgerald } 27272004aadSNick Fitzgerald 27372004aadSNick Fitzgerald impl Instance { 27472004aadSNick Fitzgerald /// Create an instance at the given memory address. 27572004aadSNick Fitzgerald /// 27672004aadSNick Fitzgerald /// It is assumed the memory was properly aligned and the 27772004aadSNick Fitzgerald /// allocation was `alloc_size` in bytes. 2787e28c254SAlex Crichton fn new( 27972004aadSNick Fitzgerald req: InstanceAllocationRequest, 28072004aadSNick Fitzgerald memories: PrimaryMap<DefinedMemoryIndex, (MemoryAllocationIndex, Memory)>, 28172004aadSNick Fitzgerald tables: PrimaryMap<DefinedTableIndex, (TableAllocationIndex, Table)>, 2822a7f0653SAlex Crichton memory_tys: &PrimaryMap<MemoryIndex, wasmtime_environ::Memory>, 28372004aadSNick Fitzgerald ) -> InstanceHandle { 2842bdae8b6SNick Fitzgerald let module = req.runtime_info.env_module(); 28572004aadSNick Fitzgerald let dropped_elements = EntitySet::with_capacity(module.passive_elements.len()); 28672004aadSNick Fitzgerald let dropped_data = EntitySet::with_capacity(module.passive_data_map.len()); 28772004aadSNick Fitzgerald 28872004aadSNick Fitzgerald #[cfg(not(feature = "wmemcheck"))] 2892a7f0653SAlex Crichton let _ = memory_tys; 29072004aadSNick Fitzgerald 2917e28c254SAlex Crichton let mut ret = OwnedInstance::new(Instance { 292ed20d93dSAlex Crichton id: req.id, 29372004aadSNick Fitzgerald runtime_info: req.runtime_info.clone(), 29472004aadSNick Fitzgerald memories, 29572004aadSNick Fitzgerald tables, 29672004aadSNick Fitzgerald dropped_elements, 29772004aadSNick Fitzgerald dropped_data, 29872004aadSNick Fitzgerald #[cfg(feature = "wmemcheck")] 29972004aadSNick Fitzgerald wmemcheck_state: { 30072004aadSNick Fitzgerald if req.wmemcheck { 3012a7f0653SAlex Crichton let size = memory_tys 30272004aadSNick Fitzgerald .iter() 30372004aadSNick Fitzgerald .next() 3042a7f0653SAlex Crichton .map(|memory| memory.1.limits.min) 30572004aadSNick Fitzgerald .unwrap_or(0) 30672004aadSNick Fitzgerald * 64 30772004aadSNick Fitzgerald * 1024; 308838ed2d0SAlex Crichton Some(Wmemcheck::new(size.try_into().unwrap())) 30972004aadSNick Fitzgerald } else { 31072004aadSNick Fitzgerald None 31172004aadSNick Fitzgerald } 31272004aadSNick Fitzgerald }, 313c3559d4aSAlex Crichton store: None, 3147e28c254SAlex Crichton vmctx: OwnedVMContext::new(), 3157e28c254SAlex Crichton }); 31672004aadSNick Fitzgerald 3177e28c254SAlex Crichton // SAFETY: this vmctx was allocated with the same layout above, so it 3187e28c254SAlex Crichton // should be safe to initialize with the same values here. 3197e28c254SAlex Crichton unsafe { 3207e28c254SAlex Crichton ret.get_mut().initialize_vmctx( 3217e28c254SAlex Crichton module, 3227e28c254SAlex Crichton req.runtime_info.offsets(), 3237e28c254SAlex Crichton req.store, 3247e28c254SAlex Crichton req.imports, 3257e28c254SAlex Crichton ); 3267e28c254SAlex Crichton } 327aad93a48SAlex Crichton ret 32872004aadSNick Fitzgerald } 32972004aadSNick Fitzgerald 330f021346eSAlex Crichton /// Converts the provided `*mut VMContext` to an `Instance` pointer and 331f021346eSAlex Crichton /// returns it with the same lifetime as `self`. 33272004aadSNick Fitzgerald /// 333f021346eSAlex Crichton /// This function can be used when traversing a `VMContext` to reach into 334f021346eSAlex Crichton /// the context needed for imports, optionally. 3352b832281SAlex Crichton /// 3362b832281SAlex Crichton /// # Safety 3372b832281SAlex Crichton /// 338f021346eSAlex Crichton /// This function requires that the `vmctx` pointer is indeed valid and 339f021346eSAlex Crichton /// from the store that `self` belongs to. 340f021346eSAlex Crichton #[inline] 341f021346eSAlex Crichton unsafe fn sibling_vmctx<'a>(&'a self, vmctx: NonNull<VMContext>) -> &'a Instance { 342*b052dee0SAlex Crichton // SAFETY: it's a contract of this function itself that `vmctx` is a 343*b052dee0SAlex Crichton // valid pointer such that this pointer arithmetic is valid. 344*b052dee0SAlex Crichton let ptr = unsafe { 345*b052dee0SAlex Crichton vmctx 346f021346eSAlex Crichton .byte_sub(mem::size_of::<Instance>()) 347*b052dee0SAlex Crichton .cast::<Instance>() 348*b052dee0SAlex Crichton }; 349*b052dee0SAlex Crichton // SAFETY: it's a contract of this function itself that `vmctx` is a 350*b052dee0SAlex Crichton // valid pointer to dereference. Additionally the lifetime of the return 351*b052dee0SAlex Crichton // value is constrained to be the same as `self` to avoid granting a 352*b052dee0SAlex Crichton // too-long lifetime. 353*b052dee0SAlex Crichton unsafe { ptr.as_ref() } 354f021346eSAlex Crichton } 355f021346eSAlex Crichton 356f021346eSAlex Crichton /// Same as [`Self::sibling_vmctx`], but the mutable version. 357f021346eSAlex Crichton /// 358f021346eSAlex Crichton /// # Safety 359f021346eSAlex Crichton /// 360f021346eSAlex Crichton /// This function requires that the `vmctx` pointer is indeed valid and 361f021346eSAlex Crichton /// from the store that `self` belongs to. 362f021346eSAlex Crichton #[inline] 363f021346eSAlex Crichton unsafe fn sibling_vmctx_mut<'a>( 364f021346eSAlex Crichton self: Pin<&'a mut Self>, 365f021346eSAlex Crichton vmctx: NonNull<VMContext>, 366f021346eSAlex Crichton ) -> Pin<&'a mut Instance> { 367*b052dee0SAlex Crichton // SAFETY: it's a contract of this function itself that `vmctx` is a 368*b052dee0SAlex Crichton // valid pointer such that this pointer arithmetic is valid. 369*b052dee0SAlex Crichton let mut ptr = unsafe { 370*b052dee0SAlex Crichton vmctx 371f021346eSAlex Crichton .byte_sub(mem::size_of::<Instance>()) 372*b052dee0SAlex Crichton .cast::<Instance>() 373*b052dee0SAlex Crichton }; 374*b052dee0SAlex Crichton 375*b052dee0SAlex Crichton // SAFETY: it's a contract of this function itself that `vmctx` is a 376*b052dee0SAlex Crichton // valid pointer to dereference. Additionally the lifetime of the return 377*b052dee0SAlex Crichton // value is constrained to be the same as `self` to avoid granting a 378*b052dee0SAlex Crichton // too-long lifetime. Finally mutable references to an instance are 379*b052dee0SAlex Crichton // always through `Pin`, so it's safe to create a pin-pointer here. 380*b052dee0SAlex Crichton unsafe { Pin::new_unchecked(ptr.as_mut()) } 3812b832281SAlex Crichton } 3822b832281SAlex Crichton 383c74a7b74SNick Fitzgerald pub(crate) fn env_module(&self) -> &Arc<wasmtime_environ::Module> { 3842bdae8b6SNick Fitzgerald self.runtime_info.env_module() 38572004aadSNick Fitzgerald } 38672004aadSNick Fitzgerald 387a727985cSAlex Crichton #[cfg(feature = "gc")] 388c74a7b74SNick Fitzgerald pub(crate) fn runtime_module(&self) -> Option<&crate::Module> { 389c74a7b74SNick Fitzgerald match &self.runtime_info { 390c74a7b74SNick Fitzgerald ModuleRuntimeInfo::Module(m) => Some(m), 391c74a7b74SNick Fitzgerald ModuleRuntimeInfo::Bare(_) => None, 392c74a7b74SNick Fitzgerald } 393c74a7b74SNick Fitzgerald } 394c74a7b74SNick Fitzgerald 39572004aadSNick Fitzgerald /// Translate a module-level interned type index into an engine-level 39672004aadSNick Fitzgerald /// interned type index. 397cb235ecfSNick Fitzgerald #[cfg(feature = "gc")] 39872004aadSNick Fitzgerald pub fn engine_type_index(&self, module_index: ModuleInternedTypeIndex) -> VMSharedTypeIndex { 39972004aadSNick Fitzgerald self.runtime_info.engine_type_index(module_index) 40072004aadSNick Fitzgerald } 40172004aadSNick Fitzgerald 40272004aadSNick Fitzgerald #[inline] 40372004aadSNick Fitzgerald fn offsets(&self) -> &VMOffsets<HostPtr> { 40472004aadSNick Fitzgerald self.runtime_info.offsets() 40572004aadSNick Fitzgerald } 40672004aadSNick Fitzgerald 40772004aadSNick Fitzgerald /// Return the indexed `VMFunctionImport`. 40872004aadSNick Fitzgerald fn imported_function(&self, index: FuncIndex) -> &VMFunctionImport { 409f1111b91SAlex Crichton unsafe { self.vmctx_plus_offset(self.offsets().vmctx_vmfunction_import(index)) } 41072004aadSNick Fitzgerald } 41172004aadSNick Fitzgerald 41246306693SAlex Crichton /// Return the index `VMTableImport`. 41346306693SAlex Crichton fn imported_table(&self, index: TableIndex) -> &VMTableImport { 414f1111b91SAlex Crichton unsafe { self.vmctx_plus_offset(self.offsets().vmctx_vmtable_import(index)) } 41572004aadSNick Fitzgerald } 41672004aadSNick Fitzgerald 41772004aadSNick Fitzgerald /// Return the indexed `VMMemoryImport`. 41872004aadSNick Fitzgerald fn imported_memory(&self, index: MemoryIndex) -> &VMMemoryImport { 419f1111b91SAlex Crichton unsafe { self.vmctx_plus_offset(self.offsets().vmctx_vmmemory_import(index)) } 42072004aadSNick Fitzgerald } 42172004aadSNick Fitzgerald 42272004aadSNick Fitzgerald /// Return the indexed `VMGlobalImport`. 42372004aadSNick Fitzgerald fn imported_global(&self, index: GlobalIndex) -> &VMGlobalImport { 424f1111b91SAlex Crichton unsafe { self.vmctx_plus_offset(self.offsets().vmctx_vmglobal_import(index)) } 42572004aadSNick Fitzgerald } 42672004aadSNick Fitzgerald 4270b4c754aSDaniel Hillerström /// Return the indexed `VMTagImport`. 4280b4c754aSDaniel Hillerström fn imported_tag(&self, index: TagIndex) -> &VMTagImport { 429f1111b91SAlex Crichton unsafe { self.vmctx_plus_offset(self.offsets().vmctx_vmtag_import(index)) } 4300b4c754aSDaniel Hillerström } 4310b4c754aSDaniel Hillerström 4320b4c754aSDaniel Hillerström /// Return the indexed `VMTagDefinition`. 433d6265b21SAlex Crichton pub fn tag_ptr(&self, index: DefinedTagIndex) -> NonNull<VMTagDefinition> { 434f1111b91SAlex Crichton unsafe { self.vmctx_plus_offset_raw(self.offsets().vmctx_vmtag_definition(index)) } 4350b4c754aSDaniel Hillerström } 4360b4c754aSDaniel Hillerström 43772004aadSNick Fitzgerald /// Return the indexed `VMTableDefinition`. 438a30e7299SAlex Crichton pub fn table(&self, index: DefinedTableIndex) -> VMTableDefinition { 439b86b9682SAlex Crichton unsafe { self.table_ptr(index).read() } 44072004aadSNick Fitzgerald } 44172004aadSNick Fitzgerald 44272004aadSNick Fitzgerald /// Updates the value for a defined table to `VMTableDefinition`. 443aad93a48SAlex Crichton fn set_table(self: Pin<&mut Self>, index: DefinedTableIndex, table: VMTableDefinition) { 44472004aadSNick Fitzgerald unsafe { 445b86b9682SAlex Crichton self.table_ptr(index).write(table); 44672004aadSNick Fitzgerald } 44772004aadSNick Fitzgerald } 44872004aadSNick Fitzgerald 449a30e7299SAlex Crichton /// Return a pointer to the `index`'th table within this instance, stored 450a30e7299SAlex Crichton /// in vmctx memory. 451a30e7299SAlex Crichton pub fn table_ptr(&self, index: DefinedTableIndex) -> NonNull<VMTableDefinition> { 452f1111b91SAlex Crichton unsafe { self.vmctx_plus_offset_raw(self.offsets().vmctx_vmtable_definition(index)) } 45372004aadSNick Fitzgerald } 45472004aadSNick Fitzgerald 45572004aadSNick Fitzgerald /// Get a locally defined or imported memory. 45672004aadSNick Fitzgerald pub(crate) fn get_memory(&self, index: MemoryIndex) -> VMMemoryDefinition { 4572bdae8b6SNick Fitzgerald if let Some(defined_index) = self.env_module().defined_memory_index(index) { 45872004aadSNick Fitzgerald self.memory(defined_index) 45972004aadSNick Fitzgerald } else { 46072004aadSNick Fitzgerald let import = self.imported_memory(index); 461b86b9682SAlex Crichton unsafe { VMMemoryDefinition::load(import.from.as_ptr()) } 46272004aadSNick Fitzgerald } 46372004aadSNick Fitzgerald } 46472004aadSNick Fitzgerald 4650e9a691dSAlex Crichton /// Return the indexed `VMMemoryDefinition`, loaded from vmctx memory 4660e9a691dSAlex Crichton /// already. 4674b518271SAlex Crichton #[inline] 4680e9a691dSAlex Crichton pub fn memory(&self, index: DefinedMemoryIndex) -> VMMemoryDefinition { 469b86b9682SAlex Crichton unsafe { VMMemoryDefinition::load(self.memory_ptr(index).as_ptr()) } 47072004aadSNick Fitzgerald } 47172004aadSNick Fitzgerald 47272004aadSNick Fitzgerald /// Set the indexed memory to `VMMemoryDefinition`. 47372004aadSNick Fitzgerald fn set_memory(&self, index: DefinedMemoryIndex, mem: VMMemoryDefinition) { 47472004aadSNick Fitzgerald unsafe { 475b86b9682SAlex Crichton self.memory_ptr(index).write(mem); 47672004aadSNick Fitzgerald } 47772004aadSNick Fitzgerald } 47872004aadSNick Fitzgerald 4790e9a691dSAlex Crichton /// Return the address of the specified memory at `index` within this vmctx. 4800e9a691dSAlex Crichton /// 4810e9a691dSAlex Crichton /// Note that the returned pointer resides in wasm-code-readable-memory in 4820e9a691dSAlex Crichton /// the vmctx. 4834b518271SAlex Crichton #[inline] 4840e9a691dSAlex Crichton pub fn memory_ptr(&self, index: DefinedMemoryIndex) -> NonNull<VMMemoryDefinition> { 485f1111b91SAlex Crichton unsafe { 486f1111b91SAlex Crichton self.vmctx_plus_offset::<VmPtr<_>>(self.offsets().vmctx_vmmemory_pointer(index)) 487f1111b91SAlex Crichton .as_non_null() 488f1111b91SAlex Crichton } 48972004aadSNick Fitzgerald } 49072004aadSNick Fitzgerald 49172004aadSNick Fitzgerald /// Return the indexed `VMGlobalDefinition`. 492c4fd2f7bSAlex Crichton pub fn global_ptr(&self, index: DefinedGlobalIndex) -> NonNull<VMGlobalDefinition> { 493f1111b91SAlex Crichton unsafe { self.vmctx_plus_offset_raw(self.offsets().vmctx_vmglobal_definition(index)) } 49472004aadSNick Fitzgerald } 49572004aadSNick Fitzgerald 49672004aadSNick Fitzgerald /// Get a raw pointer to the global at the given index regardless whether it 49772004aadSNick Fitzgerald /// is defined locally or imported from another module. 49872004aadSNick Fitzgerald /// 49972004aadSNick Fitzgerald /// Panics if the index is out of bound or is the reserved value. 50072004aadSNick Fitzgerald pub(crate) fn defined_or_imported_global_ptr( 501aad93a48SAlex Crichton self: Pin<&mut Self>, 50272004aadSNick Fitzgerald index: GlobalIndex, 503b86b9682SAlex Crichton ) -> NonNull<VMGlobalDefinition> { 5042bdae8b6SNick Fitzgerald if let Some(index) = self.env_module().defined_global_index(index) { 50572004aadSNick Fitzgerald self.global_ptr(index) 50672004aadSNick Fitzgerald } else { 507b86b9682SAlex Crichton self.imported_global(index).from.as_non_null() 50872004aadSNick Fitzgerald } 50972004aadSNick Fitzgerald } 51072004aadSNick Fitzgerald 51172004aadSNick Fitzgerald /// Get all globals within this instance. 51272004aadSNick Fitzgerald /// 51372004aadSNick Fitzgerald /// Returns both import and defined globals. 51472004aadSNick Fitzgerald /// 51572004aadSNick Fitzgerald /// Returns both exported and non-exported globals. 51672004aadSNick Fitzgerald /// 51772004aadSNick Fitzgerald /// Gives access to the full globals space. 5182b832281SAlex Crichton pub fn all_globals( 5192b832281SAlex Crichton &self, 5202b832281SAlex Crichton store: StoreId, 5212b832281SAlex Crichton ) -> impl ExactSizeIterator<Item = (GlobalIndex, crate::Global)> + '_ { 5222b832281SAlex Crichton let module = self.env_module(); 523c4fd2f7bSAlex Crichton module 524c4fd2f7bSAlex Crichton .globals 525c4fd2f7bSAlex Crichton .keys() 5262b832281SAlex Crichton .map(move |idx| (idx, self.get_exported_global(store, idx))) 52772004aadSNick Fitzgerald } 52872004aadSNick Fitzgerald 52972004aadSNick Fitzgerald /// Get the globals defined in this instance (not imported). 530aad93a48SAlex Crichton pub fn defined_globals( 531aad93a48SAlex Crichton &self, 5322b832281SAlex Crichton store: StoreId, 5332b832281SAlex Crichton ) -> impl ExactSizeIterator<Item = (DefinedGlobalIndex, crate::Global)> + '_ { 5342b832281SAlex Crichton let module = self.env_module(); 5352b832281SAlex Crichton self.all_globals(store) 53672004aadSNick Fitzgerald .skip(module.num_imported_globals) 5372b832281SAlex Crichton .map(move |(i, global)| (module.defined_global_index(i).unwrap(), global)) 53872004aadSNick Fitzgerald } 53972004aadSNick Fitzgerald 54072004aadSNick Fitzgerald /// Return a pointer to the interrupts structure 54172004aadSNick Fitzgerald #[inline] 542aad93a48SAlex Crichton pub fn vm_store_context(&self) -> NonNull<Option<VmPtr<VMStoreContext>>> { 543f1111b91SAlex Crichton unsafe { self.vmctx_plus_offset_raw(self.offsets().ptr.vmctx_store_context()) } 54472004aadSNick Fitzgerald } 54572004aadSNick Fitzgerald 54672004aadSNick Fitzgerald /// Return a pointer to the global epoch counter used by this instance. 54710eda1cfSAlex Crichton #[cfg(target_has_atomic = "64")] 548aad93a48SAlex Crichton pub fn epoch_ptr(self: Pin<&mut Self>) -> &mut Option<VmPtr<AtomicU64>> { 549aad93a48SAlex Crichton let offset = self.offsets().ptr.vmctx_epoch_ptr(); 550aad93a48SAlex Crichton unsafe { self.vmctx_plus_offset_mut(offset) } 55172004aadSNick Fitzgerald } 55272004aadSNick Fitzgerald 55372004aadSNick Fitzgerald /// Return a pointer to the collector-specific heap data. 554aad93a48SAlex Crichton pub fn gc_heap_data(self: Pin<&mut Self>) -> &mut Option<VmPtr<u8>> { 555aad93a48SAlex Crichton let offset = self.offsets().ptr.vmctx_gc_heap_data(); 556aad93a48SAlex Crichton unsafe { self.vmctx_plus_offset_mut(offset) } 55772004aadSNick Fitzgerald } 55872004aadSNick Fitzgerald 559aad93a48SAlex Crichton pub(crate) unsafe fn set_store(mut self: Pin<&mut Self>, store: Option<NonNull<dyn VMStore>>) { 560*b052dee0SAlex Crichton // FIXME: should be more targeted ideally with the `unsafe` than just 561*b052dee0SAlex Crichton // throwing this entire function in a large `unsafe` block. 562*b052dee0SAlex Crichton unsafe { 563aad93a48SAlex Crichton *self.as_mut().store_mut() = store.map(VMStoreRawPtr); 564c3559d4aSAlex Crichton if let Some(mut store) = store { 565c3559d4aSAlex Crichton let store = store.as_mut(); 566c2732814SNick Fitzgerald self.vm_store_context() 567c2732814SNick Fitzgerald .write(Some(store.vm_store_context_ptr().into())); 56810eda1cfSAlex Crichton #[cfg(target_has_atomic = "64")] 569f1111b91SAlex Crichton { 570aad93a48SAlex Crichton *self.as_mut().epoch_ptr() = 571aad93a48SAlex Crichton Some(NonNull::from(store.engine().epoch_counter()).into()); 572f1111b91SAlex Crichton } 573a4700cb7SNick Fitzgerald 574a4700cb7SNick Fitzgerald if self.env_module().needs_gc_heap { 575aad93a48SAlex Crichton self.as_mut().set_gc_heap(Some(store.gc_store().expect( 576a4700cb7SNick Fitzgerald "if we need a GC heap, then `Instance::new_raw` should have already \ 577a4700cb7SNick Fitzgerald allocated it for us", 578a4700cb7SNick Fitzgerald ))); 579a4700cb7SNick Fitzgerald } else { 580aad93a48SAlex Crichton self.as_mut().set_gc_heap(None); 581a4700cb7SNick Fitzgerald } 58272004aadSNick Fitzgerald } else { 583c2732814SNick Fitzgerald self.vm_store_context().write(None); 58410eda1cfSAlex Crichton #[cfg(target_has_atomic = "64")] 585f1111b91SAlex Crichton { 586aad93a48SAlex Crichton *self.as_mut().epoch_ptr() = None; 587f1111b91SAlex Crichton } 588aad93a48SAlex Crichton self.as_mut().set_gc_heap(None); 58972004aadSNick Fitzgerald } 59072004aadSNick Fitzgerald } 591*b052dee0SAlex Crichton } 59272004aadSNick Fitzgerald 593aad93a48SAlex Crichton unsafe fn set_gc_heap(self: Pin<&mut Self>, gc_store: Option<&GcStore>) { 59472004aadSNick Fitzgerald if let Some(gc_store) = gc_store { 595*b052dee0SAlex Crichton *self.gc_heap_data() = Some(unsafe { gc_store.gc_heap.vmctx_gc_heap_data().into() }); 59672004aadSNick Fitzgerald } else { 597f1111b91SAlex Crichton *self.gc_heap_data() = None; 59872004aadSNick Fitzgerald } 59972004aadSNick Fitzgerald } 60072004aadSNick Fitzgerald 60172004aadSNick Fitzgerald /// Return a reference to the vmctx used by compiled wasm code. 60272004aadSNick Fitzgerald #[inline] 603b86b9682SAlex Crichton pub fn vmctx(&self) -> NonNull<VMContext> { 6047e28c254SAlex Crichton InstanceLayout::vmctx(self) 60572004aadSNick Fitzgerald } 60672004aadSNick Fitzgerald 607e012eedaSAlex Crichton /// Lookup a function by index. 608e012eedaSAlex Crichton /// 609e012eedaSAlex Crichton /// # Panics 610e012eedaSAlex Crichton /// 611e012eedaSAlex Crichton /// Panics if `index` is out of bounds for this instance. 6122b832281SAlex Crichton /// 6132b832281SAlex Crichton /// # Safety 6142b832281SAlex Crichton /// 6152b832281SAlex Crichton /// The `store` parameter must be the store that owns this instance and the 6162b832281SAlex Crichton /// functions that this instance can reference. 6172b832281SAlex Crichton pub unsafe fn get_exported_func( 6182b832281SAlex Crichton self: Pin<&mut Self>, 6192b832281SAlex Crichton store: StoreId, 6202b832281SAlex Crichton index: FuncIndex, 6212b832281SAlex Crichton ) -> crate::Func { 62272004aadSNick Fitzgerald let func_ref = self.get_func_ref(index).unwrap(); 6232b832281SAlex Crichton 6242b832281SAlex Crichton // SAFETY: the validity of `func_ref` is guaranteed by the validity of 6252b832281SAlex Crichton // `self`, and the contract that `store` must own `func_ref` is a 6262b832281SAlex Crichton // contract of this function itself. 6272b832281SAlex Crichton unsafe { crate::Func::from_vm_func_ref(store, func_ref) } 62872004aadSNick Fitzgerald } 62972004aadSNick Fitzgerald 630aad93a48SAlex Crichton /// Lookup a table by index. 631aad93a48SAlex Crichton /// 632aad93a48SAlex Crichton /// # Panics 633aad93a48SAlex Crichton /// 634aad93a48SAlex Crichton /// Panics if `index` is out of bounds for this instance. 6352b832281SAlex Crichton pub fn get_exported_table(&self, store: StoreId, index: TableIndex) -> crate::Table { 6362b832281SAlex Crichton let (id, def_index) = if let Some(def_index) = self.env_module().defined_table_index(index) 6372b832281SAlex Crichton { 6382b832281SAlex Crichton (self.id, def_index) 63972004aadSNick Fitzgerald } else { 64072004aadSNick Fitzgerald let import = self.imported_table(index); 6412b832281SAlex Crichton // SAFETY: validity of this `Instance` guarantees validity of the 6422b832281SAlex Crichton // `vmctx` pointer being read here to find the transitive 6432b832281SAlex Crichton // `InstanceId` that the import is associated with. 644f021346eSAlex Crichton let id = unsafe { self.sibling_vmctx(import.vmctx.as_non_null()).id }; 6452b832281SAlex Crichton (id, import.index) 64672004aadSNick Fitzgerald }; 6472b832281SAlex Crichton crate::Table::from_raw(StoreInstanceId::new(store, id), def_index) 64872004aadSNick Fitzgerald } 64972004aadSNick Fitzgerald 650aad93a48SAlex Crichton /// Lookup a memory by index. 651aad93a48SAlex Crichton /// 652aad93a48SAlex Crichton /// # Panics 653aad93a48SAlex Crichton /// 654aad93a48SAlex Crichton /// Panics if `index` is out-of-bounds for this instance. 6552b832281SAlex Crichton pub fn get_exported_memory(&self, store: StoreId, index: MemoryIndex) -> crate::Memory { 6562b832281SAlex Crichton let (id, def_index) = if let Some(def_index) = self.env_module().defined_memory_index(index) 6572b832281SAlex Crichton { 6582b832281SAlex Crichton (self.id, def_index) 65972004aadSNick Fitzgerald } else { 66072004aadSNick Fitzgerald let import = self.imported_memory(index); 6612b832281SAlex Crichton // SAFETY: validity of this `Instance` guarantees validity of the 6622b832281SAlex Crichton // `vmctx` pointer being read here to find the transitive 6632b832281SAlex Crichton // `InstanceId` that the import is associated with. 664f021346eSAlex Crichton let id = unsafe { self.sibling_vmctx(import.vmctx.as_non_null()).id }; 6652b832281SAlex Crichton (id, import.index) 66672004aadSNick Fitzgerald }; 6672b832281SAlex Crichton crate::Memory::from_raw(StoreInstanceId::new(store, id), def_index) 66872004aadSNick Fitzgerald } 66972004aadSNick Fitzgerald 6702b832281SAlex Crichton fn get_exported_global(&self, store: StoreId, index: GlobalIndex) -> crate::Global { 6712b832281SAlex Crichton // If this global is defined within this instance, then that's easy to 6722b832281SAlex Crichton // calculate the `Global`. 673c4fd2f7bSAlex Crichton if let Some(def_index) = self.env_module().defined_global_index(index) { 6742b832281SAlex Crichton let instance = StoreInstanceId::new(store, self.id); 6752b832281SAlex Crichton return crate::Global::from_core(instance, def_index); 676c4fd2f7bSAlex Crichton } 6772b832281SAlex Crichton 6782b832281SAlex Crichton // For imported globals it's required to match on the `kind` to 6792b832281SAlex Crichton // determine which `Global` constructor is going to be invoked. 6802b832281SAlex Crichton let import = self.imported_global(index); 6812b832281SAlex Crichton match import.kind { 6822b832281SAlex Crichton VMGlobalKind::Host(index) => crate::Global::from_host(store, index), 6832b832281SAlex Crichton VMGlobalKind::Instance(index) => { 6842b832281SAlex Crichton // SAFETY: validity of this `&Instance` means validity of its 6852b832281SAlex Crichton // imports meaning we can read the id of the vmctx within. 6862b832281SAlex Crichton let id = unsafe { 6872b832281SAlex Crichton let vmctx = VMContext::from_opaque(import.vmctx.unwrap().as_non_null()); 688f021346eSAlex Crichton self.sibling_vmctx(vmctx).id 6892b832281SAlex Crichton }; 6902b832281SAlex Crichton crate::Global::from_core(StoreInstanceId::new(store, id), index) 6912b832281SAlex Crichton } 6922b832281SAlex Crichton #[cfg(feature = "component-model")] 6932b832281SAlex Crichton VMGlobalKind::ComponentFlags(index) => { 6942b832281SAlex Crichton // SAFETY: validity of this `&Instance` means validity of its 6952b832281SAlex Crichton // imports meaning we can read the id of the vmctx within. 6962b832281SAlex Crichton let id = unsafe { 6972b832281SAlex Crichton let vmctx = super::component::VMComponentContext::from_opaque( 6982b832281SAlex Crichton import.vmctx.unwrap().as_non_null(), 6992b832281SAlex Crichton ); 7002b832281SAlex Crichton super::component::ComponentInstance::vmctx_instance_id(vmctx) 7012b832281SAlex Crichton }; 7022b832281SAlex Crichton crate::Global::from_component_flags( 7032b832281SAlex Crichton crate::component::store::StoreComponentInstanceId::new(store, id), 7042b832281SAlex Crichton index, 7052b832281SAlex Crichton ) 7062b832281SAlex Crichton } 70772004aadSNick Fitzgerald } 70872004aadSNick Fitzgerald } 70972004aadSNick Fitzgerald 710eaa4632eSChris Fallin /// Get an exported tag by index. 711eaa4632eSChris Fallin /// 712eaa4632eSChris Fallin /// # Panics 713eaa4632eSChris Fallin /// 714eaa4632eSChris Fallin /// Panics if the index is out-of-range. 715eaa4632eSChris Fallin pub fn get_exported_tag(&self, store: StoreId, index: TagIndex) -> crate::Tag { 7162b832281SAlex Crichton let (id, def_index) = if let Some(def_index) = self.env_module().defined_tag_index(index) { 7172b832281SAlex Crichton (self.id, def_index) 7180b4c754aSDaniel Hillerström } else { 719598562bdSAlex Crichton let import = self.imported_tag(index); 7202b832281SAlex Crichton // SAFETY: validity of this `Instance` guarantees validity of the 7212b832281SAlex Crichton // `vmctx` pointer being read here to find the transitive 7222b832281SAlex Crichton // `InstanceId` that the import is associated with. 723f021346eSAlex Crichton let id = unsafe { self.sibling_vmctx(import.vmctx.as_non_null()).id }; 7242b832281SAlex Crichton (id, import.index) 725598562bdSAlex Crichton }; 7262b832281SAlex Crichton crate::Tag::from_raw(StoreInstanceId::new(store, id), def_index) 7270b4c754aSDaniel Hillerström } 7280b4c754aSDaniel Hillerström 72972004aadSNick Fitzgerald /// Return an iterator over the exports of this instance. 73072004aadSNick Fitzgerald /// 73172004aadSNick Fitzgerald /// Specifically, it provides access to the key-value pairs, where the keys 73272004aadSNick Fitzgerald /// are export names, and the values are export declarations which can be 73372004aadSNick Fitzgerald /// resolved `lookup_by_declaration`. 7348a42768fSAlex Crichton pub fn exports(&self) -> wasmparser::collections::index_map::Iter<'_, String, EntityIndex> { 7352bdae8b6SNick Fitzgerald self.env_module().exports.iter() 73672004aadSNick Fitzgerald } 73772004aadSNick Fitzgerald 73872004aadSNick Fitzgerald /// Grow memory by the specified amount of pages. 73972004aadSNick Fitzgerald /// 74072004aadSNick Fitzgerald /// Returns `None` if memory can't be grown by the specified amount 74172004aadSNick Fitzgerald /// of pages. Returns `Some` with the old size in bytes if growth was 74272004aadSNick Fitzgerald /// successful. 74372004aadSNick Fitzgerald pub(crate) fn memory_grow( 744aad93a48SAlex Crichton mut self: Pin<&mut Self>, 7458818b251SNick Fitzgerald store: &mut dyn VMStore, 74672004aadSNick Fitzgerald idx: DefinedMemoryIndex, 74772004aadSNick Fitzgerald delta: u64, 74872004aadSNick Fitzgerald ) -> Result<Option<usize>, Error> { 749aad93a48SAlex Crichton let memory = &mut self.as_mut().memories_mut()[idx].1; 75072004aadSNick Fitzgerald 75172004aadSNick Fitzgerald let result = unsafe { memory.grow(delta, Some(store)) }; 75272004aadSNick Fitzgerald 75372004aadSNick Fitzgerald // Update the state used by a non-shared Wasm memory in case the base 75472004aadSNick Fitzgerald // pointer and/or the length changed. 75572004aadSNick Fitzgerald if memory.as_shared_memory().is_none() { 75672004aadSNick Fitzgerald let vmmemory = memory.vmmemory(); 75772004aadSNick Fitzgerald self.set_memory(idx, vmmemory); 75872004aadSNick Fitzgerald } 75972004aadSNick Fitzgerald 76072004aadSNick Fitzgerald result 76172004aadSNick Fitzgerald } 76272004aadSNick Fitzgerald 763aad93a48SAlex Crichton pub(crate) fn table_element_type( 764aad93a48SAlex Crichton self: Pin<&mut Self>, 765aad93a48SAlex Crichton table_index: TableIndex, 766aad93a48SAlex Crichton ) -> TableElementType { 767f021346eSAlex Crichton self.get_table(table_index).element_type() 76872004aadSNick Fitzgerald } 76972004aadSNick Fitzgerald 77072004aadSNick Fitzgerald /// Grow table by the specified amount of elements, filling them with 77172004aadSNick Fitzgerald /// `init_value`. 77272004aadSNick Fitzgerald /// 77372004aadSNick Fitzgerald /// Returns `None` if table can't be grown by the specified amount of 77472004aadSNick Fitzgerald /// elements, or if `init_value` is the wrong type of table element. 7751b571864SAlex Crichton pub(crate) fn defined_table_grow( 776aad93a48SAlex Crichton mut self: Pin<&mut Self>, 7778818b251SNick Fitzgerald store: &mut dyn VMStore, 77872004aadSNick Fitzgerald table_index: DefinedTableIndex, 779df69b9a7SLinwei Shang delta: u64, 78072004aadSNick Fitzgerald init_value: TableElement, 781df69b9a7SLinwei Shang ) -> Result<Option<usize>, Error> { 78272004aadSNick Fitzgerald let table = &mut self 783aad93a48SAlex Crichton .as_mut() 784aad93a48SAlex Crichton .tables_mut() 78572004aadSNick Fitzgerald .get_mut(table_index) 78672004aadSNick Fitzgerald .unwrap_or_else(|| panic!("no table for index {}", table_index.index())) 78772004aadSNick Fitzgerald .1; 78872004aadSNick Fitzgerald 78972004aadSNick Fitzgerald let result = unsafe { table.grow(delta, init_value, store) }; 79072004aadSNick Fitzgerald 79172004aadSNick Fitzgerald // Keep the `VMContext` pointers used by compiled Wasm code up to 79272004aadSNick Fitzgerald // date. 793aad93a48SAlex Crichton let element = table.vmtable(); 79472004aadSNick Fitzgerald self.set_table(table_index, element); 79572004aadSNick Fitzgerald 79672004aadSNick Fitzgerald result 79772004aadSNick Fitzgerald } 79872004aadSNick Fitzgerald 79972004aadSNick Fitzgerald fn alloc_layout(offsets: &VMOffsets<HostPtr>) -> Layout { 80072004aadSNick Fitzgerald let size = mem::size_of::<Self>() 80172004aadSNick Fitzgerald .checked_add(usize::try_from(offsets.size_of_vmctx()).unwrap()) 80272004aadSNick Fitzgerald .unwrap(); 80372004aadSNick Fitzgerald let align = mem::align_of::<Self>(); 80472004aadSNick Fitzgerald Layout::from_size_align(size, align).unwrap() 80572004aadSNick Fitzgerald } 80672004aadSNick Fitzgerald 807aad93a48SAlex Crichton fn type_ids_array(&self) -> NonNull<VmPtr<VMSharedTypeIndex>> { 808f1111b91SAlex Crichton unsafe { self.vmctx_plus_offset_raw(self.offsets().ptr.vmctx_type_ids_array()) } 809b86b9682SAlex Crichton } 810b86b9682SAlex Crichton 81172004aadSNick Fitzgerald /// Construct a new VMFuncRef for the given function 81272004aadSNick Fitzgerald /// (imported or defined in this module) and store into the given 81372004aadSNick Fitzgerald /// location. Used during lazy initialization. 81472004aadSNick Fitzgerald /// 81572004aadSNick Fitzgerald /// Note that our current lazy-init scheme actually calls this every 81672004aadSNick Fitzgerald /// time the funcref pointer is fetched; this turns out to be better 81772004aadSNick Fitzgerald /// than tracking state related to whether it's been initialized 81872004aadSNick Fitzgerald /// before, because resetting that state on (re)instantiation is 81972004aadSNick Fitzgerald /// very expensive if there are many funcrefs. 820078bc37bSAlex Crichton /// 821078bc37bSAlex Crichton /// # Safety 822078bc37bSAlex Crichton /// 823078bc37bSAlex Crichton /// This functions requires that `into` is a valid pointer. 824078bc37bSAlex Crichton unsafe fn construct_func_ref( 825078bc37bSAlex Crichton self: Pin<&mut Self>, 82672004aadSNick Fitzgerald index: FuncIndex, 827cb235ecfSNick Fitzgerald type_index: VMSharedTypeIndex, 82872004aadSNick Fitzgerald into: *mut VMFuncRef, 82972004aadSNick Fitzgerald ) { 8302bdae8b6SNick Fitzgerald let func_ref = if let Some(def_index) = self.env_module().defined_func_index(index) { 83172004aadSNick Fitzgerald VMFuncRef { 83272004aadSNick Fitzgerald array_call: self 83372004aadSNick Fitzgerald .runtime_info 83472004aadSNick Fitzgerald .array_to_wasm_trampoline(def_index) 835b86b9682SAlex Crichton .expect("should have array-to-Wasm trampoline for escaping function") 836b86b9682SAlex Crichton .into(), 837b86b9682SAlex Crichton wasm_call: Some(self.runtime_info.function(def_index).into()), 838b86b9682SAlex Crichton vmctx: VMOpaqueContext::from_vmcontext(self.vmctx()).into(), 83972004aadSNick Fitzgerald type_index, 84072004aadSNick Fitzgerald } 84172004aadSNick Fitzgerald } else { 84272004aadSNick Fitzgerald let import = self.imported_function(index); 84372004aadSNick Fitzgerald VMFuncRef { 84472004aadSNick Fitzgerald array_call: import.array_call, 84572004aadSNick Fitzgerald wasm_call: Some(import.wasm_call), 84672004aadSNick Fitzgerald vmctx: import.vmctx, 84772004aadSNick Fitzgerald type_index, 84872004aadSNick Fitzgerald } 84972004aadSNick Fitzgerald }; 85072004aadSNick Fitzgerald 851078bc37bSAlex Crichton // SAFETY: the unsafe contract here is forwarded to callers of this 852078bc37bSAlex Crichton // function. 85372004aadSNick Fitzgerald unsafe { 85481a89169SAlex Crichton ptr::write(into, func_ref); 85572004aadSNick Fitzgerald } 85672004aadSNick Fitzgerald } 85772004aadSNick Fitzgerald 85872004aadSNick Fitzgerald /// Get a `&VMFuncRef` for the given `FuncIndex`. 85972004aadSNick Fitzgerald /// 86072004aadSNick Fitzgerald /// Returns `None` if the index is the reserved index value. 86172004aadSNick Fitzgerald /// 86272004aadSNick Fitzgerald /// The returned reference is a stable reference that won't be moved and can 86372004aadSNick Fitzgerald /// be passed into JIT code. 864078bc37bSAlex Crichton pub(crate) fn get_func_ref( 865078bc37bSAlex Crichton self: Pin<&mut Self>, 866078bc37bSAlex Crichton index: FuncIndex, 867078bc37bSAlex Crichton ) -> Option<NonNull<VMFuncRef>> { 86872004aadSNick Fitzgerald if index == FuncIndex::reserved_value() { 86972004aadSNick Fitzgerald return None; 87072004aadSNick Fitzgerald } 87172004aadSNick Fitzgerald 87272004aadSNick Fitzgerald // For now, we eagerly initialize an funcref struct in-place 87372004aadSNick Fitzgerald // whenever asked for a reference to it. This is mostly 87472004aadSNick Fitzgerald // fine, because in practice each funcref is unlikely to be 87572004aadSNick Fitzgerald // requested more than a few times: once-ish for funcref 87672004aadSNick Fitzgerald // tables used for call_indirect (the usual compilation 87772004aadSNick Fitzgerald // strategy places each function in the table at most once), 87872004aadSNick Fitzgerald // and once or a few times when fetching exports via API. 87972004aadSNick Fitzgerald // Note that for any case driven by table accesses, the lazy 88072004aadSNick Fitzgerald // table init behaves like a higher-level cache layer that 88172004aadSNick Fitzgerald // protects this initialization from happening multiple 88272004aadSNick Fitzgerald // times, via that particular table at least. 88372004aadSNick Fitzgerald // 88472004aadSNick Fitzgerald // When `ref.func` becomes more commonly used or if we 88572004aadSNick Fitzgerald // otherwise see a use-case where this becomes a hotpath, 88672004aadSNick Fitzgerald // we can reconsider by using some state to track 88772004aadSNick Fitzgerald // "uninitialized" explicitly, for example by zeroing the 88872004aadSNick Fitzgerald // funcrefs (perhaps together with other 88972004aadSNick Fitzgerald // zeroed-at-instantiate-time state) or using a separate 89072004aadSNick Fitzgerald // is-initialized bitmap. 89172004aadSNick Fitzgerald // 89272004aadSNick Fitzgerald // We arrived at this design because zeroing memory is 89372004aadSNick Fitzgerald // expensive, so it's better for instantiation performance 89472004aadSNick Fitzgerald // if we don't have to track "is-initialized" state at 89572004aadSNick Fitzgerald // all! 8962bdae8b6SNick Fitzgerald let func = &self.env_module().functions[index]; 897cb235ecfSNick Fitzgerald let sig = func.signature.unwrap_engine_type_index(); 898078bc37bSAlex Crichton 899078bc37bSAlex Crichton // SAFETY: the offset calculated here should be correct with 900078bc37bSAlex Crichton // `self.offsets` 901078bc37bSAlex Crichton let func_ref = unsafe { 902078bc37bSAlex Crichton self.vmctx_plus_offset_raw::<VMFuncRef>(self.offsets().vmctx_func_ref(func.func_ref)) 903078bc37bSAlex Crichton }; 904078bc37bSAlex Crichton 905078bc37bSAlex Crichton // SAFETY: the `func_ref` ptr should be valid as it's within our 906078bc37bSAlex Crichton // `VMContext` area. 907078bc37bSAlex Crichton unsafe { 908b86b9682SAlex Crichton self.construct_func_ref(index, sig, func_ref.as_ptr()); 909078bc37bSAlex Crichton } 91072004aadSNick Fitzgerald 911b86b9682SAlex Crichton Some(func_ref) 91272004aadSNick Fitzgerald } 91372004aadSNick Fitzgerald 914ec3b2d22SNick Fitzgerald /// Get the passive elements segment at the given index. 915ec3b2d22SNick Fitzgerald /// 916ec3b2d22SNick Fitzgerald /// Returns an empty segment if the index is out of bounds or if the segment 917ec3b2d22SNick Fitzgerald /// has been dropped. 918ec3b2d22SNick Fitzgerald /// 919ec3b2d22SNick Fitzgerald /// The `storage` parameter should always be `None`; it is a bit of a hack 920ec3b2d22SNick Fitzgerald /// to work around lifetime issues. 921ec3b2d22SNick Fitzgerald pub(crate) fn passive_element_segment<'a>( 922ec3b2d22SNick Fitzgerald &self, 923ec3b2d22SNick Fitzgerald storage: &'a mut Option<(Arc<wasmtime_environ::Module>, TableSegmentElements)>, 924ec3b2d22SNick Fitzgerald elem_index: ElemIndex, 925ec3b2d22SNick Fitzgerald ) -> &'a TableSegmentElements { 926ec3b2d22SNick Fitzgerald debug_assert!(storage.is_none()); 927ec3b2d22SNick Fitzgerald *storage = Some(( 928ec3b2d22SNick Fitzgerald // TODO: this `clone()` shouldn't be necessary but is used for now to 929ec3b2d22SNick Fitzgerald // inform `rustc` that the lifetime of the elements here are 930ec3b2d22SNick Fitzgerald // disconnected from the lifetime of `self`. 931ec3b2d22SNick Fitzgerald self.env_module().clone(), 932ec3b2d22SNick Fitzgerald // NB: fall back to an expressions-based list of elements which 933ec3b2d22SNick Fitzgerald // doesn't have static type information (as opposed to 934ec3b2d22SNick Fitzgerald // `TableSegmentElements::Functions`) since we don't know what type 935ec3b2d22SNick Fitzgerald // is needed in the caller's context. Let the type be inferred by 936ec3b2d22SNick Fitzgerald // how they use the segment. 937ec3b2d22SNick Fitzgerald TableSegmentElements::Expressions(Box::new([])), 938ec3b2d22SNick Fitzgerald )); 939ec3b2d22SNick Fitzgerald let (module, empty) = storage.as_ref().unwrap(); 940ec3b2d22SNick Fitzgerald 941ec3b2d22SNick Fitzgerald match module.passive_elements_map.get(&elem_index) { 942ec3b2d22SNick Fitzgerald Some(index) if !self.dropped_elements.contains(elem_index) => { 943ec3b2d22SNick Fitzgerald &module.passive_elements[*index] 944ec3b2d22SNick Fitzgerald } 945ec3b2d22SNick Fitzgerald _ => empty, 946ec3b2d22SNick Fitzgerald } 947ec3b2d22SNick Fitzgerald } 948ec3b2d22SNick Fitzgerald 94972004aadSNick Fitzgerald /// The `table.init` operation: initializes a portion of a table with a 95072004aadSNick Fitzgerald /// passive element. 95172004aadSNick Fitzgerald /// 95272004aadSNick Fitzgerald /// # Errors 95372004aadSNick Fitzgerald /// 95472004aadSNick Fitzgerald /// Returns a `Trap` error when the range within the table is out of bounds 95572004aadSNick Fitzgerald /// or the range within the passive element is out of bounds. 95672004aadSNick Fitzgerald pub(crate) fn table_init( 957aad93a48SAlex Crichton self: Pin<&mut Self>, 9588818b251SNick Fitzgerald store: &mut StoreOpaque, 95972004aadSNick Fitzgerald table_index: TableIndex, 96072004aadSNick Fitzgerald elem_index: ElemIndex, 961df69b9a7SLinwei Shang dst: u64, 962df69b9a7SLinwei Shang src: u64, 963df69b9a7SLinwei Shang len: u64, 96472004aadSNick Fitzgerald ) -> Result<(), Trap> { 965ec3b2d22SNick Fitzgerald let mut storage = None; 966ec3b2d22SNick Fitzgerald let elements = self.passive_element_segment(&mut storage, elem_index); 96772004aadSNick Fitzgerald let mut const_evaluator = ConstExprEvaluator::default(); 968aad93a48SAlex Crichton Self::table_init_segment( 9698818b251SNick Fitzgerald store, 970aad93a48SAlex Crichton self.id, 9718818b251SNick Fitzgerald &mut const_evaluator, 9728818b251SNick Fitzgerald table_index, 9738818b251SNick Fitzgerald elements, 9748818b251SNick Fitzgerald dst, 9758818b251SNick Fitzgerald src, 9768818b251SNick Fitzgerald len, 9778818b251SNick Fitzgerald ) 97872004aadSNick Fitzgerald } 97972004aadSNick Fitzgerald 98072004aadSNick Fitzgerald pub(crate) fn table_init_segment( 9818818b251SNick Fitzgerald store: &mut StoreOpaque, 982f021346eSAlex Crichton elements_instance_id: InstanceId, 98372004aadSNick Fitzgerald const_evaluator: &mut ConstExprEvaluator, 98472004aadSNick Fitzgerald table_index: TableIndex, 98572004aadSNick Fitzgerald elements: &TableSegmentElements, 986df69b9a7SLinwei Shang dst: u64, 987df69b9a7SLinwei Shang src: u64, 988df69b9a7SLinwei Shang len: u64, 98972004aadSNick Fitzgerald ) -> Result<(), Trap> { 99072004aadSNick Fitzgerald // https://webassembly.github.io/bulk-memory-operations/core/exec/instructions.html#exec-table-init 99172004aadSNick Fitzgerald 992f021346eSAlex Crichton let elements_instance = store.instance_mut(elements_instance_id); 993f021346eSAlex Crichton let elements_module = elements_instance.env_module(); 994f021346eSAlex Crichton let top = elements_module.tables[table_index].ref_type.heap_type.top(); 995f021346eSAlex Crichton let (defined_table_index, mut table_instance) = 996f021346eSAlex Crichton elements_instance.defined_table_index_and_instance(table_index); 997f021346eSAlex Crichton let table_instance_id = table_instance.id; 998f021346eSAlex Crichton 99972004aadSNick Fitzgerald let src = usize::try_from(src).map_err(|_| Trap::TableOutOfBounds)?; 100072004aadSNick Fitzgerald let len = usize::try_from(len).map_err(|_| Trap::TableOutOfBounds)?; 1001f021346eSAlex Crichton 1002f021346eSAlex Crichton // In the initialization below we need to simultaneously have a mutable 1003f021346eSAlex Crichton // borrow on the `Table` that we're initializing and the `StoreOpaque` 1004f021346eSAlex Crichton // that it comes from. To solve this the tables are temporarily removed 1005f021346eSAlex Crichton // from the instance at `id` to be re-inserted at the end of this 1006f021346eSAlex Crichton // function via a `Drop` helper. The table and the store are then 1007f021346eSAlex Crichton // accessed through the drop helper below. 1008f021346eSAlex Crichton // 1009f021346eSAlex Crichton // This will cause a runtime panic if the table is actually accessed 1010f021346eSAlex Crichton // during the lifetime of the functions below, but that's a bug if that 1011f021346eSAlex Crichton // happens which needs to be fixed anyway. 1012f021346eSAlex Crichton let tables = mem::replace(table_instance.as_mut().tables_mut(), PrimaryMap::new()); 1013f021346eSAlex Crichton let mut replace = ReplaceTables { 1014f021346eSAlex Crichton tables, 1015f021346eSAlex Crichton id: table_instance_id, 1016f021346eSAlex Crichton store, 1017f021346eSAlex Crichton }; 1018f021346eSAlex Crichton 1019f021346eSAlex Crichton struct ReplaceTables<'a> { 1020f021346eSAlex Crichton tables: PrimaryMap<DefinedTableIndex, (TableAllocationIndex, Table)>, 1021f021346eSAlex Crichton id: InstanceId, 1022f021346eSAlex Crichton store: &'a mut StoreOpaque, 1023f021346eSAlex Crichton } 1024f021346eSAlex Crichton 1025f021346eSAlex Crichton impl Drop for ReplaceTables<'_> { 1026f021346eSAlex Crichton fn drop(&mut self) { 1027f021346eSAlex Crichton mem::swap( 1028f021346eSAlex Crichton self.store.instance_mut(self.id).tables_mut(), 1029f021346eSAlex Crichton &mut self.tables, 1030f021346eSAlex Crichton ); 1031f021346eSAlex Crichton debug_assert!(self.tables.is_empty()); 1032f021346eSAlex Crichton } 1033f021346eSAlex Crichton } 1034f021346eSAlex Crichton 1035f021346eSAlex Crichton // Reborrow the table/store from `replace` for the below code. 1036f021346eSAlex Crichton let table = &mut replace.tables[defined_table_index].1; 1037f021346eSAlex Crichton let store = &mut *replace.store; 103872004aadSNick Fitzgerald 103972004aadSNick Fitzgerald match elements { 104072004aadSNick Fitzgerald TableSegmentElements::Functions(funcs) => { 1041f021346eSAlex Crichton let mut instance = store.instance_mut(elements_instance_id); 104272004aadSNick Fitzgerald let elements = funcs 104372004aadSNick Fitzgerald .get(src..) 104472004aadSNick Fitzgerald .and_then(|s| s.get(..len)) 104572004aadSNick Fitzgerald .ok_or(Trap::TableOutOfBounds)?; 1046078bc37bSAlex Crichton table.init_func( 1047078bc37bSAlex Crichton dst, 1048078bc37bSAlex Crichton elements 1049078bc37bSAlex Crichton .iter() 1050078bc37bSAlex Crichton .map(|idx| instance.as_mut().get_func_ref(*idx)), 1051078bc37bSAlex Crichton )?; 105272004aadSNick Fitzgerald } 105372004aadSNick Fitzgerald TableSegmentElements::Expressions(exprs) => { 105472004aadSNick Fitzgerald let exprs = exprs 105572004aadSNick Fitzgerald .get(src..) 105672004aadSNick Fitzgerald .and_then(|s| s.get(..len)) 105772004aadSNick Fitzgerald .ok_or(Trap::TableOutOfBounds)?; 1058f021346eSAlex Crichton let mut context = ConstEvalContext::new(elements_instance_id); 1059aad93a48SAlex Crichton match top { 106072004aadSNick Fitzgerald WasmHeapTopType::Extern => table.init_gc_refs( 106172004aadSNick Fitzgerald dst, 106272004aadSNick Fitzgerald exprs.iter().map(|expr| unsafe { 106372004aadSNick Fitzgerald let raw = const_evaluator 10648818b251SNick Fitzgerald .eval(store, &mut context, expr) 106572004aadSNick Fitzgerald .expect("const expr should be valid"); 106672004aadSNick Fitzgerald VMGcRef::from_raw_u32(raw.get_externref()) 106772004aadSNick Fitzgerald }), 106872004aadSNick Fitzgerald )?, 1069eaa4632eSChris Fallin WasmHeapTopType::Any | WasmHeapTopType::Exn => table.init_gc_refs( 107072004aadSNick Fitzgerald dst, 107172004aadSNick Fitzgerald exprs.iter().map(|expr| unsafe { 107272004aadSNick Fitzgerald let raw = const_evaluator 10738818b251SNick Fitzgerald .eval(store, &mut context, expr) 107472004aadSNick Fitzgerald .expect("const expr should be valid"); 107572004aadSNick Fitzgerald VMGcRef::from_raw_u32(raw.get_anyref()) 107672004aadSNick Fitzgerald }), 107772004aadSNick Fitzgerald )?, 107872004aadSNick Fitzgerald WasmHeapTopType::Func => table.init_func( 107972004aadSNick Fitzgerald dst, 108072004aadSNick Fitzgerald exprs.iter().map(|expr| unsafe { 1081c52b941eSAlex Crichton NonNull::new( 108272004aadSNick Fitzgerald const_evaluator 10838818b251SNick Fitzgerald .eval(store, &mut context, expr) 108472004aadSNick Fitzgerald .expect("const expr should be valid") 108572004aadSNick Fitzgerald .get_funcref() 1086c52b941eSAlex Crichton .cast(), 1087c52b941eSAlex Crichton ) 108872004aadSNick Fitzgerald }), 108972004aadSNick Fitzgerald )?, 1090692490b8SDaniel Hillerström WasmHeapTopType::Cont => todo!(), // FIXME: #10248 stack switching support. 109172004aadSNick Fitzgerald } 109272004aadSNick Fitzgerald } 109372004aadSNick Fitzgerald } 109472004aadSNick Fitzgerald 109572004aadSNick Fitzgerald Ok(()) 109672004aadSNick Fitzgerald } 109772004aadSNick Fitzgerald 109872004aadSNick Fitzgerald /// Drop an element. 1099aad93a48SAlex Crichton pub(crate) fn elem_drop(self: Pin<&mut Self>, elem_index: ElemIndex) { 110072004aadSNick Fitzgerald // https://webassembly.github.io/reference-types/core/exec/instructions.html#exec-elem-drop 110172004aadSNick Fitzgerald 1102aad93a48SAlex Crichton self.dropped_elements_mut().insert(elem_index); 110372004aadSNick Fitzgerald 110472004aadSNick Fitzgerald // Note that we don't check that we actually removed a segment because 110572004aadSNick Fitzgerald // dropping a non-passive segment is a no-op (not a trap). 110672004aadSNick Fitzgerald } 110772004aadSNick Fitzgerald 110872004aadSNick Fitzgerald /// Get a locally-defined memory. 11092b832281SAlex Crichton pub fn get_defined_memory_mut(self: Pin<&mut Self>, index: DefinedMemoryIndex) -> &mut Memory { 1110ab76f64bSAlex Crichton &mut self.memories_mut()[index].1 111172004aadSNick Fitzgerald } 111272004aadSNick Fitzgerald 11132b832281SAlex Crichton /// Get a locally-defined memory. 11142b832281SAlex Crichton pub fn get_defined_memory(&self, index: DefinedMemoryIndex) -> &Memory { 11152b832281SAlex Crichton &self.memories[index].1 11162b832281SAlex Crichton } 11172b832281SAlex Crichton 111872004aadSNick Fitzgerald /// Do a `memory.copy` 111972004aadSNick Fitzgerald /// 112072004aadSNick Fitzgerald /// # Errors 112172004aadSNick Fitzgerald /// 112272004aadSNick Fitzgerald /// Returns a `Trap` error when the source or destination ranges are out of 112372004aadSNick Fitzgerald /// bounds. 112472004aadSNick Fitzgerald pub(crate) fn memory_copy( 1125aad93a48SAlex Crichton self: Pin<&mut Self>, 112672004aadSNick Fitzgerald dst_index: MemoryIndex, 112772004aadSNick Fitzgerald dst: u64, 112872004aadSNick Fitzgerald src_index: MemoryIndex, 112972004aadSNick Fitzgerald src: u64, 113072004aadSNick Fitzgerald len: u64, 113172004aadSNick Fitzgerald ) -> Result<(), Trap> { 113272004aadSNick Fitzgerald // https://webassembly.github.io/reference-types/core/exec/instructions.html#exec-memory-copy 113372004aadSNick Fitzgerald 113472004aadSNick Fitzgerald let src_mem = self.get_memory(src_index); 113572004aadSNick Fitzgerald let dst_mem = self.get_memory(dst_index); 113672004aadSNick Fitzgerald 113772004aadSNick Fitzgerald let src = self.validate_inbounds(src_mem.current_length(), src, len)?; 113872004aadSNick Fitzgerald let dst = self.validate_inbounds(dst_mem.current_length(), dst, len)?; 11390bce0968SAlex Crichton let len = usize::try_from(len).unwrap(); 114072004aadSNick Fitzgerald 114172004aadSNick Fitzgerald // Bounds and casts are checked above, by this point we know that 114272004aadSNick Fitzgerald // everything is safe. 114372004aadSNick Fitzgerald unsafe { 1144b86b9682SAlex Crichton let dst = dst_mem.base.as_ptr().add(dst); 1145b86b9682SAlex Crichton let src = src_mem.base.as_ptr().add(src); 114672004aadSNick Fitzgerald // FIXME audit whether this is safe in the presence of shared memory 114772004aadSNick Fitzgerald // (https://github.com/bytecodealliance/wasmtime/issues/4203). 11480bce0968SAlex Crichton ptr::copy(src, dst, len); 114972004aadSNick Fitzgerald } 115072004aadSNick Fitzgerald 115172004aadSNick Fitzgerald Ok(()) 115272004aadSNick Fitzgerald } 115372004aadSNick Fitzgerald 115472004aadSNick Fitzgerald fn validate_inbounds(&self, max: usize, ptr: u64, len: u64) -> Result<usize, Trap> { 115572004aadSNick Fitzgerald let oob = || Trap::MemoryOutOfBounds; 115672004aadSNick Fitzgerald let end = ptr 115772004aadSNick Fitzgerald .checked_add(len) 115872004aadSNick Fitzgerald .and_then(|i| usize::try_from(i).ok()) 115972004aadSNick Fitzgerald .ok_or_else(oob)?; 116072004aadSNick Fitzgerald if end > max { 116172004aadSNick Fitzgerald Err(oob()) 116272004aadSNick Fitzgerald } else { 11630bce0968SAlex Crichton Ok(ptr.try_into().unwrap()) 116472004aadSNick Fitzgerald } 116572004aadSNick Fitzgerald } 116672004aadSNick Fitzgerald 116772004aadSNick Fitzgerald /// Perform the `memory.fill` operation on a locally defined memory. 116872004aadSNick Fitzgerald /// 116972004aadSNick Fitzgerald /// # Errors 117072004aadSNick Fitzgerald /// 117172004aadSNick Fitzgerald /// Returns a `Trap` error if the memory range is out of bounds. 117272004aadSNick Fitzgerald pub(crate) fn memory_fill( 1173aad93a48SAlex Crichton self: Pin<&mut Self>, 1174ab76f64bSAlex Crichton memory_index: DefinedMemoryIndex, 117572004aadSNick Fitzgerald dst: u64, 117672004aadSNick Fitzgerald val: u8, 117772004aadSNick Fitzgerald len: u64, 117872004aadSNick Fitzgerald ) -> Result<(), Trap> { 1179ab76f64bSAlex Crichton let memory_index = self.env_module().memory_index(memory_index); 118072004aadSNick Fitzgerald let memory = self.get_memory(memory_index); 118172004aadSNick Fitzgerald let dst = self.validate_inbounds(memory.current_length(), dst, len)?; 11820bce0968SAlex Crichton let len = usize::try_from(len).unwrap(); 118372004aadSNick Fitzgerald 118472004aadSNick Fitzgerald // Bounds and casts are checked above, by this point we know that 118572004aadSNick Fitzgerald // everything is safe. 118672004aadSNick Fitzgerald unsafe { 1187b86b9682SAlex Crichton let dst = memory.base.as_ptr().add(dst); 118872004aadSNick Fitzgerald // FIXME audit whether this is safe in the presence of shared memory 118972004aadSNick Fitzgerald // (https://github.com/bytecodealliance/wasmtime/issues/4203). 11900bce0968SAlex Crichton ptr::write_bytes(dst, val, len); 119172004aadSNick Fitzgerald } 119272004aadSNick Fitzgerald 119372004aadSNick Fitzgerald Ok(()) 119472004aadSNick Fitzgerald } 119572004aadSNick Fitzgerald 1196ec3b2d22SNick Fitzgerald /// Get the internal storage range of a particular Wasm data segment. 1197ec3b2d22SNick Fitzgerald pub(crate) fn wasm_data_range(&self, index: DataIndex) -> Range<u32> { 1198ec3b2d22SNick Fitzgerald match self.env_module().passive_data_map.get(&index) { 1199ec3b2d22SNick Fitzgerald Some(range) if !self.dropped_data.contains(index) => range.clone(), 1200ec3b2d22SNick Fitzgerald _ => 0..0, 1201ec3b2d22SNick Fitzgerald } 1202ec3b2d22SNick Fitzgerald } 1203ec3b2d22SNick Fitzgerald 1204ec3b2d22SNick Fitzgerald /// Given an internal storage range of a Wasm data segment (or subset of a 1205ec3b2d22SNick Fitzgerald /// Wasm data segment), get the data's raw bytes. 1206ec3b2d22SNick Fitzgerald pub(crate) fn wasm_data(&self, range: Range<u32>) -> &[u8] { 1207ec3b2d22SNick Fitzgerald let start = usize::try_from(range.start).unwrap(); 1208ec3b2d22SNick Fitzgerald let end = usize::try_from(range.end).unwrap(); 1209ec3b2d22SNick Fitzgerald &self.runtime_info.wasm_data()[start..end] 1210ec3b2d22SNick Fitzgerald } 1211ec3b2d22SNick Fitzgerald 121272004aadSNick Fitzgerald /// Performs the `memory.init` operation. 121372004aadSNick Fitzgerald /// 121472004aadSNick Fitzgerald /// # Errors 121572004aadSNick Fitzgerald /// 121672004aadSNick Fitzgerald /// Returns a `Trap` error if the destination range is out of this module's 121772004aadSNick Fitzgerald /// memory's bounds or if the source range is outside the data segment's 121872004aadSNick Fitzgerald /// bounds. 121972004aadSNick Fitzgerald pub(crate) fn memory_init( 1220aad93a48SAlex Crichton self: Pin<&mut Self>, 122172004aadSNick Fitzgerald memory_index: MemoryIndex, 122272004aadSNick Fitzgerald data_index: DataIndex, 122372004aadSNick Fitzgerald dst: u64, 122472004aadSNick Fitzgerald src: u32, 122572004aadSNick Fitzgerald len: u32, 122672004aadSNick Fitzgerald ) -> Result<(), Trap> { 1227ec3b2d22SNick Fitzgerald let range = self.wasm_data_range(data_index); 122872004aadSNick Fitzgerald self.memory_init_segment(memory_index, range, dst, src, len) 122972004aadSNick Fitzgerald } 123072004aadSNick Fitzgerald 123172004aadSNick Fitzgerald pub(crate) fn memory_init_segment( 1232aad93a48SAlex Crichton self: Pin<&mut Self>, 123372004aadSNick Fitzgerald memory_index: MemoryIndex, 123472004aadSNick Fitzgerald range: Range<u32>, 123572004aadSNick Fitzgerald dst: u64, 123672004aadSNick Fitzgerald src: u32, 123772004aadSNick Fitzgerald len: u32, 123872004aadSNick Fitzgerald ) -> Result<(), Trap> { 123972004aadSNick Fitzgerald // https://webassembly.github.io/bulk-memory-operations/core/exec/instructions.html#exec-memory-init 124072004aadSNick Fitzgerald 124172004aadSNick Fitzgerald let memory = self.get_memory(memory_index); 124272004aadSNick Fitzgerald let data = self.wasm_data(range); 124372004aadSNick Fitzgerald let dst = self.validate_inbounds(memory.current_length(), dst, len.into())?; 124472004aadSNick Fitzgerald let src = self.validate_inbounds(data.len(), src.into(), len.into())?; 124572004aadSNick Fitzgerald let len = len as usize; 124672004aadSNick Fitzgerald 124772004aadSNick Fitzgerald unsafe { 124872004aadSNick Fitzgerald let src_start = data.as_ptr().add(src); 1249b86b9682SAlex Crichton let dst_start = memory.base.as_ptr().add(dst); 125072004aadSNick Fitzgerald // FIXME audit whether this is safe in the presence of shared memory 125172004aadSNick Fitzgerald // (https://github.com/bytecodealliance/wasmtime/issues/4203). 125272004aadSNick Fitzgerald ptr::copy_nonoverlapping(src_start, dst_start, len); 125372004aadSNick Fitzgerald } 125472004aadSNick Fitzgerald 125572004aadSNick Fitzgerald Ok(()) 125672004aadSNick Fitzgerald } 125772004aadSNick Fitzgerald 125872004aadSNick Fitzgerald /// Drop the given data segment, truncating its length to zero. 1259aad93a48SAlex Crichton pub(crate) fn data_drop(self: Pin<&mut Self>, data_index: DataIndex) { 1260aad93a48SAlex Crichton self.dropped_data_mut().insert(data_index); 126172004aadSNick Fitzgerald 126272004aadSNick Fitzgerald // Note that we don't check that we actually removed a segment because 126372004aadSNick Fitzgerald // dropping a non-passive segment is a no-op (not a trap). 126472004aadSNick Fitzgerald } 126572004aadSNick Fitzgerald 126672004aadSNick Fitzgerald /// Get a table by index regardless of whether it is locally-defined 126772004aadSNick Fitzgerald /// or an imported, foreign table. Ensure that the given range of 126872004aadSNick Fitzgerald /// elements in the table is lazily initialized. We define this 126972004aadSNick Fitzgerald /// operation all-in-one for safety, to ensure the lazy-init 127072004aadSNick Fitzgerald /// happens. 127172004aadSNick Fitzgerald /// 127272004aadSNick Fitzgerald /// Takes an `Iterator` for the index-range to lazy-initialize, 127372004aadSNick Fitzgerald /// for flexibility. This can be a range, single item, or empty 127472004aadSNick Fitzgerald /// sequence, for example. The iterator should return indices in 127572004aadSNick Fitzgerald /// increasing order, so that the break-at-out-of-bounds behavior 127672004aadSNick Fitzgerald /// works correctly. 127772004aadSNick Fitzgerald pub(crate) fn get_table_with_lazy_init( 1278aad93a48SAlex Crichton self: Pin<&mut Self>, 127972004aadSNick Fitzgerald table_index: TableIndex, 1280df69b9a7SLinwei Shang range: impl Iterator<Item = u64>, 1281f021346eSAlex Crichton ) -> &mut Table { 1282f021346eSAlex Crichton let (idx, instance) = self.defined_table_index_and_instance(table_index); 1283f021346eSAlex Crichton instance.get_defined_table_with_lazy_init(idx, range) 128472004aadSNick Fitzgerald } 128572004aadSNick Fitzgerald 128672004aadSNick Fitzgerald /// Gets the raw runtime table data structure owned by this instance 128772004aadSNick Fitzgerald /// given the provided `idx`. 128872004aadSNick Fitzgerald /// 128972004aadSNick Fitzgerald /// The `range` specified is eagerly initialized for funcref tables. 129072004aadSNick Fitzgerald pub fn get_defined_table_with_lazy_init( 1291aad93a48SAlex Crichton mut self: Pin<&mut Self>, 129272004aadSNick Fitzgerald idx: DefinedTableIndex, 1293df69b9a7SLinwei Shang range: impl Iterator<Item = u64>, 1294ddfebe77SAlex Crichton ) -> &mut Table { 129572004aadSNick Fitzgerald let elt_ty = self.tables[idx].1.element_type(); 129672004aadSNick Fitzgerald 129772004aadSNick Fitzgerald if elt_ty == TableElementType::Func { 129872004aadSNick Fitzgerald for i in range { 129983bf774dSNick Fitzgerald let value = match self.tables[idx].1.get(None, i) { 130072004aadSNick Fitzgerald Some(value) => value, 130172004aadSNick Fitzgerald None => { 130272004aadSNick Fitzgerald // Out-of-bounds; caller will handle by likely 130372004aadSNick Fitzgerald // throwing a trap. No work to do to lazy-init 130472004aadSNick Fitzgerald // beyond the end. 130572004aadSNick Fitzgerald break; 130672004aadSNick Fitzgerald } 130772004aadSNick Fitzgerald }; 130872004aadSNick Fitzgerald 130972004aadSNick Fitzgerald if !value.is_uninit() { 131072004aadSNick Fitzgerald continue; 131172004aadSNick Fitzgerald } 131272004aadSNick Fitzgerald 131372004aadSNick Fitzgerald // The table element `i` is uninitialized and is now being 131472004aadSNick Fitzgerald // initialized. This must imply that a `precompiled` list of 131572004aadSNick Fitzgerald // function indices is available for this table. The precompiled 131672004aadSNick Fitzgerald // list is extracted and then it is consulted with `i` to 131772004aadSNick Fitzgerald // determine the function that is going to be initialized. Note 131872004aadSNick Fitzgerald // that `i` may be outside the limits of the static 131972004aadSNick Fitzgerald // initialization so it's a fallible `get` instead of an index. 13202bdae8b6SNick Fitzgerald let module = self.env_module(); 132172004aadSNick Fitzgerald let precomputed = match &module.table_initialization.initial_values[idx] { 132272004aadSNick Fitzgerald TableInitialValue::Null { precomputed } => precomputed, 132372004aadSNick Fitzgerald TableInitialValue::Expr(_) => unreachable!(), 132472004aadSNick Fitzgerald }; 1325df69b9a7SLinwei Shang // Panicking here helps catch bugs rather than silently truncating by accident. 1326df69b9a7SLinwei Shang let func_index = precomputed.get(usize::try_from(i).unwrap()).cloned(); 1327078bc37bSAlex Crichton let func_ref = 1328078bc37bSAlex Crichton func_index.and_then(|func_index| self.as_mut().get_func_ref(func_index)); 1329aad93a48SAlex Crichton self.as_mut().tables_mut()[idx] 133072004aadSNick Fitzgerald .1 133172004aadSNick Fitzgerald .set(i, TableElement::FuncRef(func_ref)) 133272004aadSNick Fitzgerald .expect("Table type should match and index should be in-bounds"); 133372004aadSNick Fitzgerald } 133472004aadSNick Fitzgerald } 133572004aadSNick Fitzgerald 1336ddfebe77SAlex Crichton self.get_defined_table(idx) 133772004aadSNick Fitzgerald } 133872004aadSNick Fitzgerald 133972004aadSNick Fitzgerald /// Get a table by index regardless of whether it is locally-defined or an 134072004aadSNick Fitzgerald /// imported, foreign table. 1341f021346eSAlex Crichton pub(crate) fn get_table(self: Pin<&mut Self>, table_index: TableIndex) -> &mut Table { 1342f021346eSAlex Crichton let (idx, instance) = self.defined_table_index_and_instance(table_index); 1343f021346eSAlex Crichton instance.get_defined_table(idx) 134472004aadSNick Fitzgerald } 134572004aadSNick Fitzgerald 134672004aadSNick Fitzgerald /// Get a locally-defined table. 13479f81f226SAlex Crichton pub(crate) fn get_defined_table(self: Pin<&mut Self>, index: DefinedTableIndex) -> &mut Table { 13489f81f226SAlex Crichton &mut self.tables_mut()[index].1 134972004aadSNick Fitzgerald } 135072004aadSNick Fitzgerald 1351f021346eSAlex Crichton pub(crate) fn defined_table_index_and_instance<'a>( 1352f021346eSAlex Crichton self: Pin<&'a mut Self>, 135372004aadSNick Fitzgerald index: TableIndex, 1354f021346eSAlex Crichton ) -> (DefinedTableIndex, Pin<&'a mut Instance>) { 13552bdae8b6SNick Fitzgerald if let Some(defined_table_index) = self.env_module().defined_table_index(index) { 1356f021346eSAlex Crichton (defined_table_index, self) 135772004aadSNick Fitzgerald } else { 135872004aadSNick Fitzgerald let import = self.imported_table(index); 1359f021346eSAlex Crichton let index = import.index; 1360f021346eSAlex Crichton let vmctx = import.vmctx.as_non_null(); 1361f021346eSAlex Crichton // SAFETY: the validity of `self` means that the reachable instances 1362f021346eSAlex Crichton // should also all be owned by the same store and fully initialized, 1363f021346eSAlex Crichton // so it's safe to laterally move from a mutable borrow of this 1364f021346eSAlex Crichton // instance to a mutable borrow of a sibling instance. 1365f021346eSAlex Crichton let foreign_instance = unsafe { self.sibling_vmctx_mut(vmctx) }; 1366f021346eSAlex Crichton (index, foreign_instance) 136772004aadSNick Fitzgerald } 136872004aadSNick Fitzgerald } 136972004aadSNick Fitzgerald 137072004aadSNick Fitzgerald /// Initialize the VMContext data associated with this Instance. 137172004aadSNick Fitzgerald /// 137272004aadSNick Fitzgerald /// The `VMContext` memory is assumed to be uninitialized; any field 137372004aadSNick Fitzgerald /// that we need in a certain state will be explicitly written by this 137472004aadSNick Fitzgerald /// function. 137572004aadSNick Fitzgerald unsafe fn initialize_vmctx( 1376aad93a48SAlex Crichton mut self: Pin<&mut Self>, 137772004aadSNick Fitzgerald module: &Module, 137872004aadSNick Fitzgerald offsets: &VMOffsets<HostPtr>, 137972004aadSNick Fitzgerald store: StorePtr, 138072004aadSNick Fitzgerald imports: Imports, 138172004aadSNick Fitzgerald ) { 13822bdae8b6SNick Fitzgerald assert!(ptr::eq(module, self.env_module().as_ref())); 138372004aadSNick Fitzgerald 1384*b052dee0SAlex Crichton // SAFETY: the type of the magic field is indeed `u32` and this function 1385*b052dee0SAlex Crichton // is initializing its value. 1386*b052dee0SAlex Crichton unsafe { 1387f1111b91SAlex Crichton self.vmctx_plus_offset_raw::<u32>(offsets.ptr.vmctx_magic()) 1388b86b9682SAlex Crichton .write(VMCONTEXT_MAGIC); 1389*b052dee0SAlex Crichton } 1390*b052dee0SAlex Crichton 1391*b052dee0SAlex Crichton // SAFETY: it's up to the caller to provide a valid store pointer here. 1392*b052dee0SAlex Crichton unsafe { 1393aad93a48SAlex Crichton self.as_mut().set_store(store.as_raw()); 1394*b052dee0SAlex Crichton } 139572004aadSNick Fitzgerald 139672004aadSNick Fitzgerald // Initialize shared types 1397*b052dee0SAlex Crichton // 1398*b052dee0SAlex Crichton // SAFETY: validity of the vmctx means it should be safe to write to it 1399*b052dee0SAlex Crichton // here. 1400*b052dee0SAlex Crichton unsafe { 1401b86b9682SAlex Crichton let types = NonNull::from(self.runtime_info.type_ids()); 1402b86b9682SAlex Crichton self.type_ids_array().write(types.cast().into()); 1403*b052dee0SAlex Crichton } 140472004aadSNick Fitzgerald 140572004aadSNick Fitzgerald // Initialize the built-in functions 1406*b052dee0SAlex Crichton // 1407*b052dee0SAlex Crichton // SAFETY: the type of the builtin functions field is indeed a pointer 1408*b052dee0SAlex Crichton // and the pointer being filled in here, plus the vmctx is valid to 1409*b052dee0SAlex Crichton // write to during initialization. 1410*b052dee0SAlex Crichton unsafe { 14115544100fSAlex Crichton static BUILTINS: VMBuiltinFunctionsArray = VMBuiltinFunctionsArray::INIT; 14125544100fSAlex Crichton let ptr = BUILTINS.expose_provenance(); 1413f1111b91SAlex Crichton self.vmctx_plus_offset_raw(offsets.ptr.vmctx_builtin_functions()) 1414b86b9682SAlex Crichton .write(VmPtr::from(ptr)); 1415*b052dee0SAlex Crichton } 141672004aadSNick Fitzgerald 141772004aadSNick Fitzgerald // Initialize the imports 1418*b052dee0SAlex Crichton // 1419*b052dee0SAlex Crichton // SAFETY: the vmctx is safe to initialize during this function and 1420*b052dee0SAlex Crichton // validity of each item itself is a contract the caller must uphold. 142172004aadSNick Fitzgerald debug_assert_eq!(imports.functions.len(), module.num_imported_funcs); 1422*b052dee0SAlex Crichton unsafe { 142372004aadSNick Fitzgerald ptr::copy_nonoverlapping( 142472004aadSNick Fitzgerald imports.functions.as_ptr(), 1425f1111b91SAlex Crichton self.vmctx_plus_offset_raw(offsets.vmctx_imported_functions_begin()) 1426b86b9682SAlex Crichton .as_ptr(), 142772004aadSNick Fitzgerald imports.functions.len(), 142872004aadSNick Fitzgerald ); 142972004aadSNick Fitzgerald debug_assert_eq!(imports.tables.len(), module.num_imported_tables); 143072004aadSNick Fitzgerald ptr::copy_nonoverlapping( 143172004aadSNick Fitzgerald imports.tables.as_ptr(), 1432f1111b91SAlex Crichton self.vmctx_plus_offset_raw(offsets.vmctx_imported_tables_begin()) 1433b86b9682SAlex Crichton .as_ptr(), 143472004aadSNick Fitzgerald imports.tables.len(), 143572004aadSNick Fitzgerald ); 143672004aadSNick Fitzgerald debug_assert_eq!(imports.memories.len(), module.num_imported_memories); 143772004aadSNick Fitzgerald ptr::copy_nonoverlapping( 143872004aadSNick Fitzgerald imports.memories.as_ptr(), 1439f1111b91SAlex Crichton self.vmctx_plus_offset_raw(offsets.vmctx_imported_memories_begin()) 1440b86b9682SAlex Crichton .as_ptr(), 144172004aadSNick Fitzgerald imports.memories.len(), 144272004aadSNick Fitzgerald ); 144372004aadSNick Fitzgerald debug_assert_eq!(imports.globals.len(), module.num_imported_globals); 144472004aadSNick Fitzgerald ptr::copy_nonoverlapping( 144572004aadSNick Fitzgerald imports.globals.as_ptr(), 1446f1111b91SAlex Crichton self.vmctx_plus_offset_raw(offsets.vmctx_imported_globals_begin()) 1447b86b9682SAlex Crichton .as_ptr(), 144872004aadSNick Fitzgerald imports.globals.len(), 144972004aadSNick Fitzgerald ); 14500b4c754aSDaniel Hillerström debug_assert_eq!(imports.tags.len(), module.num_imported_tags); 14510b4c754aSDaniel Hillerström ptr::copy_nonoverlapping( 14520b4c754aSDaniel Hillerström imports.tags.as_ptr(), 1453f1111b91SAlex Crichton self.vmctx_plus_offset_raw(offsets.vmctx_imported_tags_begin()) 14540b4c754aSDaniel Hillerström .as_ptr(), 14550b4c754aSDaniel Hillerström imports.tags.len(), 14560b4c754aSDaniel Hillerström ); 1457*b052dee0SAlex Crichton } 14580b4c754aSDaniel Hillerström 145972004aadSNick Fitzgerald // N.B.: there is no need to initialize the funcrefs array because we 146072004aadSNick Fitzgerald // eagerly construct each element in it whenever asked for a reference 146172004aadSNick Fitzgerald // to that element. In other words, there is no state needed to track 146272004aadSNick Fitzgerald // the lazy-init, so we don't need to initialize any state now. 146372004aadSNick Fitzgerald 146472004aadSNick Fitzgerald // Initialize the defined tables 1465*b052dee0SAlex Crichton // 1466*b052dee0SAlex Crichton // SAFETY: it's safe to initialize these tables during initialization 1467*b052dee0SAlex Crichton // here and the various types of pointers and such here should all be 1468*b052dee0SAlex Crichton // valid. 1469*b052dee0SAlex Crichton unsafe { 1470f1111b91SAlex Crichton let mut ptr = self.vmctx_plus_offset_raw(offsets.vmctx_tables_begin()); 1471aad93a48SAlex Crichton let tables = self.as_mut().tables_mut(); 14727a49e44fSAlex Crichton for i in 0..module.num_defined_tables() { 1473aad93a48SAlex Crichton ptr.write(tables[DefinedTableIndex::new(i)].1.vmtable()); 147472004aadSNick Fitzgerald ptr = ptr.add(1); 147572004aadSNick Fitzgerald } 1476*b052dee0SAlex Crichton } 147772004aadSNick Fitzgerald 147872004aadSNick Fitzgerald // Initialize the defined memories. This fills in both the 147972004aadSNick Fitzgerald // `defined_memories` table and the `owned_memories` table at the same 148072004aadSNick Fitzgerald // time. Entries in `defined_memories` hold a pointer to a definition 148172004aadSNick Fitzgerald // (all memories) whereas the `owned_memories` hold the actual 148272004aadSNick Fitzgerald // definitions of memories owned (not shared) in the module. 1483*b052dee0SAlex Crichton // 1484*b052dee0SAlex Crichton // SAFETY: it's safe to initialize these memories during initialization 1485*b052dee0SAlex Crichton // here and the various types of pointers and such here should all be 1486*b052dee0SAlex Crichton // valid. 1487*b052dee0SAlex Crichton unsafe { 1488f1111b91SAlex Crichton let mut ptr = self.vmctx_plus_offset_raw(offsets.vmctx_memories_begin()); 1489f1111b91SAlex Crichton let mut owned_ptr = self.vmctx_plus_offset_raw(offsets.vmctx_owned_memories_begin()); 1490aad93a48SAlex Crichton let memories = self.as_mut().memories_mut(); 14912a7f0653SAlex Crichton for i in 0..module.num_defined_memories() { 149272004aadSNick Fitzgerald let defined_memory_index = DefinedMemoryIndex::new(i); 149372004aadSNick Fitzgerald let memory_index = module.memory_index(defined_memory_index); 14942a7f0653SAlex Crichton if module.memories[memory_index].shared { 1495aad93a48SAlex Crichton let def_ptr = memories[defined_memory_index] 149672004aadSNick Fitzgerald .1 149772004aadSNick Fitzgerald .as_shared_memory() 149872004aadSNick Fitzgerald .unwrap() 149972004aadSNick Fitzgerald .vmmemory_ptr(); 1500b86b9682SAlex Crichton ptr.write(VmPtr::from(def_ptr)); 150172004aadSNick Fitzgerald } else { 1502aad93a48SAlex Crichton owned_ptr.write(memories[defined_memory_index].1.vmmemory()); 1503b86b9682SAlex Crichton ptr.write(VmPtr::from(owned_ptr)); 150472004aadSNick Fitzgerald owned_ptr = owned_ptr.add(1); 150572004aadSNick Fitzgerald } 150672004aadSNick Fitzgerald ptr = ptr.add(1); 150772004aadSNick Fitzgerald } 1508*b052dee0SAlex Crichton } 150972004aadSNick Fitzgerald 1510818966f3SNick Fitzgerald // Zero-initialize the globals so that nothing is uninitialized memory 1511818966f3SNick Fitzgerald // after this function returns. The globals are actually initialized 1512818966f3SNick Fitzgerald // with their const expression initializers after the instance is fully 1513818966f3SNick Fitzgerald // allocated. 1514*b052dee0SAlex Crichton // 1515*b052dee0SAlex Crichton // SAFETY: it's safe to initialize globals during initialization 1516*b052dee0SAlex Crichton // here. Note that while the value being written is not valid for all 1517*b052dee0SAlex Crichton // types of globals it's initializing the memory to zero instead of 1518*b052dee0SAlex Crichton // being in an undefined state. So it's still unsafe to access globals 1519*b052dee0SAlex Crichton // after this, but if it's read then it'd hopefully crash faster than 1520*b052dee0SAlex Crichton // leaving this undefined. 1521*b052dee0SAlex Crichton unsafe { 1522818966f3SNick Fitzgerald for (index, _init) in module.global_initializers.iter() { 1523b86b9682SAlex Crichton self.global_ptr(index).write(VMGlobalDefinition::new()); 152472004aadSNick Fitzgerald } 1525*b052dee0SAlex Crichton } 15260b4c754aSDaniel Hillerström 15270b4c754aSDaniel Hillerström // Initialize the defined tags 1528*b052dee0SAlex Crichton // 1529*b052dee0SAlex Crichton // SAFETY: it's safe to initialize these tags during initialization 1530*b052dee0SAlex Crichton // here and the various types of pointers and such here should all be 1531*b052dee0SAlex Crichton // valid. 1532*b052dee0SAlex Crichton unsafe { 1533f1111b91SAlex Crichton let mut ptr = self.vmctx_plus_offset_raw(offsets.vmctx_tags_begin()); 15340b4c754aSDaniel Hillerström for i in 0..module.num_defined_tags() { 15350b4c754aSDaniel Hillerström let defined_index = DefinedTagIndex::new(i); 15360b4c754aSDaniel Hillerström let tag_index = module.tag_index(defined_index); 15370b4c754aSDaniel Hillerström let tag = module.tags[tag_index]; 15380b4c754aSDaniel Hillerström ptr.write(VMTagDefinition::new( 15390b4c754aSDaniel Hillerström tag.signature.unwrap_engine_type_index(), 15400b4c754aSDaniel Hillerström )); 15410b4c754aSDaniel Hillerström ptr = ptr.add(1); 15420b4c754aSDaniel Hillerström } 154372004aadSNick Fitzgerald } 1544*b052dee0SAlex Crichton } 154572004aadSNick Fitzgerald 1546aad93a48SAlex Crichton /// Attempts to convert from the host `addr` specified to a WebAssembly 1547aad93a48SAlex Crichton /// based address recorded in `WasmFault`. 1548aad93a48SAlex Crichton /// 1549aad93a48SAlex Crichton /// This method will check all linear memories that this instance contains 1550aad93a48SAlex Crichton /// to see if any of them contain `addr`. If one does then `Some` is 1551aad93a48SAlex Crichton /// returned with metadata about the wasm fault. Otherwise `None` is 1552aad93a48SAlex Crichton /// returned and `addr` doesn't belong to this instance. 1553aad93a48SAlex Crichton pub fn wasm_fault(&self, addr: usize) -> Option<WasmFault> { 155472004aadSNick Fitzgerald let mut fault = None; 155572004aadSNick Fitzgerald for (_, (_, memory)) in self.memories.iter() { 155672004aadSNick Fitzgerald let accessible = memory.wasm_accessible(); 155772004aadSNick Fitzgerald if accessible.start <= addr && addr < accessible.end { 155872004aadSNick Fitzgerald // All linear memories should be disjoint so assert that no 155972004aadSNick Fitzgerald // prior fault has been found. 156072004aadSNick Fitzgerald assert!(fault.is_none()); 156172004aadSNick Fitzgerald fault = Some(WasmFault { 156272004aadSNick Fitzgerald memory_size: memory.byte_size(), 156372004aadSNick Fitzgerald wasm_address: u64::try_from(addr - accessible.start).unwrap(), 156472004aadSNick Fitzgerald }); 156572004aadSNick Fitzgerald } 156672004aadSNick Fitzgerald } 156772004aadSNick Fitzgerald fault 156872004aadSNick Fitzgerald } 15690e9a691dSAlex Crichton 15700e9a691dSAlex Crichton /// Returns the id, within this instance's store, that it's assigned. 15710e9a691dSAlex Crichton pub fn id(&self) -> InstanceId { 15720e9a691dSAlex Crichton self.id 15730e9a691dSAlex Crichton } 1574e012eedaSAlex Crichton 1575e012eedaSAlex Crichton /// Get all memories within this instance. 1576e012eedaSAlex Crichton /// 1577e012eedaSAlex Crichton /// Returns both import and defined memories. 1578e012eedaSAlex Crichton /// 1579e012eedaSAlex Crichton /// Returns both exported and non-exported memories. 1580e012eedaSAlex Crichton /// 1581e012eedaSAlex Crichton /// Gives access to the full memories space. 15822b832281SAlex Crichton pub fn all_memories( 15832b832281SAlex Crichton &self, 15842b832281SAlex Crichton store: StoreId, 15852b832281SAlex Crichton ) -> impl ExactSizeIterator<Item = (MemoryIndex, crate::Memory)> + '_ { 15862b832281SAlex Crichton self.env_module() 15872b832281SAlex Crichton .memories 15882b832281SAlex Crichton .iter() 15892b832281SAlex Crichton .map(move |(i, _)| (i, self.get_exported_memory(store, i))) 1590e012eedaSAlex Crichton } 1591e012eedaSAlex Crichton 1592e012eedaSAlex Crichton /// Return the memories defined in this instance (not imported). 15932b832281SAlex Crichton pub fn defined_memories<'a>( 15942b832281SAlex Crichton &'a self, 15952b832281SAlex Crichton store: StoreId, 15962b832281SAlex Crichton ) -> impl ExactSizeIterator<Item = crate::Memory> + 'a { 1597e012eedaSAlex Crichton let num_imported = self.env_module().num_imported_memories; 15982b832281SAlex Crichton self.all_memories(store) 1599e012eedaSAlex Crichton .skip(num_imported) 1600e012eedaSAlex Crichton .map(|(_i, memory)| memory) 1601e012eedaSAlex Crichton } 1602e012eedaSAlex Crichton 1603e012eedaSAlex Crichton /// Lookup an item with the given index. 1604e012eedaSAlex Crichton /// 1605e012eedaSAlex Crichton /// # Panics 1606e012eedaSAlex Crichton /// 1607e012eedaSAlex Crichton /// Panics if `export` is not valid for this instance. 16082b832281SAlex Crichton /// 16092b832281SAlex Crichton /// # Safety 16102b832281SAlex Crichton /// 16112b832281SAlex Crichton /// This function requires that `store` is the correct store which owns this 16122b832281SAlex Crichton /// instance. 16132b832281SAlex Crichton pub unsafe fn get_export_by_index_mut( 16142b832281SAlex Crichton self: Pin<&mut Self>, 16152b832281SAlex Crichton store: StoreId, 16162b832281SAlex Crichton export: EntityIndex, 16172b832281SAlex Crichton ) -> Export { 1618e012eedaSAlex Crichton match export { 16192b832281SAlex Crichton // SAFETY: the contract of `store` owning the this instance is a 16202b832281SAlex Crichton // safety requirement of this function itself. 16212b832281SAlex Crichton EntityIndex::Function(i) => { 16222b832281SAlex Crichton Export::Function(unsafe { self.get_exported_func(store, i) }) 16232b832281SAlex Crichton } 16242b832281SAlex Crichton EntityIndex::Global(i) => Export::Global(self.get_exported_global(store, i)), 16252b832281SAlex Crichton EntityIndex::Table(i) => Export::Table(self.get_exported_table(store, i)), 16262b832281SAlex Crichton EntityIndex::Memory(i) => Export::Memory { 16272b832281SAlex Crichton memory: self.get_exported_memory(store, i), 16282b832281SAlex Crichton shared: self.env_module().memories[i].shared, 16292b832281SAlex Crichton }, 16302b832281SAlex Crichton EntityIndex::Tag(i) => Export::Tag(self.get_exported_tag(store, i)), 1631e012eedaSAlex Crichton } 1632e012eedaSAlex Crichton } 1633aad93a48SAlex Crichton 1634aad93a48SAlex Crichton fn store_mut(self: Pin<&mut Self>) -> &mut Option<VMStoreRawPtr> { 1635aad93a48SAlex Crichton // SAFETY: this is a pin-projection to get a mutable reference to an 1636aad93a48SAlex Crichton // internal field and is safe so long as the `&mut Self` temporarily 1637aad93a48SAlex Crichton // created is not overwritten, which it isn't here. 1638aad93a48SAlex Crichton unsafe { &mut self.get_unchecked_mut().store } 1639aad93a48SAlex Crichton } 1640aad93a48SAlex Crichton 1641aad93a48SAlex Crichton fn dropped_elements_mut(self: Pin<&mut Self>) -> &mut EntitySet<ElemIndex> { 1642aad93a48SAlex Crichton // SAFETY: see `store_mut` above. 1643aad93a48SAlex Crichton unsafe { &mut self.get_unchecked_mut().dropped_elements } 1644aad93a48SAlex Crichton } 1645aad93a48SAlex Crichton 1646aad93a48SAlex Crichton fn dropped_data_mut(self: Pin<&mut Self>) -> &mut EntitySet<DataIndex> { 1647aad93a48SAlex Crichton // SAFETY: see `store_mut` above. 1648aad93a48SAlex Crichton unsafe { &mut self.get_unchecked_mut().dropped_data } 1649aad93a48SAlex Crichton } 1650aad93a48SAlex Crichton 1651aad93a48SAlex Crichton fn memories_mut( 1652aad93a48SAlex Crichton self: Pin<&mut Self>, 1653aad93a48SAlex Crichton ) -> &mut PrimaryMap<DefinedMemoryIndex, (MemoryAllocationIndex, Memory)> { 1654aad93a48SAlex Crichton // SAFETY: see `store_mut` above. 1655aad93a48SAlex Crichton unsafe { &mut self.get_unchecked_mut().memories } 1656aad93a48SAlex Crichton } 1657aad93a48SAlex Crichton 1658f021346eSAlex Crichton pub(crate) fn tables_mut( 1659aad93a48SAlex Crichton self: Pin<&mut Self>, 1660aad93a48SAlex Crichton ) -> &mut PrimaryMap<DefinedTableIndex, (TableAllocationIndex, Table)> { 1661aad93a48SAlex Crichton // SAFETY: see `store_mut` above. 1662aad93a48SAlex Crichton unsafe { &mut self.get_unchecked_mut().tables } 1663aad93a48SAlex Crichton } 1664aad93a48SAlex Crichton 1665aad93a48SAlex Crichton #[cfg(feature = "wmemcheck")] 1666aad93a48SAlex Crichton pub(super) fn wmemcheck_state_mut(self: Pin<&mut Self>) -> &mut Option<Wmemcheck> { 1667aad93a48SAlex Crichton // SAFETY: see `store_mut` above. 1668aad93a48SAlex Crichton unsafe { &mut self.get_unchecked_mut().wmemcheck_state } 1669aad93a48SAlex Crichton } 167072004aadSNick Fitzgerald } 167172004aadSNick Fitzgerald 16727e28c254SAlex Crichton // SAFETY: `layout` should describe this accurately and `OwnedVMContext` is the 16737e28c254SAlex Crichton // last field of `ComponentInstance`. 16747e28c254SAlex Crichton unsafe impl InstanceLayout for Instance { 16757e28c254SAlex Crichton const INIT_ZEROED: bool = false; 16767e28c254SAlex Crichton type VMContext = VMContext; 16777e28c254SAlex Crichton 16787e28c254SAlex Crichton fn layout(&self) -> Layout { 16797e28c254SAlex Crichton Self::alloc_layout(self.runtime_info.offsets()) 16807e28c254SAlex Crichton } 16817e28c254SAlex Crichton 16827e28c254SAlex Crichton fn owned_vmctx(&self) -> &OwnedVMContext<VMContext> { 16837e28c254SAlex Crichton &self.vmctx 16847e28c254SAlex Crichton } 16857e28c254SAlex Crichton 16867e28c254SAlex Crichton fn owned_vmctx_mut(&mut self) -> &mut OwnedVMContext<VMContext> { 16877e28c254SAlex Crichton &mut self.vmctx 16887e28c254SAlex Crichton } 16897e28c254SAlex Crichton } 16907e28c254SAlex Crichton 16917e28c254SAlex Crichton pub type InstanceHandle = OwnedInstance<Instance>; 16927e28c254SAlex Crichton 169372004aadSNick Fitzgerald /// A handle holding an `Instance` of a WebAssembly module. 1694aad93a48SAlex Crichton /// 1695aad93a48SAlex Crichton /// This structure is an owning handle of the `instance` contained internally. 1696aad93a48SAlex Crichton /// When this value goes out of scope it will deallocate the `Instance` and all 1697aad93a48SAlex Crichton /// memory associated with it. 1698aad93a48SAlex Crichton /// 1699aad93a48SAlex Crichton /// Note that this lives within a `StoreOpaque` on a list of instances that a 1700aad93a48SAlex Crichton /// store is keeping alive. 170172004aadSNick Fitzgerald #[derive(Debug)] 17027e28c254SAlex Crichton #[repr(transparent)] // guarantee this is a zero-cost wrapper 17037e28c254SAlex Crichton pub struct OwnedInstance<T: InstanceLayout> { 1704aad93a48SAlex Crichton /// The raw pointer to the instance that was allocated. 1705aad93a48SAlex Crichton /// 1706aad93a48SAlex Crichton /// Note that this is not equivalent to `Box<Instance>` because the 1707aad93a48SAlex Crichton /// allocation here has a `VMContext` trailing after it. Thus the custom 1708aad93a48SAlex Crichton /// destructor to invoke the `dealloc` function with the appropriate 1709aad93a48SAlex Crichton /// layout. 17107e28c254SAlex Crichton instance: SendSyncPtr<T>, 17117e28c254SAlex Crichton _marker: marker::PhantomData<Box<(T, OwnedVMContext<T::VMContext>)>>, 171272004aadSNick Fitzgerald } 171372004aadSNick Fitzgerald 17147e28c254SAlex Crichton /// Structure that must be placed at the end of a type implementing 17157e28c254SAlex Crichton /// `InstanceLayout`. 17167e28c254SAlex Crichton #[repr(align(16))] // match the alignment of VMContext 17177e28c254SAlex Crichton pub struct OwnedVMContext<T> { 17187e28c254SAlex Crichton /// A pointer to the `vmctx` field at the end of the `structure`. 17197e28c254SAlex Crichton /// 17207e28c254SAlex Crichton /// If you're looking at this a reasonable question would be "why do we need 17217e28c254SAlex Crichton /// a pointer to ourselves?" because after all the pointer's value is 17227e28c254SAlex Crichton /// trivially derivable from any `&Instance` pointer. The rationale for this 17237e28c254SAlex Crichton /// field's existence is subtle, but it's required for correctness. The 17247e28c254SAlex Crichton /// short version is "this makes miri happy". 17257e28c254SAlex Crichton /// 17267e28c254SAlex Crichton /// The long version of why this field exists is that the rules that MIRI 17277e28c254SAlex Crichton /// uses to ensure pointers are used correctly have various conditions on 17287e28c254SAlex Crichton /// them depend on how pointers are used. More specifically if `*mut T` is 17297e28c254SAlex Crichton /// derived from `&mut T`, then that invalidates all prior pointers drived 17307e28c254SAlex Crichton /// from the `&mut T`. This means that while we liberally want to re-acquire 17317e28c254SAlex Crichton /// a `*mut VMContext` throughout the implementation of `Instance` the 17327e28c254SAlex Crichton /// trivial way, a function `fn vmctx(Pin<&mut Instance>) -> *mut VMContext` 17337e28c254SAlex Crichton /// would effectively invalidate all prior `*mut VMContext` pointers 17347e28c254SAlex Crichton /// acquired. The purpose of this field is to serve as a sort of 17357e28c254SAlex Crichton /// source-of-truth for where `*mut VMContext` pointers come from. 17367e28c254SAlex Crichton /// 17377e28c254SAlex Crichton /// This field is initialized when the `Instance` is created with the 17387e28c254SAlex Crichton /// original allocation's pointer. That means that the provenance of this 17397e28c254SAlex Crichton /// pointer contains the entire allocation (both instance and `VMContext`). 17407e28c254SAlex Crichton /// This provenance bit is then "carried through" where `fn vmctx` will base 17417e28c254SAlex Crichton /// all returned pointers on this pointer itself. This provides the means of 17427e28c254SAlex Crichton /// never invalidating this pointer throughout MIRI and additionally being 17437e28c254SAlex Crichton /// able to still temporarily have `Pin<&mut Instance>` methods and such. 17447e28c254SAlex Crichton /// 17457e28c254SAlex Crichton /// It's important to note, though, that this is not here purely for MIRI. 17467e28c254SAlex Crichton /// The careful construction of the `fn vmctx` method has ramifications on 17477e28c254SAlex Crichton /// the LLVM IR generated, for example. A historical CVE on Wasmtime, 17487e28c254SAlex Crichton /// GHSA-ch89-5g45-qwc7, was caused due to relying on undefined behavior. By 17497e28c254SAlex Crichton /// deriving VMContext pointers from this pointer it specifically hints to 17507e28c254SAlex Crichton /// LLVM that trickery is afoot and it properly informs `noalias` and such 17517e28c254SAlex Crichton /// annotations and analysis. More-or-less this pointer is actually loaded 17527e28c254SAlex Crichton /// in LLVM IR which helps defeat otherwise present aliasing optimizations, 17537e28c254SAlex Crichton /// which we want, since writes to this should basically never be optimized 17547e28c254SAlex Crichton /// out. 17557e28c254SAlex Crichton /// 17567e28c254SAlex Crichton /// As a final note it's worth pointing out that the machine code generated 17577e28c254SAlex Crichton /// for accessing `fn vmctx` is still as one would expect. This member isn't 17587e28c254SAlex Crichton /// actually ever loaded at runtime (or at least shouldn't be). Perhaps in 17597e28c254SAlex Crichton /// the future if the memory consumption of this field is a problem we could 17607e28c254SAlex Crichton /// shrink it slightly, but for now one extra pointer per wasm instance 17617e28c254SAlex Crichton /// seems not too bad. 17627e28c254SAlex Crichton vmctx_self_reference: SendSyncPtr<T>, 17637e28c254SAlex Crichton 17647e28c254SAlex Crichton /// This field ensures that going from `Pin<&mut T>` to `&mut T` is not a 17657e28c254SAlex Crichton /// safe operation. 17667e28c254SAlex Crichton _marker: core::marker::PhantomPinned, 17677e28c254SAlex Crichton } 17687e28c254SAlex Crichton 17697e28c254SAlex Crichton impl<T> OwnedVMContext<T> { 17707e28c254SAlex Crichton /// Creates a new blank vmctx to place at the end of an instance. 17717e28c254SAlex Crichton pub fn new() -> OwnedVMContext<T> { 17727e28c254SAlex Crichton OwnedVMContext { 17737e28c254SAlex Crichton vmctx_self_reference: SendSyncPtr::new(NonNull::dangling()), 17747e28c254SAlex Crichton _marker: core::marker::PhantomPinned, 17757e28c254SAlex Crichton } 17767e28c254SAlex Crichton } 17777e28c254SAlex Crichton } 17787e28c254SAlex Crichton 17797e28c254SAlex Crichton /// Helper trait to plumb both core instances and component instances into 17807e28c254SAlex Crichton /// `OwnedInstance` below. 17817e28c254SAlex Crichton /// 17827e28c254SAlex Crichton /// # Safety 17837e28c254SAlex Crichton /// 17847e28c254SAlex Crichton /// This trait requires `layout` to correctly describe `Self` and appropriately 17857e28c254SAlex Crichton /// allocate space for `Self::VMContext` afterwards. Additionally the field 17867e28c254SAlex Crichton /// returned by `owned_vmctx()` must be the last field in the structure. 17877e28c254SAlex Crichton pub unsafe trait InstanceLayout { 17887e28c254SAlex Crichton /// Whether or not to allocate this instance with `alloc_zeroed` or `alloc`. 17897e28c254SAlex Crichton const INIT_ZEROED: bool; 17907e28c254SAlex Crichton 17917e28c254SAlex Crichton /// The trailing `VMContext` type at the end of this instance. 17927e28c254SAlex Crichton type VMContext; 17937e28c254SAlex Crichton 17947e28c254SAlex Crichton /// The memory layout to use to allocate and deallocate this instance. 17957e28c254SAlex Crichton fn layout(&self) -> Layout; 17967e28c254SAlex Crichton 17977e28c254SAlex Crichton fn owned_vmctx(&self) -> &OwnedVMContext<Self::VMContext>; 17987e28c254SAlex Crichton fn owned_vmctx_mut(&mut self) -> &mut OwnedVMContext<Self::VMContext>; 17997e28c254SAlex Crichton 18007e28c254SAlex Crichton /// Returns the `vmctx_self_reference` set above. 18017e28c254SAlex Crichton #[inline] 18027e28c254SAlex Crichton fn vmctx(&self) -> NonNull<Self::VMContext> { 18037e28c254SAlex Crichton // The definition of this method is subtle but intentional. The goal 18047e28c254SAlex Crichton // here is that effectively this should return `&mut self.vmctx`, but 18057e28c254SAlex Crichton // it's not quite so simple. Some more documentation is available on the 18067e28c254SAlex Crichton // `vmctx_self_reference` field, but the general idea is that we're 18077e28c254SAlex Crichton // creating a pointer to return with proper provenance. Provenance is 18087e28c254SAlex Crichton // still in the works in Rust at the time of this writing but the load 18097e28c254SAlex Crichton // of the `self.vmctx_self_reference` field is important here as it 18107e28c254SAlex Crichton // affects how LLVM thinks about aliasing with respect to the returned 18117e28c254SAlex Crichton // pointer. 18127e28c254SAlex Crichton // 18137e28c254SAlex Crichton // The intention of this method is to codegen to machine code as `&mut 18147e28c254SAlex Crichton // self.vmctx`, however. While it doesn't show up like this in LLVM IR 18157e28c254SAlex Crichton // (there's an actual load of the field) it does look like that by the 18167e28c254SAlex Crichton // time the backend runs. (that's magic to me, the backend removing 18177e28c254SAlex Crichton // loads...) 18187e28c254SAlex Crichton let owned_vmctx = self.owned_vmctx(); 18197e28c254SAlex Crichton let owned_vmctx_raw = NonNull::from(owned_vmctx); 18207e28c254SAlex Crichton // SAFETY: it's part of the contract of `InstanceLayout` and the usage 18217e28c254SAlex Crichton // with `OwnedInstance` that this indeed points to the vmctx. 18227e28c254SAlex Crichton let addr = unsafe { owned_vmctx_raw.add(1) }; 18237e28c254SAlex Crichton owned_vmctx 18247e28c254SAlex Crichton .vmctx_self_reference 18257e28c254SAlex Crichton .as_non_null() 18267e28c254SAlex Crichton .with_addr(addr.addr()) 18277e28c254SAlex Crichton } 18287e28c254SAlex Crichton 18297e28c254SAlex Crichton /// Helper function to access various locations offset from our `*mut 18307e28c254SAlex Crichton /// VMContext` object. 18317e28c254SAlex Crichton /// 18327e28c254SAlex Crichton /// Note that this method takes `&self` as an argument but returns 18337e28c254SAlex Crichton /// `NonNull<T>` which is frequently used to mutate said memory. This is an 18347e28c254SAlex Crichton /// intentional design decision where the safety of the modification of 18357e28c254SAlex Crichton /// memory is placed as a burden onto the caller. The implementation of this 18367e28c254SAlex Crichton /// method explicitly does not require `&mut self` to acquire mutable 18377e28c254SAlex Crichton /// provenance to update the `VMContext` region. Instead all pointers into 18387e28c254SAlex Crichton /// the `VMContext` area have provenance/permissions to write. 18397e28c254SAlex Crichton /// 18407e28c254SAlex Crichton /// Also note though that care must be taken to ensure that reads/writes of 18417e28c254SAlex Crichton /// memory must only happen where appropriate, for example a non-atomic 18427e28c254SAlex Crichton /// write (as most are) should never happen concurrently with another read 18437e28c254SAlex Crichton /// or write. It's generally on the burden of the caller to adhere to this. 18447e28c254SAlex Crichton /// 18457e28c254SAlex Crichton /// Also of note is that most of the time the usage of this method falls 18467e28c254SAlex Crichton /// into one of: 18477e28c254SAlex Crichton /// 18487e28c254SAlex Crichton /// * Something in the VMContext is being read or written. In that case use 18497e28c254SAlex Crichton /// `vmctx_plus_offset` or `vmctx_plus_offset_mut` if possible due to 18507e28c254SAlex Crichton /// that having a safer lifetime. 18517e28c254SAlex Crichton /// 18527e28c254SAlex Crichton /// * A pointer is being created to pass to other VM* data structures. In 18537e28c254SAlex Crichton /// that situation the lifetime of all VM data structures are typically 18547e28c254SAlex Crichton /// tied to the `Store<T>` which is what provides the guarantees around 18557e28c254SAlex Crichton /// concurrency/etc. 18567e28c254SAlex Crichton /// 18577e28c254SAlex Crichton /// There's quite a lot of unsafety riding on this method, especially 18587e28c254SAlex Crichton /// related to the ascription `T` of the byte `offset`. It's hoped that in 18597e28c254SAlex Crichton /// the future we're able to settle on an in theory safer design. 18607e28c254SAlex Crichton /// 18617e28c254SAlex Crichton /// # Safety 18627e28c254SAlex Crichton /// 18637e28c254SAlex Crichton /// This method is unsafe because the `offset` must be within bounds of the 18647e28c254SAlex Crichton /// `VMContext` object trailing this instance. Additionally `T` must be a 18657e28c254SAlex Crichton /// valid ascription of the value that resides at that location. 18667e28c254SAlex Crichton unsafe fn vmctx_plus_offset_raw<T: VmSafe>(&self, offset: impl Into<u32>) -> NonNull<T> { 18677e28c254SAlex Crichton // SAFETY: the safety requirements of `byte_add` are forwarded to this 18687e28c254SAlex Crichton // method's caller. 18697e28c254SAlex Crichton unsafe { 18707e28c254SAlex Crichton self.vmctx() 18717e28c254SAlex Crichton .byte_add(usize::try_from(offset.into()).unwrap()) 18727e28c254SAlex Crichton .cast() 18737e28c254SAlex Crichton } 18747e28c254SAlex Crichton } 18757e28c254SAlex Crichton 18767e28c254SAlex Crichton /// Helper above `vmctx_plus_offset_raw` which transfers the lifetime of 18777e28c254SAlex Crichton /// `&self` to the returned reference `&T`. 18787e28c254SAlex Crichton /// 18797e28c254SAlex Crichton /// # Safety 18807e28c254SAlex Crichton /// 18817e28c254SAlex Crichton /// See the safety documentation of `vmctx_plus_offset_raw`. 18827e28c254SAlex Crichton unsafe fn vmctx_plus_offset<T: VmSafe>(&self, offset: impl Into<u32>) -> &T { 18837e28c254SAlex Crichton // SAFETY: this method has the same safety requirements as 18847e28c254SAlex Crichton // `vmctx_plus_offset_raw`. 18857e28c254SAlex Crichton unsafe { self.vmctx_plus_offset_raw(offset).as_ref() } 18867e28c254SAlex Crichton } 18877e28c254SAlex Crichton 18887e28c254SAlex Crichton /// Helper above `vmctx_plus_offset_raw` which transfers the lifetime of 18897e28c254SAlex Crichton /// `&mut self` to the returned reference `&mut T`. 18907e28c254SAlex Crichton /// 18917e28c254SAlex Crichton /// # Safety 18927e28c254SAlex Crichton /// 18937e28c254SAlex Crichton /// See the safety documentation of `vmctx_plus_offset_raw`. 18947e28c254SAlex Crichton unsafe fn vmctx_plus_offset_mut<T: VmSafe>( 18957e28c254SAlex Crichton self: Pin<&mut Self>, 18967e28c254SAlex Crichton offset: impl Into<u32>, 18977e28c254SAlex Crichton ) -> &mut T { 18987e28c254SAlex Crichton // SAFETY: this method has the same safety requirements as 18997e28c254SAlex Crichton // `vmctx_plus_offset_raw`. 19007e28c254SAlex Crichton unsafe { self.vmctx_plus_offset_raw(offset).as_mut() } 19017e28c254SAlex Crichton } 19027e28c254SAlex Crichton } 19037e28c254SAlex Crichton 19047e28c254SAlex Crichton impl<T: InstanceLayout> OwnedInstance<T> { 19057e28c254SAlex Crichton /// Allocates a new `OwnedInstance` and places `instance` inside of it. 19067e28c254SAlex Crichton /// 19077e28c254SAlex Crichton /// This will `instance` 19087e28c254SAlex Crichton pub(super) fn new(mut instance: T) -> OwnedInstance<T> { 19097e28c254SAlex Crichton let layout = instance.layout(); 19107e28c254SAlex Crichton debug_assert!(layout.size() >= size_of_val(&instance)); 19117e28c254SAlex Crichton debug_assert!(layout.align() >= align_of_val(&instance)); 19127e28c254SAlex Crichton 19137e28c254SAlex Crichton // SAFETY: it's up to us to assert that `layout` has a non-zero size, 19147e28c254SAlex Crichton // which is asserted here. 19157e28c254SAlex Crichton let ptr = unsafe { 19167e28c254SAlex Crichton assert!(layout.size() > 0); 19177e28c254SAlex Crichton if T::INIT_ZEROED { 19187e28c254SAlex Crichton alloc::alloc::alloc_zeroed(layout) 19197e28c254SAlex Crichton } else { 19207e28c254SAlex Crichton alloc::alloc::alloc(layout) 19217e28c254SAlex Crichton } 19227e28c254SAlex Crichton }; 19237e28c254SAlex Crichton if ptr.is_null() { 19247e28c254SAlex Crichton alloc::alloc::handle_alloc_error(layout); 19257e28c254SAlex Crichton } 19267e28c254SAlex Crichton let instance_ptr = NonNull::new(ptr.cast::<T>()).unwrap(); 19277e28c254SAlex Crichton 19287e28c254SAlex Crichton // SAFETY: it's part of the unsafe contract of `InstanceLayout` that the 19297e28c254SAlex Crichton // `add` here is appropriate for the layout allocated. 19307e28c254SAlex Crichton let vmctx_self_reference = unsafe { instance_ptr.add(1).cast() }; 19317e28c254SAlex Crichton instance.owned_vmctx_mut().vmctx_self_reference = vmctx_self_reference.into(); 19327e28c254SAlex Crichton 19337e28c254SAlex Crichton // SAFETY: we allocated above and it's an unsafe contract of 19347e28c254SAlex Crichton // `InstanceLayout` that the layout is suitable for writing the 19357e28c254SAlex Crichton // instance. 19367e28c254SAlex Crichton unsafe { 19377e28c254SAlex Crichton instance_ptr.write(instance); 19387e28c254SAlex Crichton } 19397e28c254SAlex Crichton 19407e28c254SAlex Crichton let ret = OwnedInstance { 19417e28c254SAlex Crichton instance: SendSyncPtr::new(instance_ptr), 19427e28c254SAlex Crichton _marker: marker::PhantomData, 19437e28c254SAlex Crichton }; 19447e28c254SAlex Crichton 19457e28c254SAlex Crichton // Double-check various vmctx calculations are correct. 19467e28c254SAlex Crichton debug_assert_eq!( 19477e28c254SAlex Crichton vmctx_self_reference.addr(), 19487e28c254SAlex Crichton // SAFETY: `InstanceLayout` should guarantee it's safe to add 1 to 19497e28c254SAlex Crichton // the last field to get a pointer to 1-byte-past-the-end of an 19507e28c254SAlex Crichton // object, which should be valid. 19517e28c254SAlex Crichton unsafe { NonNull::from(ret.get().owned_vmctx()).add(1).addr() } 19527e28c254SAlex Crichton ); 19537e28c254SAlex Crichton debug_assert_eq!(vmctx_self_reference.addr(), ret.get().vmctx().addr()); 19547e28c254SAlex Crichton 19557e28c254SAlex Crichton ret 19567e28c254SAlex Crichton } 19577e28c254SAlex Crichton 1958aad93a48SAlex Crichton /// Gets the raw underlying `&Instance` from this handle. 19597e28c254SAlex Crichton pub fn get(&self) -> &T { 1960aad93a48SAlex Crichton // SAFETY: this is an owned instance handle that retains exclusive 1961aad93a48SAlex Crichton // ownership of the `Instance` inside. With `&self` given we know 1962aad93a48SAlex Crichton // this pointer is valid valid and the returned lifetime is connected 1963aad93a48SAlex Crichton // to `self` so that should also be valid. 1964aad93a48SAlex Crichton unsafe { self.instance.as_non_null().as_ref() } 196572004aadSNick Fitzgerald } 196672004aadSNick Fitzgerald 1967aad93a48SAlex Crichton /// Same as [`Self::get`] except for mutability. 19687e28c254SAlex Crichton pub fn get_mut(&mut self) -> Pin<&mut T> { 1969aad93a48SAlex Crichton // SAFETY: The lifetime concerns here are the same as `get` above. 1970aad93a48SAlex Crichton // Otherwise `new_unchecked` is used here to uphold the contract that 1971aad93a48SAlex Crichton // instances are always pinned in memory. 1972aad93a48SAlex Crichton unsafe { Pin::new_unchecked(self.instance.as_non_null().as_mut()) } 197372004aadSNick Fitzgerald } 197472004aadSNick Fitzgerald } 197572004aadSNick Fitzgerald 19767e28c254SAlex Crichton impl<T: InstanceLayout> Drop for OwnedInstance<T> { 1977aad93a48SAlex Crichton fn drop(&mut self) { 1978aad93a48SAlex Crichton unsafe { 19797e28c254SAlex Crichton let layout = self.get().layout(); 1980aad93a48SAlex Crichton ptr::drop_in_place(self.instance.as_ptr()); 1981aad93a48SAlex Crichton alloc::alloc::dealloc(self.instance.as_ptr().cast(), layout); 198272004aadSNick Fitzgerald } 198372004aadSNick Fitzgerald } 198472004aadSNick Fitzgerald } 1985