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