1 //! An `Instance` contains all the runtime state used by execution of a 2 //! wasm module (except its callstack and register state). An 3 //! `InstanceHandle` is a reference-counting handle for an `Instance`. 4 5 use crate::prelude::*; 6 use crate::runtime::vm::const_expr::{ConstEvalContext, ConstExprEvaluator}; 7 use crate::runtime::vm::export::Export; 8 use crate::runtime::vm::memory::{Memory, RuntimeMemoryCreator}; 9 use crate::runtime::vm::table::{Table, TableElement, TableElementType}; 10 use crate::runtime::vm::vmcontext::{ 11 VMBuiltinFunctionsArray, VMContext, VMFuncRef, VMFunctionImport, VMGlobalDefinition, 12 VMGlobalImport, VMMemoryDefinition, VMMemoryImport, VMOpaqueContext, VMRuntimeLimits, 13 VMTableDefinition, VMTableImport, 14 }; 15 use crate::runtime::vm::{ 16 ExportFunction, ExportGlobal, ExportMemory, ExportTable, GcStore, Imports, ModuleRuntimeInfo, 17 SendSyncPtr, VMFunctionBody, VMGcRef, VMStore, WasmFault, 18 }; 19 use alloc::sync::Arc; 20 use core::alloc::Layout; 21 use core::any::Any; 22 use core::ops::Range; 23 use core::ptr::NonNull; 24 use core::sync::atomic::AtomicU64; 25 use core::{mem, ptr}; 26 use sptr::Strict; 27 use wasmtime_environ::{ 28 packed_option::ReservedValue, DataIndex, DefinedGlobalIndex, DefinedMemoryIndex, 29 DefinedTableIndex, ElemIndex, EntityIndex, EntityRef, EntitySet, FuncIndex, GlobalIndex, 30 HostPtr, MemoryIndex, MemoryPlan, Module, ModuleInternedTypeIndex, PrimaryMap, PtrSize, 31 TableIndex, TableInitialValue, TableSegmentElements, Trap, VMOffsets, VMSharedTypeIndex, 32 WasmHeapTopType, VMCONTEXT_MAGIC, 33 }; 34 #[cfg(feature = "wmemcheck")] 35 use wasmtime_wmemcheck::Wmemcheck; 36 37 mod allocator; 38 39 pub use allocator::*; 40 41 /// A type that roughly corresponds to a WebAssembly instance, but is also used 42 /// for host-defined objects. 43 /// 44 /// This structure is is never allocated directly but is instead managed through 45 /// an `InstanceHandle`. This structure ends with a `VMContext` which has a 46 /// dynamic size corresponding to the `module` configured within. Memory 47 /// management of this structure is always externalized. 48 /// 49 /// Instances here can correspond to actual instantiated modules, but it's also 50 /// used ubiquitously for host-defined objects. For example creating a 51 /// host-defined memory will have a `module` that looks like it exports a single 52 /// memory (and similar for other constructs). 53 /// 54 /// This `Instance` type is used as a ubiquitous representation for WebAssembly 55 /// values, whether or not they were created on the host or through a module. 56 #[repr(C)] // ensure that the vmctx field is last. 57 pub struct Instance { 58 /// The runtime info (corresponding to the "compiled module" 59 /// abstraction in higher layers) that is retained and needed for 60 /// lazy initialization. This provides access to the underlying 61 /// Wasm module entities, the compiled JIT code, metadata about 62 /// functions, lazy initialization state, etc. 63 runtime_info: ModuleRuntimeInfo, 64 65 /// WebAssembly linear memory data. 66 /// 67 /// This is where all runtime information about defined linear memories in 68 /// this module lives. 69 /// 70 /// The `MemoryAllocationIndex` was given from our `InstanceAllocator` and 71 /// must be given back to the instance allocator when deallocating each 72 /// memory. 73 memories: PrimaryMap<DefinedMemoryIndex, (MemoryAllocationIndex, Memory)>, 74 75 /// WebAssembly table data. 76 /// 77 /// Like memories, this is only for defined tables in the module and 78 /// contains all of their runtime state. 79 /// 80 /// The `TableAllocationIndex` was given from our `InstanceAllocator` and 81 /// must be given back to the instance allocator when deallocating each 82 /// table. 83 tables: PrimaryMap<DefinedTableIndex, (TableAllocationIndex, Table)>, 84 85 /// Stores the dropped passive element segments in this instantiation by index. 86 /// If the index is present in the set, the segment has been dropped. 87 dropped_elements: EntitySet<ElemIndex>, 88 89 /// Stores the dropped passive data segments in this instantiation by index. 90 /// If the index is present in the set, the segment has been dropped. 91 dropped_data: EntitySet<DataIndex>, 92 93 /// Hosts can store arbitrary per-instance information here. 94 /// 95 /// Most of the time from Wasmtime this is `Box::new(())`, a noop 96 /// allocation, but some host-defined objects will store their state here. 97 host_state: Box<dyn Any + Send + Sync>, 98 99 /// A pointer to the `vmctx` field at the end of the `Instance`. 100 /// 101 /// If you're looking at this a reasonable question would be "why do we need 102 /// a pointer to ourselves?" because after all the pointer's value is 103 /// trivially derivable from any `&Instance` pointer. The rationale for this 104 /// field's existence is subtle, but it's required for correctness. The 105 /// short version is "this makes miri happy". 106 /// 107 /// The long version of why this field exists is that the rules that MIRI 108 /// uses to ensure pointers are used correctly have various conditions on 109 /// them depend on how pointers are used. More specifically if `*mut T` is 110 /// derived from `&mut T`, then that invalidates all prior pointers drived 111 /// from the `&mut T`. This means that while we liberally want to re-acquire 112 /// a `*mut VMContext` throughout the implementation of `Instance` the 113 /// trivial way, a function `fn vmctx(&mut Instance) -> *mut VMContext` 114 /// would effectively invalidate all prior `*mut VMContext` pointers 115 /// acquired. The purpose of this field is to serve as a sort of 116 /// source-of-truth for where `*mut VMContext` pointers come from. 117 /// 118 /// This field is initialized when the `Instance` is created with the 119 /// original allocation's pointer. That means that the provenance of this 120 /// pointer contains the entire allocation (both instance and `VMContext`). 121 /// This provenance bit is then "carried through" where `fn vmctx` will base 122 /// all returned pointers on this pointer itself. This provides the means of 123 /// never invalidating this pointer throughout MIRI and additionally being 124 /// able to still temporarily have `&mut Instance` methods and such. 125 /// 126 /// It's important to note, though, that this is not here purely for MIRI. 127 /// The careful construction of the `fn vmctx` method has ramifications on 128 /// the LLVM IR generated, for example. A historical CVE on Wasmtime, 129 /// GHSA-ch89-5g45-qwc7, was caused due to relying on undefined behavior. By 130 /// deriving VMContext pointers from this pointer it specifically hints to 131 /// LLVM that trickery is afoot and it properly informs `noalias` and such 132 /// annotations and analysis. More-or-less this pointer is actually loaded 133 /// in LLVM IR which helps defeat otherwise present aliasing optimizations, 134 /// which we want, since writes to this should basically never be optimized 135 /// out. 136 /// 137 /// As a final note it's worth pointing out that the machine code generated 138 /// for accessing `fn vmctx` is still as one would expect. This member isn't 139 /// actually ever loaded at runtime (or at least shouldn't be). Perhaps in 140 /// the future if the memory consumption of this field is a problem we could 141 /// shrink it slightly, but for now one extra pointer per wasm instance 142 /// seems not too bad. 143 vmctx_self_reference: SendSyncPtr<VMContext>, 144 145 // TODO: add support for multiple memories; `wmemcheck_state` corresponds to 146 // memory 0. 147 #[cfg(feature = "wmemcheck")] 148 pub(crate) wmemcheck_state: Option<Wmemcheck>, 149 150 /// Additional context used by compiled wasm code. This field is last, and 151 /// represents a dynamically-sized array that extends beyond the nominal 152 /// end of the struct (similar to a flexible array member). 153 vmctx: VMContext, 154 } 155 156 impl Instance { 157 /// Create an instance at the given memory address. 158 /// 159 /// It is assumed the memory was properly aligned and the 160 /// allocation was `alloc_size` in bytes. 161 unsafe fn new( 162 req: InstanceAllocationRequest, 163 memories: PrimaryMap<DefinedMemoryIndex, (MemoryAllocationIndex, Memory)>, 164 tables: PrimaryMap<DefinedTableIndex, (TableAllocationIndex, Table)>, 165 memory_plans: &PrimaryMap<MemoryIndex, MemoryPlan>, 166 ) -> InstanceHandle { 167 // The allocation must be *at least* the size required of `Instance`. 168 let layout = Self::alloc_layout(req.runtime_info.offsets()); 169 let ptr = alloc::alloc::alloc(layout); 170 if ptr.is_null() { 171 alloc::alloc::handle_alloc_error(layout); 172 } 173 let ptr = ptr.cast::<Instance>(); 174 175 let module = req.runtime_info.env_module(); 176 let dropped_elements = EntitySet::with_capacity(module.passive_elements.len()); 177 let dropped_data = EntitySet::with_capacity(module.passive_data_map.len()); 178 179 #[cfg(not(feature = "wmemcheck"))] 180 let _ = memory_plans; 181 182 ptr::write( 183 ptr, 184 Instance { 185 runtime_info: req.runtime_info.clone(), 186 memories, 187 tables, 188 dropped_elements, 189 dropped_data, 190 host_state: req.host_state, 191 vmctx_self_reference: SendSyncPtr::new(NonNull::new(ptr.add(1).cast()).unwrap()), 192 vmctx: VMContext { 193 _marker: core::marker::PhantomPinned, 194 }, 195 #[cfg(feature = "wmemcheck")] 196 wmemcheck_state: { 197 if req.wmemcheck { 198 let size = memory_plans 199 .iter() 200 .next() 201 .map(|plan| plan.1.memory.limits.min) 202 .unwrap_or(0) 203 * 64 204 * 1024; 205 Some(Wmemcheck::new(size as usize)) 206 } else { 207 None 208 } 209 }, 210 }, 211 ); 212 213 (*ptr).initialize_vmctx(module, req.runtime_info.offsets(), req.store, req.imports); 214 InstanceHandle { 215 instance: Some(SendSyncPtr::new(NonNull::new(ptr).unwrap())), 216 } 217 } 218 219 /// Converts the provided `*mut VMContext` to an `Instance` pointer and runs 220 /// the provided closure with the instance. 221 /// 222 /// This method will move the `vmctx` pointer backwards to point to the 223 /// original `Instance` that precedes it. The closure is provided a 224 /// temporary version of the `Instance` pointer with a constrained lifetime 225 /// to the closure to ensure it doesn't accidentally escape. 226 /// 227 /// # Unsafety 228 /// 229 /// Callers must validate that the `vmctx` pointer is a valid allocation 230 /// and that it's valid to acquire `&mut Instance` at this time. For example 231 /// this can't be called twice on the same `VMContext` to get two active 232 /// pointers to the same `Instance`. 233 #[inline] 234 pub unsafe fn from_vmctx<R>(vmctx: *mut VMContext, f: impl FnOnce(&mut Instance) -> R) -> R { 235 debug_assert!(!vmctx.is_null()); 236 let ptr = vmctx 237 .byte_sub(mem::size_of::<Instance>()) 238 .cast::<Instance>(); 239 f(&mut *ptr) 240 } 241 242 /// Helper function to access various locations offset from our `*mut 243 /// VMContext` object. 244 /// 245 /// # Safety 246 /// 247 /// This method is unsafe because the `offset` must be within bounds of the 248 /// `VMContext` object trailing this instance. 249 unsafe fn vmctx_plus_offset<T>(&self, offset: impl Into<u32>) -> *const T { 250 self.vmctx() 251 .byte_add(usize::try_from(offset.into()).unwrap()) 252 .cast() 253 } 254 255 /// Dual of `vmctx_plus_offset`, but for mutability. 256 unsafe fn vmctx_plus_offset_mut<T>(&mut self, offset: impl Into<u32>) -> *mut T { 257 self.vmctx() 258 .byte_add(usize::try_from(offset.into()).unwrap()) 259 .cast() 260 } 261 262 pub(crate) fn env_module(&self) -> &Arc<wasmtime_environ::Module> { 263 self.runtime_info.env_module() 264 } 265 266 pub(crate) fn runtime_module(&self) -> Option<&crate::Module> { 267 match &self.runtime_info { 268 ModuleRuntimeInfo::Module(m) => Some(m), 269 ModuleRuntimeInfo::Bare(_) => None, 270 } 271 } 272 273 /// Translate a module-level interned type index into an engine-level 274 /// interned type index. 275 pub fn engine_type_index(&self, module_index: ModuleInternedTypeIndex) -> VMSharedTypeIndex { 276 self.runtime_info.engine_type_index(module_index) 277 } 278 279 #[inline] 280 fn offsets(&self) -> &VMOffsets<HostPtr> { 281 self.runtime_info.offsets() 282 } 283 284 /// Return the indexed `VMFunctionImport`. 285 fn imported_function(&self, index: FuncIndex) -> &VMFunctionImport { 286 unsafe { &*self.vmctx_plus_offset(self.offsets().vmctx_vmfunction_import(index)) } 287 } 288 289 /// Return the index `VMTableImport`. 290 fn imported_table(&self, index: TableIndex) -> &VMTableImport { 291 unsafe { &*self.vmctx_plus_offset(self.offsets().vmctx_vmtable_import(index)) } 292 } 293 294 /// Return the indexed `VMMemoryImport`. 295 fn imported_memory(&self, index: MemoryIndex) -> &VMMemoryImport { 296 unsafe { &*self.vmctx_plus_offset(self.offsets().vmctx_vmmemory_import(index)) } 297 } 298 299 /// Return the indexed `VMGlobalImport`. 300 fn imported_global(&self, index: GlobalIndex) -> &VMGlobalImport { 301 unsafe { &*self.vmctx_plus_offset(self.offsets().vmctx_vmglobal_import(index)) } 302 } 303 304 /// Return the indexed `VMTableDefinition`. 305 #[allow(dead_code)] 306 fn table(&mut self, index: DefinedTableIndex) -> VMTableDefinition { 307 unsafe { *self.table_ptr(index) } 308 } 309 310 /// Updates the value for a defined table to `VMTableDefinition`. 311 fn set_table(&mut self, index: DefinedTableIndex, table: VMTableDefinition) { 312 unsafe { 313 *self.table_ptr(index) = table; 314 } 315 } 316 317 /// Return the indexed `VMTableDefinition`. 318 fn table_ptr(&mut self, index: DefinedTableIndex) -> *mut VMTableDefinition { 319 unsafe { self.vmctx_plus_offset_mut(self.offsets().vmctx_vmtable_definition(index)) } 320 } 321 322 /// Get a locally defined or imported memory. 323 pub(crate) fn get_memory(&self, index: MemoryIndex) -> VMMemoryDefinition { 324 if let Some(defined_index) = self.env_module().defined_memory_index(index) { 325 self.memory(defined_index) 326 } else { 327 let import = self.imported_memory(index); 328 unsafe { VMMemoryDefinition::load(import.from) } 329 } 330 } 331 332 /// Get a locally defined or imported memory. 333 #[cfg(feature = "threads")] 334 pub(crate) fn get_runtime_memory(&mut self, index: MemoryIndex) -> &mut Memory { 335 if let Some(defined_index) = self.env_module().defined_memory_index(index) { 336 unsafe { &mut *self.get_defined_memory(defined_index) } 337 } else { 338 let import = self.imported_memory(index); 339 unsafe { 340 let ptr = 341 Instance::from_vmctx(import.vmctx, |i| i.get_defined_memory(import.index)); 342 &mut *ptr 343 } 344 } 345 } 346 347 /// Return the indexed `VMMemoryDefinition`. 348 fn memory(&self, index: DefinedMemoryIndex) -> VMMemoryDefinition { 349 unsafe { VMMemoryDefinition::load(self.memory_ptr(index)) } 350 } 351 352 /// Set the indexed memory to `VMMemoryDefinition`. 353 fn set_memory(&self, index: DefinedMemoryIndex, mem: VMMemoryDefinition) { 354 unsafe { 355 *self.memory_ptr(index) = mem; 356 } 357 } 358 359 /// Return the indexed `VMMemoryDefinition`. 360 fn memory_ptr(&self, index: DefinedMemoryIndex) -> *mut VMMemoryDefinition { 361 unsafe { *self.vmctx_plus_offset(self.offsets().vmctx_vmmemory_pointer(index)) } 362 } 363 364 /// Return the indexed `VMGlobalDefinition`. 365 fn global_ptr(&mut self, index: DefinedGlobalIndex) -> *mut VMGlobalDefinition { 366 unsafe { self.vmctx_plus_offset_mut(self.offsets().vmctx_vmglobal_definition(index)) } 367 } 368 369 /// Get a raw pointer to the global at the given index regardless whether it 370 /// is defined locally or imported from another module. 371 /// 372 /// Panics if the index is out of bound or is the reserved value. 373 pub(crate) fn defined_or_imported_global_ptr( 374 &mut self, 375 index: GlobalIndex, 376 ) -> *mut VMGlobalDefinition { 377 if let Some(index) = self.env_module().defined_global_index(index) { 378 self.global_ptr(index) 379 } else { 380 self.imported_global(index).from 381 } 382 } 383 384 /// Get all globals within this instance. 385 /// 386 /// Returns both import and defined globals. 387 /// 388 /// Returns both exported and non-exported globals. 389 /// 390 /// Gives access to the full globals space. 391 pub fn all_globals<'a>( 392 &'a mut self, 393 ) -> impl ExactSizeIterator<Item = (GlobalIndex, ExportGlobal)> + 'a { 394 let module = self.env_module().clone(); 395 module.globals.keys().map(move |idx| { 396 ( 397 idx, 398 ExportGlobal { 399 definition: self.defined_or_imported_global_ptr(idx), 400 vmctx: self.vmctx(), 401 global: self.env_module().globals[idx], 402 }, 403 ) 404 }) 405 } 406 407 /// Get the globals defined in this instance (not imported). 408 pub fn defined_globals<'a>( 409 &'a mut self, 410 ) -> impl ExactSizeIterator<Item = (DefinedGlobalIndex, ExportGlobal)> + 'a { 411 let module = self.env_module().clone(); 412 module 413 .globals 414 .keys() 415 .skip(module.num_imported_globals) 416 .map(move |global_idx| { 417 let def_idx = module.defined_global_index(global_idx).unwrap(); 418 let global = ExportGlobal { 419 definition: self.global_ptr(def_idx), 420 vmctx: self.vmctx(), 421 global: self.env_module().globals[global_idx], 422 }; 423 (def_idx, global) 424 }) 425 } 426 427 /// Return a pointer to the interrupts structure 428 #[inline] 429 pub fn runtime_limits(&mut self) -> *mut *const VMRuntimeLimits { 430 unsafe { self.vmctx_plus_offset_mut(self.offsets().ptr.vmctx_runtime_limits()) } 431 } 432 433 /// Return a pointer to the global epoch counter used by this instance. 434 pub fn epoch_ptr(&mut self) -> *mut *const AtomicU64 { 435 unsafe { self.vmctx_plus_offset_mut(self.offsets().ptr.vmctx_epoch_ptr()) } 436 } 437 438 /// Return a pointer to the GC heap base pointer. 439 pub fn gc_heap_base(&mut self) -> *mut *mut u8 { 440 unsafe { self.vmctx_plus_offset_mut(self.offsets().ptr.vmctx_gc_heap_base()) } 441 } 442 443 /// Return a pointer to the GC heap bound. 444 pub fn gc_heap_bound(&mut self) -> *mut usize { 445 unsafe { self.vmctx_plus_offset_mut(self.offsets().ptr.vmctx_gc_heap_bound()) } 446 } 447 448 /// Return a pointer to the collector-specific heap data. 449 pub fn gc_heap_data(&mut self) -> *mut *mut u8 { 450 unsafe { self.vmctx_plus_offset_mut(self.offsets().ptr.vmctx_gc_heap_data()) } 451 } 452 453 /// Gets a pointer to this instance's `Store` which was originally 454 /// configured on creation. 455 /// 456 /// # Panics 457 /// 458 /// This will panic if the originally configured store was `None`. That can 459 /// happen for host functions so host functions can't be queried what their 460 /// original `Store` was since it's just retained as null (since host 461 /// functions are shared amongst threads and don't all share the same 462 /// store). 463 #[inline] 464 pub fn store(&self) -> *mut dyn VMStore { 465 let ptr = unsafe { 466 *self.vmctx_plus_offset::<*mut dyn VMStore>(self.offsets().ptr.vmctx_store()) 467 }; 468 debug_assert!(!ptr.is_null()); 469 ptr 470 } 471 472 /// Serves a similar purpose as `OpaqueRootScope`, but for situations where 473 /// you need to enter a GC scope (which would normally require mutably 474 /// borrowing the instance's underlying store) but also access to `Instance` 475 /// methods that will internally mutably borrow that store as well. 476 pub(crate) fn with_gc_lifo_scope<T>(&mut self, f: impl FnOnce(&mut Self) -> T) -> T { 477 let store_ptr = self.store(); 478 let scope = unsafe { (*store_ptr).gc_roots().enter_lifo_scope() }; 479 let _exit_scope = ExitScopeOnDrop(store_ptr, scope); 480 return f(self); 481 482 // Use an RAII type to exit the scope when it's dropped, so that we exit 483 // the scope even if `f` panics. 484 struct ExitScopeOnDrop(*mut dyn VMStore, usize); 485 486 impl Drop for ExitScopeOnDrop { 487 fn drop(&mut self) { 488 unsafe { 489 (*self.0).exit_gc_lifo_scope(self.1); 490 } 491 } 492 } 493 } 494 495 pub(crate) unsafe fn set_store(&mut self, store: Option<*mut dyn VMStore>) { 496 if let Some(store) = store { 497 *self.vmctx_plus_offset_mut(self.offsets().ptr.vmctx_store()) = store; 498 *self.runtime_limits() = (*store).vmruntime_limits(); 499 *self.epoch_ptr() = (*store).engine().epoch_counter(); 500 self.set_gc_heap((*store).gc_store_mut().ok()); 501 } else { 502 assert_eq!( 503 mem::size_of::<*mut dyn VMStore>(), 504 mem::size_of::<[*mut (); 2]>() 505 ); 506 *self.vmctx_plus_offset_mut::<[*mut (); 2]>(self.offsets().ptr.vmctx_store()) = 507 [ptr::null_mut(), ptr::null_mut()]; 508 *self.runtime_limits() = ptr::null_mut(); 509 *self.epoch_ptr() = ptr::null_mut(); 510 self.set_gc_heap(None); 511 } 512 } 513 514 unsafe fn set_gc_heap(&mut self, gc_store: Option<&mut GcStore>) { 515 if let Some(gc_store) = gc_store { 516 *self.gc_heap_base() = gc_store.gc_heap.vmctx_gc_heap_base(); 517 *self.gc_heap_bound() = gc_store.gc_heap.vmctx_gc_heap_bound(); 518 *self.gc_heap_data() = gc_store.gc_heap.vmctx_gc_heap_data(); 519 } else { 520 *self.gc_heap_base() = ptr::null_mut(); 521 *self.gc_heap_bound() = 0; 522 *self.gc_heap_data() = ptr::null_mut(); 523 } 524 } 525 526 pub(crate) unsafe fn set_callee(&mut self, callee: Option<NonNull<VMFunctionBody>>) { 527 *self.vmctx_plus_offset_mut(self.offsets().ptr.vmctx_callee()) = 528 callee.map_or(ptr::null_mut(), |c| c.as_ptr()); 529 } 530 531 /// Return a reference to the vmctx used by compiled wasm code. 532 #[inline] 533 pub fn vmctx(&self) -> *mut VMContext { 534 // The definition of this method is subtle but intentional. The goal 535 // here is that effectively this should return `&mut self.vmctx`, but 536 // it's not quite so simple. Some more documentation is available on the 537 // `vmctx_self_reference` field, but the general idea is that we're 538 // creating a pointer to return with proper provenance. Provenance is 539 // still in the works in Rust at the time of this writing but the load 540 // of the `self.vmctx_self_reference` field is important here as it 541 // affects how LLVM thinks about aliasing with respect to the returned 542 // pointer. 543 // 544 // The intention of this method is to codegen to machine code as `&mut 545 // self.vmctx`, however. While it doesn't show up like this in LLVM IR 546 // (there's an actual load of the field) it does look like that by the 547 // time the backend runs. (that's magic to me, the backend removing 548 // loads...) 549 // 550 // As a final minor note, strict provenance APIs are not stable on Rust 551 // today so the `sptr` crate is used. This crate provides the extension 552 // trait `Strict` but the method names conflict with the nightly methods 553 // so a different syntax is used to invoke methods here. 554 let addr = ptr::addr_of!(self.vmctx); 555 Strict::with_addr(self.vmctx_self_reference.as_ptr(), Strict::addr(addr)) 556 } 557 558 fn get_exported_func(&mut self, index: FuncIndex) -> ExportFunction { 559 let func_ref = self.get_func_ref(index).unwrap(); 560 let func_ref = NonNull::new(func_ref as *const VMFuncRef as *mut _).unwrap(); 561 ExportFunction { func_ref } 562 } 563 564 fn get_exported_table(&mut self, index: TableIndex) -> ExportTable { 565 let (definition, vmctx) = 566 if let Some(def_index) = self.env_module().defined_table_index(index) { 567 (self.table_ptr(def_index), self.vmctx()) 568 } else { 569 let import = self.imported_table(index); 570 (import.from, import.vmctx) 571 }; 572 ExportTable { 573 definition, 574 vmctx, 575 table: self.env_module().table_plans[index].clone(), 576 } 577 } 578 579 fn get_exported_memory(&mut self, index: MemoryIndex) -> ExportMemory { 580 let (definition, vmctx, def_index) = 581 if let Some(def_index) = self.env_module().defined_memory_index(index) { 582 (self.memory_ptr(def_index), self.vmctx(), def_index) 583 } else { 584 let import = self.imported_memory(index); 585 (import.from, import.vmctx, import.index) 586 }; 587 ExportMemory { 588 definition, 589 vmctx, 590 memory: self.env_module().memory_plans[index].clone(), 591 index: def_index, 592 } 593 } 594 595 fn get_exported_global(&mut self, index: GlobalIndex) -> ExportGlobal { 596 ExportGlobal { 597 definition: if let Some(def_index) = self.env_module().defined_global_index(index) { 598 self.global_ptr(def_index) 599 } else { 600 self.imported_global(index).from 601 }, 602 vmctx: self.vmctx(), 603 global: self.env_module().globals[index], 604 } 605 } 606 607 /// Return an iterator over the exports of this instance. 608 /// 609 /// Specifically, it provides access to the key-value pairs, where the keys 610 /// are export names, and the values are export declarations which can be 611 /// resolved `lookup_by_declaration`. 612 pub fn exports(&self) -> wasmparser::collections::index_map::Iter<String, EntityIndex> { 613 self.env_module().exports.iter() 614 } 615 616 /// Return a reference to the custom state attached to this instance. 617 #[inline] 618 pub fn host_state(&self) -> &dyn Any { 619 &*self.host_state 620 } 621 622 /// Return the table index for the given `VMTableDefinition`. 623 pub unsafe fn table_index(&mut self, table: &VMTableDefinition) -> DefinedTableIndex { 624 let index = DefinedTableIndex::new( 625 usize::try_from( 626 (table as *const VMTableDefinition) 627 .offset_from(self.table_ptr(DefinedTableIndex::new(0))), 628 ) 629 .unwrap(), 630 ); 631 assert!(index.index() < self.tables.len()); 632 index 633 } 634 635 /// Get the given memory's page size, in bytes. 636 pub(crate) fn memory_page_size(&self, index: MemoryIndex) -> usize { 637 usize::try_from(self.env_module().memory_plans[index].memory.page_size()).unwrap() 638 } 639 640 /// Grow memory by the specified amount of pages. 641 /// 642 /// Returns `None` if memory can't be grown by the specified amount 643 /// of pages. Returns `Some` with the old size in bytes if growth was 644 /// successful. 645 pub(crate) fn memory_grow( 646 &mut self, 647 index: MemoryIndex, 648 delta: u64, 649 ) -> Result<Option<usize>, Error> { 650 match self.env_module().defined_memory_index(index) { 651 Some(idx) => self.defined_memory_grow(idx, delta), 652 None => { 653 let import = self.imported_memory(index); 654 unsafe { 655 Instance::from_vmctx(import.vmctx, |i| { 656 i.defined_memory_grow(import.index, delta) 657 }) 658 } 659 } 660 } 661 } 662 663 fn defined_memory_grow( 664 &mut self, 665 idx: DefinedMemoryIndex, 666 delta: u64, 667 ) -> Result<Option<usize>, Error> { 668 let store = unsafe { &mut *self.store() }; 669 let memory = &mut self.memories[idx].1; 670 671 let result = unsafe { memory.grow(delta, Some(store)) }; 672 673 // Update the state used by a non-shared Wasm memory in case the base 674 // pointer and/or the length changed. 675 if memory.as_shared_memory().is_none() { 676 let vmmemory = memory.vmmemory(); 677 self.set_memory(idx, vmmemory); 678 } 679 680 result 681 } 682 683 pub(crate) fn table_element_type(&mut self, table_index: TableIndex) -> TableElementType { 684 unsafe { (*self.get_table(table_index)).element_type() } 685 } 686 687 /// Grow table by the specified amount of elements, filling them with 688 /// `init_value`. 689 /// 690 /// Returns `None` if table can't be grown by the specified amount of 691 /// elements, or if `init_value` is the wrong type of table element. 692 pub(crate) fn table_grow( 693 &mut self, 694 table_index: TableIndex, 695 delta: u64, 696 init_value: TableElement, 697 ) -> Result<Option<usize>, Error> { 698 self.with_defined_table_index_and_instance(table_index, |i, instance| { 699 instance.defined_table_grow(i, delta, init_value) 700 }) 701 } 702 703 fn defined_table_grow( 704 &mut self, 705 table_index: DefinedTableIndex, 706 delta: u64, 707 init_value: TableElement, 708 ) -> Result<Option<usize>, Error> { 709 let store = unsafe { &mut *self.store() }; 710 let table = &mut self 711 .tables 712 .get_mut(table_index) 713 .unwrap_or_else(|| panic!("no table for index {}", table_index.index())) 714 .1; 715 716 let result = unsafe { table.grow(delta, init_value, store) }; 717 718 // Keep the `VMContext` pointers used by compiled Wasm code up to 719 // date. 720 let element = self.tables[table_index].1.vmtable(); 721 self.set_table(table_index, element); 722 723 result 724 } 725 726 fn alloc_layout(offsets: &VMOffsets<HostPtr>) -> Layout { 727 let size = mem::size_of::<Self>() 728 .checked_add(usize::try_from(offsets.size_of_vmctx()).unwrap()) 729 .unwrap(); 730 let align = mem::align_of::<Self>(); 731 Layout::from_size_align(size, align).unwrap() 732 } 733 734 /// Construct a new VMFuncRef for the given function 735 /// (imported or defined in this module) and store into the given 736 /// location. Used during lazy initialization. 737 /// 738 /// Note that our current lazy-init scheme actually calls this every 739 /// time the funcref pointer is fetched; this turns out to be better 740 /// than tracking state related to whether it's been initialized 741 /// before, because resetting that state on (re)instantiation is 742 /// very expensive if there are many funcrefs. 743 fn construct_func_ref( 744 &mut self, 745 index: FuncIndex, 746 sig: ModuleInternedTypeIndex, 747 into: *mut VMFuncRef, 748 ) { 749 let type_index = unsafe { 750 let base: *const VMSharedTypeIndex = 751 *self.vmctx_plus_offset_mut(self.offsets().ptr.vmctx_type_ids_array()); 752 *base.add(sig.index()) 753 }; 754 755 let func_ref = if let Some(def_index) = self.env_module().defined_func_index(index) { 756 VMFuncRef { 757 array_call: self 758 .runtime_info 759 .array_to_wasm_trampoline(def_index) 760 .expect("should have array-to-Wasm trampoline for escaping function"), 761 wasm_call: Some(self.runtime_info.function(def_index)), 762 vmctx: VMOpaqueContext::from_vmcontext(self.vmctx()), 763 type_index, 764 } 765 } else { 766 let import = self.imported_function(index); 767 VMFuncRef { 768 array_call: import.array_call, 769 wasm_call: Some(import.wasm_call), 770 vmctx: import.vmctx, 771 type_index, 772 } 773 }; 774 775 // Safety: we have a `&mut self`, so we have exclusive access 776 // to this Instance. 777 unsafe { 778 ptr::write(into, func_ref); 779 } 780 } 781 782 /// Get a `&VMFuncRef` for the given `FuncIndex`. 783 /// 784 /// Returns `None` if the index is the reserved index value. 785 /// 786 /// The returned reference is a stable reference that won't be moved and can 787 /// be passed into JIT code. 788 pub(crate) fn get_func_ref(&mut self, index: FuncIndex) -> Option<*mut VMFuncRef> { 789 if index == FuncIndex::reserved_value() { 790 return None; 791 } 792 793 // Safety: we have a `&mut self`, so we have exclusive access 794 // to this Instance. 795 unsafe { 796 // For now, we eagerly initialize an funcref struct in-place 797 // whenever asked for a reference to it. This is mostly 798 // fine, because in practice each funcref is unlikely to be 799 // requested more than a few times: once-ish for funcref 800 // tables used for call_indirect (the usual compilation 801 // strategy places each function in the table at most once), 802 // and once or a few times when fetching exports via API. 803 // Note that for any case driven by table accesses, the lazy 804 // table init behaves like a higher-level cache layer that 805 // protects this initialization from happening multiple 806 // times, via that particular table at least. 807 // 808 // When `ref.func` becomes more commonly used or if we 809 // otherwise see a use-case where this becomes a hotpath, 810 // we can reconsider by using some state to track 811 // "uninitialized" explicitly, for example by zeroing the 812 // funcrefs (perhaps together with other 813 // zeroed-at-instantiate-time state) or using a separate 814 // is-initialized bitmap. 815 // 816 // We arrived at this design because zeroing memory is 817 // expensive, so it's better for instantiation performance 818 // if we don't have to track "is-initialized" state at 819 // all! 820 let func = &self.env_module().functions[index]; 821 let sig = func.signature; 822 let func_ref: *mut VMFuncRef = self 823 .vmctx_plus_offset_mut::<VMFuncRef>(self.offsets().vmctx_func_ref(func.func_ref)); 824 self.construct_func_ref(index, sig, func_ref); 825 826 Some(func_ref) 827 } 828 } 829 830 /// Get the passive elements segment at the given index. 831 /// 832 /// Returns an empty segment if the index is out of bounds or if the segment 833 /// has been dropped. 834 /// 835 /// The `storage` parameter should always be `None`; it is a bit of a hack 836 /// to work around lifetime issues. 837 pub(crate) fn passive_element_segment<'a>( 838 &self, 839 storage: &'a mut Option<(Arc<wasmtime_environ::Module>, TableSegmentElements)>, 840 elem_index: ElemIndex, 841 ) -> &'a TableSegmentElements { 842 debug_assert!(storage.is_none()); 843 *storage = Some(( 844 // TODO: this `clone()` shouldn't be necessary but is used for now to 845 // inform `rustc` that the lifetime of the elements here are 846 // disconnected from the lifetime of `self`. 847 self.env_module().clone(), 848 // NB: fall back to an expressions-based list of elements which 849 // doesn't have static type information (as opposed to 850 // `TableSegmentElements::Functions`) since we don't know what type 851 // is needed in the caller's context. Let the type be inferred by 852 // how they use the segment. 853 TableSegmentElements::Expressions(Box::new([])), 854 )); 855 let (module, empty) = storage.as_ref().unwrap(); 856 857 match module.passive_elements_map.get(&elem_index) { 858 Some(index) if !self.dropped_elements.contains(elem_index) => { 859 &module.passive_elements[*index] 860 } 861 _ => empty, 862 } 863 } 864 865 /// The `table.init` operation: initializes a portion of a table with a 866 /// passive element. 867 /// 868 /// # Errors 869 /// 870 /// Returns a `Trap` error when the range within the table is out of bounds 871 /// or the range within the passive element is out of bounds. 872 pub(crate) fn table_init( 873 &mut self, 874 table_index: TableIndex, 875 elem_index: ElemIndex, 876 dst: u64, 877 src: u64, 878 len: u64, 879 ) -> Result<(), Trap> { 880 let mut storage = None; 881 let elements = self.passive_element_segment(&mut storage, elem_index); 882 let mut const_evaluator = ConstExprEvaluator::default(); 883 self.table_init_segment(&mut const_evaluator, table_index, elements, dst, src, len) 884 } 885 886 pub(crate) fn table_init_segment( 887 &mut self, 888 const_evaluator: &mut ConstExprEvaluator, 889 table_index: TableIndex, 890 elements: &TableSegmentElements, 891 dst: u64, 892 src: u64, 893 len: u64, 894 ) -> Result<(), Trap> { 895 // https://webassembly.github.io/bulk-memory-operations/core/exec/instructions.html#exec-table-init 896 897 let table = unsafe { &mut *self.get_table(table_index) }; 898 let src = usize::try_from(src).map_err(|_| Trap::TableOutOfBounds)?; 899 let len = usize::try_from(len).map_err(|_| Trap::TableOutOfBounds)?; 900 let module = self.env_module().clone(); 901 902 match elements { 903 TableSegmentElements::Functions(funcs) => { 904 let elements = funcs 905 .get(src..) 906 .and_then(|s| s.get(..len)) 907 .ok_or(Trap::TableOutOfBounds)?; 908 table.init_func( 909 dst, 910 elements 911 .iter() 912 .map(|idx| self.get_func_ref(*idx).unwrap_or(ptr::null_mut())), 913 )?; 914 } 915 TableSegmentElements::Expressions(exprs) => { 916 let exprs = exprs 917 .get(src..) 918 .and_then(|s| s.get(..len)) 919 .ok_or(Trap::TableOutOfBounds)?; 920 let mut context = ConstEvalContext::new(self); 921 match module.table_plans[table_index] 922 .table 923 .ref_type 924 .heap_type 925 .top() 926 { 927 WasmHeapTopType::Extern => table.init_gc_refs( 928 dst, 929 exprs.iter().map(|expr| unsafe { 930 let raw = const_evaluator 931 .eval(&mut context, expr) 932 .expect("const expr should be valid"); 933 VMGcRef::from_raw_u32(raw.get_externref()) 934 }), 935 )?, 936 WasmHeapTopType::Any => table.init_gc_refs( 937 dst, 938 exprs.iter().map(|expr| unsafe { 939 let raw = const_evaluator 940 .eval(&mut context, expr) 941 .expect("const expr should be valid"); 942 VMGcRef::from_raw_u32(raw.get_anyref()) 943 }), 944 )?, 945 WasmHeapTopType::Func => table.init_func( 946 dst, 947 exprs.iter().map(|expr| unsafe { 948 const_evaluator 949 .eval(&mut context, expr) 950 .expect("const expr should be valid") 951 .get_funcref() 952 .cast() 953 }), 954 )?, 955 } 956 } 957 } 958 959 Ok(()) 960 } 961 962 /// Drop an element. 963 pub(crate) fn elem_drop(&mut self, elem_index: ElemIndex) { 964 // https://webassembly.github.io/reference-types/core/exec/instructions.html#exec-elem-drop 965 966 self.dropped_elements.insert(elem_index); 967 968 // Note that we don't check that we actually removed a segment because 969 // dropping a non-passive segment is a no-op (not a trap). 970 } 971 972 /// Get a locally-defined memory. 973 pub fn get_defined_memory(&mut self, index: DefinedMemoryIndex) -> *mut Memory { 974 ptr::addr_of_mut!(self.memories[index].1) 975 } 976 977 /// Do a `memory.copy` 978 /// 979 /// # Errors 980 /// 981 /// Returns a `Trap` error when the source or destination ranges are out of 982 /// bounds. 983 pub(crate) fn memory_copy( 984 &mut self, 985 dst_index: MemoryIndex, 986 dst: u64, 987 src_index: MemoryIndex, 988 src: u64, 989 len: u64, 990 ) -> Result<(), Trap> { 991 // https://webassembly.github.io/reference-types/core/exec/instructions.html#exec-memory-copy 992 993 let src_mem = self.get_memory(src_index); 994 let dst_mem = self.get_memory(dst_index); 995 996 let src = self.validate_inbounds(src_mem.current_length(), src, len)?; 997 let dst = self.validate_inbounds(dst_mem.current_length(), dst, len)?; 998 let len = usize::try_from(len).unwrap(); 999 1000 // Bounds and casts are checked above, by this point we know that 1001 // everything is safe. 1002 unsafe { 1003 let dst = dst_mem.base.add(dst); 1004 let src = src_mem.base.add(src); 1005 // FIXME audit whether this is safe in the presence of shared memory 1006 // (https://github.com/bytecodealliance/wasmtime/issues/4203). 1007 ptr::copy(src, dst, len); 1008 } 1009 1010 Ok(()) 1011 } 1012 1013 fn validate_inbounds(&self, max: usize, ptr: u64, len: u64) -> Result<usize, Trap> { 1014 let oob = || Trap::MemoryOutOfBounds; 1015 let end = ptr 1016 .checked_add(len) 1017 .and_then(|i| usize::try_from(i).ok()) 1018 .ok_or_else(oob)?; 1019 if end > max { 1020 Err(oob()) 1021 } else { 1022 Ok(ptr.try_into().unwrap()) 1023 } 1024 } 1025 1026 /// Perform the `memory.fill` operation on a locally defined memory. 1027 /// 1028 /// # Errors 1029 /// 1030 /// Returns a `Trap` error if the memory range is out of bounds. 1031 pub(crate) fn memory_fill( 1032 &mut self, 1033 memory_index: MemoryIndex, 1034 dst: u64, 1035 val: u8, 1036 len: u64, 1037 ) -> Result<(), Trap> { 1038 let memory = self.get_memory(memory_index); 1039 let dst = self.validate_inbounds(memory.current_length(), dst, len)?; 1040 let len = usize::try_from(len).unwrap(); 1041 1042 // Bounds and casts are checked above, by this point we know that 1043 // everything is safe. 1044 unsafe { 1045 let dst = memory.base.add(dst); 1046 // FIXME audit whether this is safe in the presence of shared memory 1047 // (https://github.com/bytecodealliance/wasmtime/issues/4203). 1048 ptr::write_bytes(dst, val, len); 1049 } 1050 1051 Ok(()) 1052 } 1053 1054 /// Get the internal storage range of a particular Wasm data segment. 1055 pub(crate) fn wasm_data_range(&self, index: DataIndex) -> Range<u32> { 1056 match self.env_module().passive_data_map.get(&index) { 1057 Some(range) if !self.dropped_data.contains(index) => range.clone(), 1058 _ => 0..0, 1059 } 1060 } 1061 1062 /// Given an internal storage range of a Wasm data segment (or subset of a 1063 /// Wasm data segment), get the data's raw bytes. 1064 pub(crate) fn wasm_data(&self, range: Range<u32>) -> &[u8] { 1065 let start = usize::try_from(range.start).unwrap(); 1066 let end = usize::try_from(range.end).unwrap(); 1067 &self.runtime_info.wasm_data()[start..end] 1068 } 1069 1070 /// Performs the `memory.init` operation. 1071 /// 1072 /// # Errors 1073 /// 1074 /// Returns a `Trap` error if the destination range is out of this module's 1075 /// memory's bounds or if the source range is outside the data segment's 1076 /// bounds. 1077 pub(crate) fn memory_init( 1078 &mut self, 1079 memory_index: MemoryIndex, 1080 data_index: DataIndex, 1081 dst: u64, 1082 src: u32, 1083 len: u32, 1084 ) -> Result<(), Trap> { 1085 let range = self.wasm_data_range(data_index); 1086 self.memory_init_segment(memory_index, range, dst, src, len) 1087 } 1088 1089 pub(crate) fn memory_init_segment( 1090 &mut self, 1091 memory_index: MemoryIndex, 1092 range: Range<u32>, 1093 dst: u64, 1094 src: u32, 1095 len: u32, 1096 ) -> Result<(), Trap> { 1097 // https://webassembly.github.io/bulk-memory-operations/core/exec/instructions.html#exec-memory-init 1098 1099 let memory = self.get_memory(memory_index); 1100 let data = self.wasm_data(range); 1101 let dst = self.validate_inbounds(memory.current_length(), dst, len.into())?; 1102 let src = self.validate_inbounds(data.len(), src.into(), len.into())?; 1103 let len = len as usize; 1104 1105 unsafe { 1106 let src_start = data.as_ptr().add(src); 1107 let dst_start = memory.base.add(dst); 1108 // FIXME audit whether this is safe in the presence of shared memory 1109 // (https://github.com/bytecodealliance/wasmtime/issues/4203). 1110 ptr::copy_nonoverlapping(src_start, dst_start, len); 1111 } 1112 1113 Ok(()) 1114 } 1115 1116 /// Drop the given data segment, truncating its length to zero. 1117 pub(crate) fn data_drop(&mut self, data_index: DataIndex) { 1118 self.dropped_data.insert(data_index); 1119 1120 // Note that we don't check that we actually removed a segment because 1121 // dropping a non-passive segment is a no-op (not a trap). 1122 } 1123 1124 /// Get a table by index regardless of whether it is locally-defined 1125 /// or an imported, foreign table. Ensure that the given range of 1126 /// elements in the table is lazily initialized. We define this 1127 /// operation all-in-one for safety, to ensure the lazy-init 1128 /// happens. 1129 /// 1130 /// Takes an `Iterator` for the index-range to lazy-initialize, 1131 /// for flexibility. This can be a range, single item, or empty 1132 /// sequence, for example. The iterator should return indices in 1133 /// increasing order, so that the break-at-out-of-bounds behavior 1134 /// works correctly. 1135 pub(crate) fn get_table_with_lazy_init( 1136 &mut self, 1137 table_index: TableIndex, 1138 range: impl Iterator<Item = u64>, 1139 ) -> *mut Table { 1140 self.with_defined_table_index_and_instance(table_index, |idx, instance| { 1141 instance.get_defined_table_with_lazy_init(idx, range) 1142 }) 1143 } 1144 1145 /// Gets the raw runtime table data structure owned by this instance 1146 /// given the provided `idx`. 1147 /// 1148 /// The `range` specified is eagerly initialized for funcref tables. 1149 pub fn get_defined_table_with_lazy_init( 1150 &mut self, 1151 idx: DefinedTableIndex, 1152 range: impl Iterator<Item = u64>, 1153 ) -> *mut Table { 1154 let elt_ty = self.tables[idx].1.element_type(); 1155 1156 if elt_ty == TableElementType::Func { 1157 for i in range { 1158 let gc_store = unsafe { (*self.store()).unwrap_gc_store_mut() }; 1159 let value = match self.tables[idx].1.get(gc_store, i) { 1160 Some(value) => value, 1161 None => { 1162 // Out-of-bounds; caller will handle by likely 1163 // throwing a trap. No work to do to lazy-init 1164 // beyond the end. 1165 break; 1166 } 1167 }; 1168 1169 if !value.is_uninit() { 1170 continue; 1171 } 1172 1173 // The table element `i` is uninitialized and is now being 1174 // initialized. This must imply that a `precompiled` list of 1175 // function indices is available for this table. The precompiled 1176 // list is extracted and then it is consulted with `i` to 1177 // determine the function that is going to be initialized. Note 1178 // that `i` may be outside the limits of the static 1179 // initialization so it's a fallible `get` instead of an index. 1180 let module = self.env_module(); 1181 let precomputed = match &module.table_initialization.initial_values[idx] { 1182 TableInitialValue::Null { precomputed } => precomputed, 1183 TableInitialValue::Expr(_) => unreachable!(), 1184 }; 1185 // Panicking here helps catch bugs rather than silently truncating by accident. 1186 let func_index = precomputed.get(usize::try_from(i).unwrap()).cloned(); 1187 let func_ref = func_index 1188 .and_then(|func_index| self.get_func_ref(func_index)) 1189 .unwrap_or(ptr::null_mut()); 1190 self.tables[idx] 1191 .1 1192 .set(i, TableElement::FuncRef(func_ref)) 1193 .expect("Table type should match and index should be in-bounds"); 1194 } 1195 } 1196 1197 ptr::addr_of_mut!(self.tables[idx].1) 1198 } 1199 1200 /// Get a table by index regardless of whether it is locally-defined or an 1201 /// imported, foreign table. 1202 pub(crate) fn get_table(&mut self, table_index: TableIndex) -> *mut Table { 1203 self.with_defined_table_index_and_instance(table_index, |idx, instance| { 1204 ptr::addr_of_mut!(instance.tables[idx].1) 1205 }) 1206 } 1207 1208 /// Get a locally-defined table. 1209 pub(crate) fn get_defined_table(&mut self, index: DefinedTableIndex) -> *mut Table { 1210 ptr::addr_of_mut!(self.tables[index].1) 1211 } 1212 1213 pub(crate) fn with_defined_table_index_and_instance<R>( 1214 &mut self, 1215 index: TableIndex, 1216 f: impl FnOnce(DefinedTableIndex, &mut Instance) -> R, 1217 ) -> R { 1218 if let Some(defined_table_index) = self.env_module().defined_table_index(index) { 1219 f(defined_table_index, self) 1220 } else { 1221 let import = self.imported_table(index); 1222 unsafe { 1223 Instance::from_vmctx(import.vmctx, |foreign_instance| { 1224 let foreign_table_def = import.from; 1225 let foreign_table_index = foreign_instance.table_index(&*foreign_table_def); 1226 f(foreign_table_index, foreign_instance) 1227 }) 1228 } 1229 } 1230 } 1231 1232 /// Initialize the VMContext data associated with this Instance. 1233 /// 1234 /// The `VMContext` memory is assumed to be uninitialized; any field 1235 /// that we need in a certain state will be explicitly written by this 1236 /// function. 1237 unsafe fn initialize_vmctx( 1238 &mut self, 1239 module: &Module, 1240 offsets: &VMOffsets<HostPtr>, 1241 store: StorePtr, 1242 imports: Imports, 1243 ) { 1244 assert!(ptr::eq(module, self.env_module().as_ref())); 1245 1246 *self.vmctx_plus_offset_mut(offsets.ptr.vmctx_magic()) = VMCONTEXT_MAGIC; 1247 self.set_callee(None); 1248 self.set_store(store.as_raw()); 1249 1250 // Initialize shared types 1251 let types = self.runtime_info.type_ids(); 1252 *self.vmctx_plus_offset_mut(offsets.ptr.vmctx_type_ids_array()) = types.as_ptr(); 1253 1254 // Initialize the built-in functions 1255 *self.vmctx_plus_offset_mut(offsets.ptr.vmctx_builtin_functions()) = 1256 &VMBuiltinFunctionsArray::INIT; 1257 1258 // Initialize the imports 1259 debug_assert_eq!(imports.functions.len(), module.num_imported_funcs); 1260 ptr::copy_nonoverlapping( 1261 imports.functions.as_ptr(), 1262 self.vmctx_plus_offset_mut(offsets.vmctx_imported_functions_begin()), 1263 imports.functions.len(), 1264 ); 1265 debug_assert_eq!(imports.tables.len(), module.num_imported_tables); 1266 ptr::copy_nonoverlapping( 1267 imports.tables.as_ptr(), 1268 self.vmctx_plus_offset_mut(offsets.vmctx_imported_tables_begin()), 1269 imports.tables.len(), 1270 ); 1271 debug_assert_eq!(imports.memories.len(), module.num_imported_memories); 1272 ptr::copy_nonoverlapping( 1273 imports.memories.as_ptr(), 1274 self.vmctx_plus_offset_mut(offsets.vmctx_imported_memories_begin()), 1275 imports.memories.len(), 1276 ); 1277 debug_assert_eq!(imports.globals.len(), module.num_imported_globals); 1278 ptr::copy_nonoverlapping( 1279 imports.globals.as_ptr(), 1280 self.vmctx_plus_offset_mut(offsets.vmctx_imported_globals_begin()), 1281 imports.globals.len(), 1282 ); 1283 1284 // N.B.: there is no need to initialize the funcrefs array because we 1285 // eagerly construct each element in it whenever asked for a reference 1286 // to that element. In other words, there is no state needed to track 1287 // the lazy-init, so we don't need to initialize any state now. 1288 1289 // Initialize the defined tables 1290 let mut ptr = self.vmctx_plus_offset_mut(offsets.vmctx_tables_begin()); 1291 for i in 0..module.table_plans.len() - module.num_imported_tables { 1292 ptr::write(ptr, self.tables[DefinedTableIndex::new(i)].1.vmtable()); 1293 ptr = ptr.add(1); 1294 } 1295 1296 // Initialize the defined memories. This fills in both the 1297 // `defined_memories` table and the `owned_memories` table at the same 1298 // time. Entries in `defined_memories` hold a pointer to a definition 1299 // (all memories) whereas the `owned_memories` hold the actual 1300 // definitions of memories owned (not shared) in the module. 1301 let mut ptr = self.vmctx_plus_offset_mut(offsets.vmctx_memories_begin()); 1302 let mut owned_ptr = self.vmctx_plus_offset_mut(offsets.vmctx_owned_memories_begin()); 1303 for i in 0..module.memory_plans.len() - module.num_imported_memories { 1304 let defined_memory_index = DefinedMemoryIndex::new(i); 1305 let memory_index = module.memory_index(defined_memory_index); 1306 if module.memory_plans[memory_index].memory.shared { 1307 let def_ptr = self.memories[defined_memory_index] 1308 .1 1309 .as_shared_memory() 1310 .unwrap() 1311 .vmmemory_ptr(); 1312 ptr::write(ptr, def_ptr.cast_mut()); 1313 } else { 1314 ptr::write(owned_ptr, self.memories[defined_memory_index].1.vmmemory()); 1315 ptr::write(ptr, owned_ptr); 1316 owned_ptr = owned_ptr.add(1); 1317 } 1318 ptr = ptr.add(1); 1319 } 1320 1321 // Initialize the defined globals 1322 let mut const_evaluator = ConstExprEvaluator::default(); 1323 self.initialize_vmctx_globals(&mut const_evaluator, module); 1324 } 1325 1326 unsafe fn initialize_vmctx_globals( 1327 &mut self, 1328 const_evaluator: &mut ConstExprEvaluator, 1329 module: &Module, 1330 ) { 1331 for (index, init) in module.global_initializers.iter() { 1332 let mut context = ConstEvalContext::new(self); 1333 let raw = const_evaluator 1334 .eval(&mut context, init) 1335 .expect("should be a valid const expr"); 1336 1337 let to = self.global_ptr(index); 1338 let wasm_ty = module.globals[module.global_index(index)].wasm_ty; 1339 1340 #[cfg(feature = "wmemcheck")] 1341 if index.index() == 0 && wasm_ty == wasmtime_environ::WasmValType::I32 { 1342 if let Some(wmemcheck) = &mut self.wmemcheck_state { 1343 let size = usize::try_from(raw.get_i32()).unwrap(); 1344 wmemcheck.set_stack_size(size); 1345 } 1346 } 1347 1348 ptr::write(to, VMGlobalDefinition::from_val_raw(wasm_ty, raw)); 1349 } 1350 } 1351 1352 fn wasm_fault(&self, addr: usize) -> Option<WasmFault> { 1353 let mut fault = None; 1354 for (_, (_, memory)) in self.memories.iter() { 1355 let accessible = memory.wasm_accessible(); 1356 if accessible.start <= addr && addr < accessible.end { 1357 // All linear memories should be disjoint so assert that no 1358 // prior fault has been found. 1359 assert!(fault.is_none()); 1360 fault = Some(WasmFault { 1361 memory_size: memory.byte_size(), 1362 wasm_address: u64::try_from(addr - accessible.start).unwrap(), 1363 }); 1364 } 1365 } 1366 fault 1367 } 1368 } 1369 1370 /// A handle holding an `Instance` of a WebAssembly module. 1371 #[derive(Debug)] 1372 pub struct InstanceHandle { 1373 instance: Option<SendSyncPtr<Instance>>, 1374 } 1375 1376 impl InstanceHandle { 1377 /// Creates an "empty" instance handle which internally has a null pointer 1378 /// to an instance. 1379 pub fn null() -> InstanceHandle { 1380 InstanceHandle { instance: None } 1381 } 1382 1383 /// Return a raw pointer to the vmctx used by compiled wasm code. 1384 #[inline] 1385 pub fn vmctx(&self) -> *mut VMContext { 1386 self.instance().vmctx() 1387 } 1388 1389 /// Return a reference to a module. 1390 pub fn module(&self) -> &Arc<Module> { 1391 self.instance().env_module() 1392 } 1393 1394 /// Lookup a function by index. 1395 pub fn get_exported_func(&mut self, export: FuncIndex) -> ExportFunction { 1396 self.instance_mut().get_exported_func(export) 1397 } 1398 1399 /// Lookup a global by index. 1400 pub fn get_exported_global(&mut self, export: GlobalIndex) -> ExportGlobal { 1401 self.instance_mut().get_exported_global(export) 1402 } 1403 1404 /// Lookup a memory by index. 1405 pub fn get_exported_memory(&mut self, export: MemoryIndex) -> ExportMemory { 1406 self.instance_mut().get_exported_memory(export) 1407 } 1408 1409 /// Lookup a table by index. 1410 pub fn get_exported_table(&mut self, export: TableIndex) -> ExportTable { 1411 self.instance_mut().get_exported_table(export) 1412 } 1413 1414 /// Lookup an item with the given index. 1415 pub fn get_export_by_index(&mut self, export: EntityIndex) -> Export { 1416 match export { 1417 EntityIndex::Function(i) => Export::Function(self.get_exported_func(i)), 1418 EntityIndex::Global(i) => Export::Global(self.get_exported_global(i)), 1419 EntityIndex::Table(i) => Export::Table(self.get_exported_table(i)), 1420 EntityIndex::Memory(i) => Export::Memory(self.get_exported_memory(i)), 1421 } 1422 } 1423 1424 /// Return an iterator over the exports of this instance. 1425 /// 1426 /// Specifically, it provides access to the key-value pairs, where the keys 1427 /// are export names, and the values are export declarations which can be 1428 /// resolved `lookup_by_declaration`. 1429 pub fn exports(&self) -> wasmparser::collections::index_map::Iter<String, EntityIndex> { 1430 self.instance().exports() 1431 } 1432 1433 /// Return a reference to the custom state attached to this instance. 1434 pub fn host_state(&self) -> &dyn Any { 1435 self.instance().host_state() 1436 } 1437 1438 /// Get a table defined locally within this module. 1439 pub fn get_defined_table(&mut self, index: DefinedTableIndex) -> *mut Table { 1440 self.instance_mut().get_defined_table(index) 1441 } 1442 1443 /// Get a table defined locally within this module, lazily 1444 /// initializing the given range first. 1445 pub fn get_defined_table_with_lazy_init( 1446 &mut self, 1447 index: DefinedTableIndex, 1448 range: impl Iterator<Item = u64>, 1449 ) -> *mut Table { 1450 let index = self.instance().env_module().table_index(index); 1451 self.instance_mut().get_table_with_lazy_init(index, range) 1452 } 1453 1454 /// Get all tables within this instance. 1455 /// 1456 /// Returns both import and defined tables. 1457 /// 1458 /// Returns both exported and non-exported tables. 1459 /// 1460 /// Gives access to the full tables space. 1461 pub fn all_tables<'a>( 1462 &'a mut self, 1463 ) -> impl ExactSizeIterator<Item = (TableIndex, ExportTable)> + 'a { 1464 let indices = (0..self.module().table_plans.len()) 1465 .map(|i| TableIndex::new(i)) 1466 .collect::<Vec<_>>(); 1467 indices.into_iter().map(|i| (i, self.get_exported_table(i))) 1468 } 1469 1470 /// Return the tables defined in this instance (not imported). 1471 pub fn defined_tables<'a>(&'a mut self) -> impl ExactSizeIterator<Item = ExportTable> + 'a { 1472 let num_imported = self.module().num_imported_tables; 1473 self.all_tables() 1474 .skip(num_imported) 1475 .map(|(_i, table)| table) 1476 } 1477 1478 /// Get all memories within this instance. 1479 /// 1480 /// Returns both import and defined memories. 1481 /// 1482 /// Returns both exported and non-exported memories. 1483 /// 1484 /// Gives access to the full memories space. 1485 pub fn all_memories<'a>( 1486 &'a mut self, 1487 ) -> impl ExactSizeIterator<Item = (MemoryIndex, ExportMemory)> + 'a { 1488 let indices = (0..self.module().memory_plans.len()) 1489 .map(|i| MemoryIndex::new(i)) 1490 .collect::<Vec<_>>(); 1491 indices 1492 .into_iter() 1493 .map(|i| (i, self.get_exported_memory(i))) 1494 } 1495 1496 /// Return the memories defined in this instance (not imported). 1497 pub fn defined_memories<'a>(&'a mut self) -> impl ExactSizeIterator<Item = ExportMemory> + 'a { 1498 let num_imported = self.module().num_imported_memories; 1499 self.all_memories() 1500 .skip(num_imported) 1501 .map(|(_i, memory)| memory) 1502 } 1503 1504 /// Get all globals within this instance. 1505 /// 1506 /// Returns both import and defined globals. 1507 /// 1508 /// Returns both exported and non-exported globals. 1509 /// 1510 /// Gives access to the full globals space. 1511 pub fn all_globals<'a>( 1512 &'a mut self, 1513 ) -> impl ExactSizeIterator<Item = (GlobalIndex, ExportGlobal)> + 'a { 1514 self.instance_mut().all_globals() 1515 } 1516 1517 /// Get the globals defined in this instance (not imported). 1518 pub fn defined_globals<'a>( 1519 &'a mut self, 1520 ) -> impl ExactSizeIterator<Item = (DefinedGlobalIndex, ExportGlobal)> + 'a { 1521 self.instance_mut().defined_globals() 1522 } 1523 1524 /// Return a reference to the contained `Instance`. 1525 #[inline] 1526 pub(crate) fn instance(&self) -> &Instance { 1527 unsafe { &*self.instance.unwrap().as_ptr() } 1528 } 1529 1530 pub(crate) fn instance_mut(&mut self) -> &mut Instance { 1531 unsafe { &mut *self.instance.unwrap().as_ptr() } 1532 } 1533 1534 /// Returns the `Store` pointer that was stored on creation 1535 #[inline] 1536 pub fn store(&self) -> *mut dyn VMStore { 1537 self.instance().store() 1538 } 1539 1540 /// Configure the `*mut dyn Store` internal pointer after-the-fact. 1541 /// 1542 /// This is provided for the original `Store` itself to configure the first 1543 /// self-pointer after the original `Box` has been initialized. 1544 pub unsafe fn set_store(&mut self, store: *mut dyn VMStore) { 1545 self.instance_mut().set_store(Some(store)); 1546 } 1547 1548 /// Returns a clone of this instance. 1549 /// 1550 /// This is unsafe because the returned handle here is just a cheap clone 1551 /// of the internals, there's no lifetime tracking around its validity. 1552 /// You'll need to ensure that the returned handles all go out of scope at 1553 /// the same time. 1554 #[inline] 1555 pub unsafe fn clone(&self) -> InstanceHandle { 1556 InstanceHandle { 1557 instance: self.instance, 1558 } 1559 } 1560 1561 /// Performs post-initialization of an instance after its handle has been 1562 /// created and registered with a store. 1563 /// 1564 /// Failure of this function means that the instance still must persist 1565 /// within the store since failure may indicate partial failure, or some 1566 /// state could be referenced by other instances. 1567 pub fn initialize(&mut self, module: &Module, is_bulk_memory: bool) -> Result<()> { 1568 allocator::initialize_instance(self.instance_mut(), module, is_bulk_memory) 1569 } 1570 1571 /// Attempts to convert from the host `addr` specified to a WebAssembly 1572 /// based address recorded in `WasmFault`. 1573 /// 1574 /// This method will check all linear memories that this instance contains 1575 /// to see if any of them contain `addr`. If one does then `Some` is 1576 /// returned with metadata about the wasm fault. Otherwise `None` is 1577 /// returned and `addr` doesn't belong to this instance. 1578 pub fn wasm_fault(&self, addr: usize) -> Option<WasmFault> { 1579 self.instance().wasm_fault(addr) 1580 } 1581 } 1582