1 use crate::linker::{Definition, DefinitionType}; 2 use crate::prelude::*; 3 use crate::runtime::vm::{ 4 Imports, InstanceAllocationRequest, ModuleRuntimeInfo, StorePtr, VMFuncRef, VMFunctionImport, 5 VMGlobalImport, VMMemoryImport, VMOpaqueContext, VMTableImport, VMTagImport, 6 }; 7 use crate::store::{InstanceId, StoreOpaque, Stored}; 8 use crate::types::matching; 9 use crate::{ 10 AsContextMut, Engine, Export, Extern, Func, Global, Memory, Module, ModuleExport, SharedMemory, 11 StoreContext, StoreContextMut, Table, Tag, TypedFunc, 12 }; 13 use alloc::sync::Arc; 14 use core::ptr::NonNull; 15 use wasmparser::WasmFeatures; 16 use wasmtime_environ::{ 17 EntityIndex, EntityType, FuncIndex, GlobalIndex, MemoryIndex, PrimaryMap, TableIndex, TagIndex, 18 TypeTrace, 19 }; 20 21 /// An instantiated WebAssembly module. 22 /// 23 /// This type represents the instantiation of a [`Module`]. Once instantiated 24 /// you can access the [`exports`](Instance::exports) which are of type 25 /// [`Extern`] and provide the ability to call functions, set globals, read 26 /// memory, etc. When interacting with any wasm code you'll want to make an 27 /// [`Instance`] to call any code or execute anything. 28 /// 29 /// Instances are owned by a [`Store`](crate::Store) which is passed in at 30 /// creation time. It's recommended to create instances with 31 /// [`Linker::instantiate`](crate::Linker::instantiate) or similar 32 /// [`Linker`](crate::Linker) methods, but a more low-level constructor is also 33 /// available as [`Instance::new`]. 34 #[derive(Copy, Clone, Debug)] 35 #[repr(transparent)] 36 pub struct Instance(Stored<InstanceData>); 37 38 pub(crate) struct InstanceData { 39 /// The id of the instance within the store, used to find the original 40 /// `InstanceHandle`. 41 id: InstanceId, 42 /// A lazily-populated list of exports of this instance. The order of 43 /// exports here matches the order of the exports in the original 44 /// module. 45 exports: Vec<Option<Extern>>, 46 } 47 48 impl InstanceData { 49 pub fn from_id(id: InstanceId) -> InstanceData { 50 InstanceData { 51 id, 52 exports: vec![], 53 } 54 } 55 } 56 57 impl Instance { 58 /// Creates a new [`Instance`] from the previously compiled [`Module`] and 59 /// list of `imports` specified. 60 /// 61 /// This method instantiates the `module` provided with the `imports`, 62 /// following the procedure in the [core specification][inst] to 63 /// instantiate. Instantiation can fail for a number of reasons (many 64 /// specified below), but if successful the `start` function will be 65 /// automatically run (if specified in the `module`) and then the 66 /// [`Instance`] will be returned. 67 /// 68 /// Per the WebAssembly spec, instantiation includes running the module's 69 /// start function, if it has one (not to be confused with the `_start` 70 /// function, which is not run). 71 /// 72 /// Note that this is a low-level function that just performs an 73 /// instantiation. See the [`Linker`](crate::Linker) struct for an API which 74 /// provides a convenient way to link imports and provides automatic Command 75 /// and Reactor behavior. 76 /// 77 /// ## Providing Imports 78 /// 79 /// The entries in the list of `imports` are intended to correspond 1:1 80 /// with the list of imports returned by [`Module::imports`]. Before 81 /// calling [`Instance::new`] you'll want to inspect the return value of 82 /// [`Module::imports`] and, for each import type, create an [`Extern`] 83 /// which corresponds to that type. These [`Extern`] values are all then 84 /// collected into a list and passed to this function. 85 /// 86 /// Note that this function is intentionally relatively low level. For an 87 /// easier time passing imports by doing name-based resolution it's 88 /// recommended to instead use the [`Linker`](crate::Linker) type. 89 /// 90 /// ## Errors 91 /// 92 /// This function can fail for a number of reasons, including, but not 93 /// limited to: 94 /// 95 /// * The number of `imports` provided doesn't match the number of imports 96 /// returned by the `module`'s [`Module::imports`] method. 97 /// * The type of any [`Extern`] doesn't match the corresponding 98 /// [`ExternType`] entry that it maps to. 99 /// * The `start` function in the instance, if present, traps. 100 /// * Module/instance resource limits are exceeded. 101 /// 102 /// When instantiation fails it's recommended to inspect the return value to 103 /// see why it failed, or bubble it upwards. If you'd like to specifically 104 /// check for trap errors, you can use `error.downcast::<Trap>()`. For more 105 /// about error handling see the [`Trap`] documentation. 106 /// 107 /// [`Trap`]: crate::Trap 108 /// 109 /// # Panics 110 /// 111 /// This function will panic if called with a store associated with a 112 /// [`asynchronous config`](crate::Config::async_support). This function 113 /// will also panic if any [`Extern`] supplied is not owned by `store`. 114 /// 115 /// [inst]: https://webassembly.github.io/spec/core/exec/modules.html#exec-instantiation 116 /// [`ExternType`]: crate::ExternType 117 pub fn new( 118 mut store: impl AsContextMut, 119 module: &Module, 120 imports: &[Extern], 121 ) -> Result<Instance> { 122 let mut store = store.as_context_mut(); 123 let imports = Instance::typecheck_externs(store.0, module, imports)?; 124 // Note that the unsafety here should be satisfied by the call to 125 // `typecheck_externs` above which satisfies the condition that all 126 // the imports are valid for this module. 127 unsafe { Instance::new_started(&mut store, module, imports.as_ref()) } 128 } 129 130 /// Same as [`Instance::new`], except for usage in [asynchronous stores]. 131 /// 132 /// For more details about this function see the documentation on 133 /// [`Instance::new`]. The only difference between these two methods is that 134 /// this one will asynchronously invoke the wasm start function in case it 135 /// calls any imported function which is an asynchronous host function (e.g. 136 /// created with [`Func::new_async`](crate::Func::new_async). 137 /// 138 /// # Panics 139 /// 140 /// This function will panic if called with a store associated with a 141 /// [`synchronous config`](crate::Config::new). This is only compatible with 142 /// stores associated with an [`asynchronous 143 /// config`](crate::Config::async_support). 144 /// 145 /// This function will also panic, like [`Instance::new`], if any [`Extern`] 146 /// specified does not belong to `store`. 147 #[cfg(feature = "async")] 148 pub async fn new_async<T>( 149 mut store: impl AsContextMut<Data = T>, 150 module: &Module, 151 imports: &[Extern], 152 ) -> Result<Instance> 153 where 154 T: Send, 155 { 156 let mut store = store.as_context_mut(); 157 let imports = Instance::typecheck_externs(store.0, module, imports)?; 158 // See `new` for notes on this unsafety 159 unsafe { Instance::new_started_async(&mut store, module, imports.as_ref()).await } 160 } 161 162 fn typecheck_externs( 163 store: &mut StoreOpaque, 164 module: &Module, 165 imports: &[Extern], 166 ) -> Result<OwnedImports> { 167 for import in imports { 168 if !import.comes_from_same_store(store) { 169 bail!("cross-`Store` instantiation is not currently supported"); 170 } 171 } 172 typecheck(module, imports, |cx, ty, item| { 173 let item = DefinitionType::from(store, item); 174 cx.definition(ty, &item) 175 })?; 176 let mut owned_imports = OwnedImports::new(module); 177 for import in imports { 178 owned_imports.push(import, store, module); 179 } 180 Ok(owned_imports) 181 } 182 183 /// Internal function to create an instance and run the start function. 184 /// 185 /// This function's unsafety is the same as `Instance::new_raw`. 186 pub(crate) unsafe fn new_started<T>( 187 store: &mut StoreContextMut<'_, T>, 188 module: &Module, 189 imports: Imports<'_>, 190 ) -> Result<Instance> { 191 assert!( 192 !store.0.async_support(), 193 "must use async instantiation when async support is enabled", 194 ); 195 Self::new_started_impl(store, module, imports) 196 } 197 198 /// Internal function to create an instance and run the start function. 199 /// 200 /// ONLY CALL THIS IF YOU HAVE ALREADY CHECKED FOR ASYNCNESS AND HANDLED 201 /// THE FIBER NONSENSE 202 pub(crate) unsafe fn new_started_impl<T>( 203 store: &mut StoreContextMut<'_, T>, 204 module: &Module, 205 imports: Imports<'_>, 206 ) -> Result<Instance> { 207 let (instance, start) = Instance::new_raw(store.0, module, imports)?; 208 if let Some(start) = start { 209 instance.start_raw(store, start)?; 210 } 211 Ok(instance) 212 } 213 214 /// Internal function to create an instance and run the start function. 215 /// 216 /// This function's unsafety is the same as `Instance::new_raw`. 217 #[cfg(feature = "async")] 218 async unsafe fn new_started_async<T>( 219 store: &mut StoreContextMut<'_, T>, 220 module: &Module, 221 imports: Imports<'_>, 222 ) -> Result<Instance> 223 where 224 T: Send, 225 { 226 assert!( 227 store.0.async_support(), 228 "must use sync instantiation when async support is disabled", 229 ); 230 231 store 232 .on_fiber(|store| Self::new_started_impl(store, module, imports)) 233 .await? 234 } 235 236 /// Internal function to create an instance which doesn't have its `start` 237 /// function run yet. 238 /// 239 /// This is not intended to be exposed from Wasmtime, it's intended to 240 /// refactor out common code from `new_started` and `new_started_async`. 241 /// 242 /// Note that this step needs to be run on a fiber in async mode even 243 /// though it doesn't do any blocking work because an async resource 244 /// limiter may need to yield. 245 /// 246 /// # Unsafety 247 /// 248 /// This method is unsafe because it does not type-check the `imports` 249 /// provided. The `imports` provided must be suitable for the module 250 /// provided as well. 251 unsafe fn new_raw( 252 store: &mut StoreOpaque, 253 module: &Module, 254 imports: Imports<'_>, 255 ) -> Result<(Instance, Option<FuncIndex>)> { 256 if !Engine::same(store.engine(), module.engine()) { 257 bail!("cross-`Engine` instantiation is not currently supported"); 258 } 259 store.bump_resource_counts(module)?; 260 261 // Allocate the GC heap, if necessary. 262 if store.engine().features().gc_types() { 263 let _ = store.gc_store_mut()?; 264 } 265 266 let compiled_module = module.compiled_module(); 267 268 // Register the module just before instantiation to ensure we keep the module 269 // properly referenced while in use by the store. 270 let module_id = store.modules_mut().register_module(module); 271 store.fill_func_refs(); 272 273 // The first thing we do is issue an instance allocation request 274 // to the instance allocator. This, on success, will give us an 275 // instance handle. 276 // 277 // Note that the `host_state` here is a pointer back to the 278 // `Instance` we'll be returning from this function. This is a 279 // circular reference so we can't construct it before we construct 280 // this instance, so we determine what the ID is and then assert 281 // it's the same later when we do actually insert it. 282 let instance_to_be = store.store_data().next_id::<InstanceData>(); 283 284 let mut instance_handle = 285 store 286 .engine() 287 .allocator() 288 .allocate_module(InstanceAllocationRequest { 289 runtime_info: &ModuleRuntimeInfo::Module(module.clone()), 290 imports, 291 host_state: Box::new(Instance(instance_to_be)), 292 store: StorePtr::new(store.traitobj()), 293 wmemcheck: store.engine().config().wmemcheck, 294 pkey: store.get_pkey(), 295 tunables: store.engine().tunables(), 296 })?; 297 298 // The instance still has lots of setup, for example 299 // data/elements/start/etc. This can all fail, but even on failure 300 // the instance may persist some state via previous successful 301 // initialization. For this reason once we have an instance handle 302 // we immediately insert it into the store to keep it alive. 303 // 304 // Note that we `clone` the instance handle just to make easier 305 // working the borrow checker here easier. Technically the `&mut 306 // instance` has somewhat of a borrow on `store` (which 307 // conflicts with the borrow on `store.engine`) but this doesn't 308 // matter in practice since initialization isn't even running any 309 // code here anyway. 310 let id = store.add_instance(instance_handle.clone(), module_id); 311 312 // Additionally, before we start doing fallible instantiation, we 313 // do one more step which is to insert an `InstanceData` 314 // corresponding to this instance. This `InstanceData` can be used 315 // via `Caller::get_export` if our instance's state "leaks" into 316 // other instances, even if we don't return successfully from this 317 // function. 318 // 319 // We don't actually load all exports from the instance at this 320 // time, instead preferring to lazily load them as they're demanded. 321 // For module/instance exports, though, those aren't actually 322 // stored in the instance handle so we need to immediately handle 323 // those here. 324 let instance = { 325 let exports = vec![None; compiled_module.module().exports.len()]; 326 let data = InstanceData { id, exports }; 327 Instance::from_wasmtime(data, store) 328 }; 329 330 // double-check our guess of what the new instance's ID would be 331 // was actually correct. 332 assert_eq!(instance.0, instance_to_be); 333 334 // Now that we've recorded all information we need to about this 335 // instance within a `Store` we can start performing fallible 336 // initialization. Note that we still defer the `start` function to 337 // later since that may need to run asynchronously. 338 // 339 // If this returns an error (or if the start function traps) then 340 // any other initialization which may have succeeded which placed 341 // items from this instance into other instances should be ok when 342 // those items are loaded and run we'll have all the metadata to 343 // look at them. 344 let bulk_memory = store 345 .engine() 346 .features() 347 .contains(WasmFeatures::BULK_MEMORY); 348 instance_handle.initialize(store, compiled_module.module(), bulk_memory)?; 349 350 Ok((instance, compiled_module.module().start_func)) 351 } 352 353 pub(crate) fn from_wasmtime(handle: InstanceData, store: &mut StoreOpaque) -> Instance { 354 Instance(store.store_data_mut().insert(handle)) 355 } 356 357 fn start_raw<T>(&self, store: &mut StoreContextMut<'_, T>, start: FuncIndex) -> Result<()> { 358 let id = store.0.store_data()[self.0].id; 359 // If a start function is present, invoke it. Make sure we use all the 360 // trap-handling configuration in `store` as well. 361 let instance = store.0.instance_mut(id); 362 let f = instance.get_exported_func(start); 363 let caller_vmctx = instance.vmctx(); 364 unsafe { 365 super::func::invoke_wasm_and_catch_traps(store, |_default_caller, vm| { 366 f.func_ref.as_ref().array_call( 367 vm, 368 VMOpaqueContext::from_vmcontext(caller_vmctx), 369 NonNull::from(&mut []), 370 ) 371 })?; 372 } 373 Ok(()) 374 } 375 376 /// Get this instance's module. 377 pub fn module<'a, T: 'a>(&self, store: impl Into<StoreContext<'a, T>>) -> &'a Module { 378 self._module(store.into().0) 379 } 380 381 fn _module<'a>(&self, store: &'a StoreOpaque) -> &'a Module { 382 let InstanceData { id, .. } = store[self.0]; 383 store.module_for_instance(id).unwrap() 384 } 385 386 /// Returns the list of exported items from this [`Instance`]. 387 /// 388 /// # Panics 389 /// 390 /// Panics if `store` does not own this instance. 391 pub fn exports<'a, T: 'a>( 392 &'a self, 393 store: impl Into<StoreContextMut<'a, T>>, 394 ) -> impl ExactSizeIterator<Item = Export<'a>> + 'a { 395 self._exports(store.into().0) 396 } 397 398 fn _exports<'a>( 399 &'a self, 400 store: &'a mut StoreOpaque, 401 ) -> impl ExactSizeIterator<Item = Export<'a>> + 'a { 402 // If this is an `Instantiated` instance then all the `exports` may not 403 // be filled in. Fill them all in now if that's the case. 404 let InstanceData { exports, id, .. } = &store[self.0]; 405 if exports.iter().any(|e| e.is_none()) { 406 let module = Arc::clone(store.instance(*id).module()); 407 let data = &store[self.0]; 408 let id = data.id; 409 410 for name in module.exports.keys() { 411 let instance = store.instance(id); 412 if let Some((export_name_index, _, &entity)) = 413 instance.module().exports.get_full(name) 414 { 415 self._get_export(store, entity, export_name_index); 416 } 417 } 418 } 419 420 let data = &store.store_data()[self.0]; 421 let module = store.instance(data.id).module(); 422 module 423 .exports 424 .iter() 425 .zip(&data.exports) 426 .map(|((name, _), export)| Export::new(name, export.clone().unwrap())) 427 } 428 429 /// Looks up an exported [`Extern`] value by name. 430 /// 431 /// This method will search the module for an export named `name` and return 432 /// the value, if found. 433 /// 434 /// Returns `None` if there was no export named `name`. 435 /// 436 /// # Panics 437 /// 438 /// Panics if `store` does not own this instance. 439 /// 440 /// # Why does `get_export` take a mutable context? 441 /// 442 /// This method requires a mutable context because an instance's exports are 443 /// lazily populated, and we cache them as they are accessed. This makes 444 /// instantiating a module faster, but also means this method requires a 445 /// mutable context. 446 pub fn get_export(&self, mut store: impl AsContextMut, name: &str) -> Option<Extern> { 447 let store = store.as_context_mut().0; 448 let data = &store[self.0]; 449 let instance = store.instance(data.id); 450 let (export_name_index, _, &entity) = instance.module().exports.get_full(name)?; 451 self._get_export(store, entity, export_name_index) 452 } 453 454 /// Looks up an exported [`Extern`] value by a [`ModuleExport`] value. 455 /// 456 /// This is similar to [`Instance::get_export`] but uses a [`ModuleExport`] value to avoid 457 /// string lookups where possible. [`ModuleExport`]s can be obtained by calling 458 /// [`Module::get_export_index`] on the [`Module`] that this instance was instantiated with. 459 /// 460 /// This method will search the module for an export with a matching entity index and return 461 /// the value, if found. 462 /// 463 /// Returns `None` if there was no export with a matching entity index. 464 /// # Panics 465 /// 466 /// Panics if `store` does not own this instance. 467 pub fn get_module_export( 468 &self, 469 mut store: impl AsContextMut, 470 export: &ModuleExport, 471 ) -> Option<Extern> { 472 let store = store.as_context_mut().0; 473 474 // Verify the `ModuleExport` matches the module used in this instance. 475 if self._module(store).id() != export.module { 476 return None; 477 } 478 479 self._get_export(store, export.entity, export.export_name_index) 480 } 481 482 fn _get_export( 483 &self, 484 store: &mut StoreOpaque, 485 entity: EntityIndex, 486 export_name_index: usize, 487 ) -> Option<Extern> { 488 // Instantiated instances will lazily fill in exports, so we process 489 // all that lazy logic here. 490 let data = &store[self.0]; 491 492 if let Some(export) = &data.exports[export_name_index] { 493 return Some(export.clone()); 494 } 495 496 let instance = store.instance_mut(data.id); // Reborrow the &mut InstanceHandle 497 let item = 498 unsafe { Extern::from_wasmtime_export(instance.get_export_by_index(entity), store) }; 499 let data = &mut store[self.0]; 500 data.exports[export_name_index] = Some(item.clone()); 501 Some(item) 502 } 503 504 /// Looks up an exported [`Func`] value by name. 505 /// 506 /// Returns `None` if there was no export named `name`, or if there was but 507 /// it wasn't a function. 508 /// 509 /// # Panics 510 /// 511 /// Panics if `store` does not own this instance. 512 pub fn get_func(&self, store: impl AsContextMut, name: &str) -> Option<Func> { 513 self.get_export(store, name)?.into_func() 514 } 515 516 /// Looks up an exported [`Func`] value by name and with its type. 517 /// 518 /// This function is a convenience wrapper over [`Instance::get_func`] and 519 /// [`Func::typed`]. For more information see the linked documentation. 520 /// 521 /// Returns an error if `name` isn't a function export or if the export's 522 /// type did not match `Params` or `Results` 523 /// 524 /// # Panics 525 /// 526 /// Panics if `store` does not own this instance. 527 pub fn get_typed_func<Params, Results>( 528 &self, 529 mut store: impl AsContextMut, 530 name: &str, 531 ) -> Result<TypedFunc<Params, Results>> 532 where 533 Params: crate::WasmParams, 534 Results: crate::WasmResults, 535 { 536 let f = self 537 .get_export(store.as_context_mut(), name) 538 .and_then(|f| f.into_func()) 539 .ok_or_else(|| anyhow!("failed to find function export `{}`", name))?; 540 Ok(f.typed::<Params, Results>(store) 541 .with_context(|| format!("failed to convert function `{name}` to given type"))?) 542 } 543 544 /// Looks up an exported [`Table`] value by name. 545 /// 546 /// Returns `None` if there was no export named `name`, or if there was but 547 /// it wasn't a table. 548 /// 549 /// # Panics 550 /// 551 /// Panics if `store` does not own this instance. 552 pub fn get_table(&self, store: impl AsContextMut, name: &str) -> Option<Table> { 553 self.get_export(store, name)?.into_table() 554 } 555 556 /// Looks up an exported [`Memory`] value by name. 557 /// 558 /// Returns `None` if there was no export named `name`, or if there was but 559 /// it wasn't a memory. 560 /// 561 /// # Panics 562 /// 563 /// Panics if `store` does not own this instance. 564 pub fn get_memory(&self, store: impl AsContextMut, name: &str) -> Option<Memory> { 565 self.get_export(store, name)?.into_memory() 566 } 567 568 /// Looks up an exported [`SharedMemory`] value by name. 569 /// 570 /// Returns `None` if there was no export named `name`, or if there was but 571 /// it wasn't a shared memory. 572 /// 573 /// # Panics 574 /// 575 /// Panics if `store` does not own this instance. 576 pub fn get_shared_memory( 577 &self, 578 mut store: impl AsContextMut, 579 name: &str, 580 ) -> Option<SharedMemory> { 581 let mut store = store.as_context_mut(); 582 self.get_export(&mut store, name)?.into_shared_memory() 583 } 584 585 /// Looks up an exported [`Global`] value by name. 586 /// 587 /// Returns `None` if there was no export named `name`, or if there was but 588 /// it wasn't a global. 589 /// 590 /// # Panics 591 /// 592 /// Panics if `store` does not own this instance. 593 pub fn get_global(&self, store: impl AsContextMut, name: &str) -> Option<Global> { 594 self.get_export(store, name)?.into_global() 595 } 596 597 /// Looks up a tag [`Tag`] by name. 598 /// 599 /// Returns `None` if there was no export named `name`, or if there was but 600 /// it wasn't a tag. 601 /// 602 /// # Panics 603 /// 604 /// Panics if `store` does not own this instance. 605 pub fn get_tag(&self, store: impl AsContextMut, name: &str) -> Option<Tag> { 606 self.get_export(store, name)?.into_tag() 607 } 608 609 #[cfg(feature = "component-model")] 610 pub(crate) fn id(&self, store: &StoreOpaque) -> InstanceId { 611 store[self.0].id 612 } 613 614 /// Get all globals within this instance. 615 /// 616 /// Returns both import and defined globals. 617 /// 618 /// Returns both exported and non-exported globals. 619 /// 620 /// Gives access to the full globals space. 621 #[cfg(feature = "coredump")] 622 pub(crate) fn all_globals<'a>( 623 &'a self, 624 store: &'a mut StoreOpaque, 625 ) -> impl ExactSizeIterator<Item = (GlobalIndex, Global)> + 'a { 626 let data = &store[self.0]; 627 let instance = store.instance_mut(data.id); 628 instance 629 .all_globals() 630 .collect::<Vec<_>>() 631 .into_iter() 632 .map(|(i, g)| (i, unsafe { Global::from_wasmtime_global(g, store) })) 633 } 634 635 /// Get all memories within this instance. 636 /// 637 /// Returns both import and defined memories. 638 /// 639 /// Returns both exported and non-exported memories. 640 /// 641 /// Gives access to the full memories space. 642 #[cfg(feature = "coredump")] 643 pub(crate) fn all_memories<'a>( 644 &'a self, 645 store: &'a mut StoreOpaque, 646 ) -> impl ExactSizeIterator<Item = (MemoryIndex, Memory)> + 'a { 647 let data = &store[self.0]; 648 let instance = store.instance_mut(data.id); 649 instance 650 .all_memories() 651 .collect::<Vec<_>>() 652 .into_iter() 653 .map(|(i, m)| (i, unsafe { Memory::from_wasmtime_memory(m, store) })) 654 } 655 } 656 657 pub(crate) struct OwnedImports { 658 functions: PrimaryMap<FuncIndex, VMFunctionImport>, 659 tables: PrimaryMap<TableIndex, VMTableImport>, 660 memories: PrimaryMap<MemoryIndex, VMMemoryImport>, 661 globals: PrimaryMap<GlobalIndex, VMGlobalImport>, 662 tags: PrimaryMap<TagIndex, VMTagImport>, 663 } 664 665 impl OwnedImports { 666 fn new(module: &Module) -> OwnedImports { 667 let mut ret = OwnedImports::empty(); 668 ret.reserve(module); 669 return ret; 670 } 671 672 pub(crate) fn empty() -> OwnedImports { 673 OwnedImports { 674 functions: PrimaryMap::new(), 675 tables: PrimaryMap::new(), 676 memories: PrimaryMap::new(), 677 globals: PrimaryMap::new(), 678 tags: PrimaryMap::new(), 679 } 680 } 681 682 pub(crate) fn reserve(&mut self, module: &Module) { 683 let raw = module.compiled_module().module(); 684 self.functions.reserve(raw.num_imported_funcs); 685 self.tables.reserve(raw.num_imported_tables); 686 self.memories.reserve(raw.num_imported_memories); 687 self.globals.reserve(raw.num_imported_globals); 688 self.tags.reserve(raw.num_imported_tags); 689 } 690 691 #[cfg(feature = "component-model")] 692 pub(crate) fn clear(&mut self) { 693 self.functions.clear(); 694 self.tables.clear(); 695 self.memories.clear(); 696 self.globals.clear(); 697 self.tags.clear(); 698 } 699 700 fn push(&mut self, item: &Extern, store: &mut StoreOpaque, module: &Module) { 701 match item { 702 Extern::Func(i) => { 703 self.functions.push(i.vmimport(store, module)); 704 } 705 Extern::Global(i) => { 706 self.globals.push(i.vmimport(store)); 707 } 708 Extern::Table(i) => { 709 self.tables.push(i.vmimport(store)); 710 } 711 Extern::Memory(i) => { 712 self.memories.push(i.vmimport(store)); 713 } 714 Extern::SharedMemory(i) => { 715 self.memories.push(i.vmimport(store)); 716 } 717 Extern::Tag(i) => { 718 self.tags.push(i.vmimport(store)); 719 } 720 } 721 } 722 723 /// Note that this is unsafe as the validity of `item` is not verified and 724 /// it contains a bunch of raw pointers. 725 #[cfg(feature = "component-model")] 726 pub(crate) unsafe fn push_export(&mut self, item: &crate::runtime::vm::Export) { 727 match item { 728 crate::runtime::vm::Export::Function(f) => { 729 let f = f.func_ref.as_ref(); 730 self.functions.push(VMFunctionImport { 731 wasm_call: f.wasm_call.unwrap(), 732 array_call: f.array_call, 733 vmctx: f.vmctx, 734 }); 735 } 736 crate::runtime::vm::Export::Global(g) => { 737 self.globals.push(VMGlobalImport { 738 from: g.definition.into(), 739 }); 740 } 741 crate::runtime::vm::Export::Table(t) => { 742 self.tables.push(VMTableImport { 743 from: t.definition.into(), 744 vmctx: t.vmctx.into(), 745 }); 746 } 747 crate::runtime::vm::Export::Memory(m) => { 748 self.memories.push(VMMemoryImport { 749 from: m.definition.into(), 750 vmctx: m.vmctx.into(), 751 index: m.index, 752 }); 753 } 754 crate::runtime::vm::Export::Tag(t) => { 755 self.tags.push(VMTagImport { 756 from: t.definition.into(), 757 }); 758 } 759 } 760 } 761 762 pub(crate) fn as_ref(&self) -> Imports<'_> { 763 Imports { 764 tables: self.tables.values().as_slice(), 765 globals: self.globals.values().as_slice(), 766 memories: self.memories.values().as_slice(), 767 functions: self.functions.values().as_slice(), 768 tags: self.tags.values().as_slice(), 769 } 770 } 771 } 772 773 /// An instance, pre-instantiation, that is ready to be instantiated. 774 /// 775 /// This structure represents an instance *just before* it was instantiated, 776 /// after all type-checking and imports have been resolved. The only thing left 777 /// to do for this instance is to actually run the process of instantiation. 778 /// 779 /// Note that an `InstancePre` may not be tied to any particular [`Store`] if 780 /// none of the imports it closed over are tied to any particular [`Store`]. 781 /// 782 /// This structure is created through the [`Linker::instantiate_pre`] method, 783 /// which also has some more information and examples. 784 /// 785 /// [`Store`]: crate::Store 786 /// [`Linker::instantiate_pre`]: crate::Linker::instantiate_pre 787 pub struct InstancePre<T> { 788 module: Module, 789 790 /// The items which this `InstancePre` use to instantiate the `module` 791 /// provided, passed to `Instance::new_started` after inserting them into a 792 /// `Store`. 793 /// 794 /// Note that this is stored as an `Arc<[T]>` to quickly move a strong 795 /// reference to everything internally into a `Store<T>` without having to 796 /// clone each individual item. 797 items: Arc<[Definition]>, 798 799 /// A count of `Definition::HostFunc` entries in `items` above to 800 /// preallocate space in a `Store` up front for all entries to be inserted. 801 host_funcs: usize, 802 803 /// The `VMFuncRef`s for the functions in `items` that do not 804 /// have a `wasm_call` trampoline. We pre-allocate and pre-patch these 805 /// `VMFuncRef`s so that we don't have to do it at 806 /// instantiation time. 807 /// 808 /// This is an `Arc<[T]>` for the same reason as `items`. 809 func_refs: Arc<[VMFuncRef]>, 810 811 _marker: core::marker::PhantomData<fn() -> T>, 812 } 813 814 /// InstancePre's clone does not require T: Clone 815 impl<T> Clone for InstancePre<T> { 816 fn clone(&self) -> Self { 817 Self { 818 module: self.module.clone(), 819 items: self.items.clone(), 820 host_funcs: self.host_funcs, 821 func_refs: self.func_refs.clone(), 822 _marker: self._marker, 823 } 824 } 825 } 826 827 impl<T> InstancePre<T> { 828 /// Creates a new `InstancePre` which type-checks the `items` provided and 829 /// on success is ready to instantiate a new instance. 830 /// 831 /// # Unsafety 832 /// 833 /// This method is unsafe as the `T` of the `InstancePre<T>` is not 834 /// guaranteed to be the same as the `T` within the `Store`, the caller must 835 /// verify that. 836 pub(crate) unsafe fn new(module: &Module, items: Vec<Definition>) -> Result<InstancePre<T>> { 837 typecheck(module, &items, |cx, ty, item| cx.definition(ty, &item.ty()))?; 838 839 let mut func_refs = vec![]; 840 let mut host_funcs = 0; 841 for item in &items { 842 match item { 843 Definition::Extern(_, _) => {} 844 Definition::HostFunc(f) => { 845 host_funcs += 1; 846 if f.func_ref().wasm_call.is_none() { 847 // `f` needs its `VMFuncRef::wasm_call` patched with a 848 // Wasm-to-native trampoline. 849 debug_assert!(matches!(f.host_ctx(), crate::HostContext::Array(_))); 850 func_refs.push(VMFuncRef { 851 wasm_call: module 852 .wasm_to_array_trampoline(f.sig_index()) 853 .map(|f| f.into()), 854 ..*f.func_ref() 855 }); 856 } 857 } 858 } 859 } 860 861 Ok(InstancePre { 862 module: module.clone(), 863 items: items.into(), 864 host_funcs, 865 func_refs: func_refs.into(), 866 _marker: core::marker::PhantomData, 867 }) 868 } 869 870 /// Returns a reference to the module that this [`InstancePre`] will be 871 /// instantiating. 872 pub fn module(&self) -> &Module { 873 &self.module 874 } 875 876 /// Instantiates this instance, creating a new instance within the provided 877 /// `store`. 878 /// 879 /// This function will run the actual process of instantiation to 880 /// completion. This will use all of the previously-closed-over items as 881 /// imports to instantiate the module that this was originally created with. 882 /// 883 /// For more information about instantiation see [`Instance::new`]. 884 /// 885 /// # Panics 886 /// 887 /// Panics if any import closed over by this [`InstancePre`] isn't owned by 888 /// `store`, or if `store` has async support enabled. Additionally this 889 /// function will panic if the `store` provided comes from a different 890 /// [`Engine`] than the [`InstancePre`] originally came from. 891 pub fn instantiate(&self, mut store: impl AsContextMut<Data = T>) -> Result<Instance> { 892 let mut store = store.as_context_mut(); 893 let imports = pre_instantiate_raw( 894 &mut store.0, 895 &self.module, 896 &self.items, 897 self.host_funcs, 898 &self.func_refs, 899 )?; 900 901 // This unsafety should be handled by the type-checking performed by the 902 // constructor of `InstancePre` to assert that all the imports we're passing 903 // in match the module we're instantiating. 904 unsafe { Instance::new_started(&mut store, &self.module, imports.as_ref()) } 905 } 906 907 /// Creates a new instance, running the start function asynchronously 908 /// instead of inline. 909 /// 910 /// For more information about asynchronous instantiation see the 911 /// documentation on [`Instance::new_async`]. 912 /// 913 /// # Panics 914 /// 915 /// Panics if any import closed over by this [`InstancePre`] isn't owned by 916 /// `store`, or if `store` does not have async support enabled. 917 #[cfg(feature = "async")] 918 pub async fn instantiate_async( 919 &self, 920 mut store: impl AsContextMut<Data = T>, 921 ) -> Result<Instance> 922 where 923 T: Send, 924 { 925 let mut store = store.as_context_mut(); 926 let imports = pre_instantiate_raw( 927 &mut store.0, 928 &self.module, 929 &self.items, 930 self.host_funcs, 931 &self.func_refs, 932 )?; 933 934 // This unsafety should be handled by the type-checking performed by the 935 // constructor of `InstancePre` to assert that all the imports we're passing 936 // in match the module we're instantiating. 937 unsafe { Instance::new_started_async(&mut store, &self.module, imports.as_ref()).await } 938 } 939 } 940 941 /// Helper function shared between 942 /// `InstancePre::{instantiate,instantiate_async}` 943 /// 944 /// This is an out-of-line function to avoid the generic on `InstancePre` and 945 /// get this compiled into the `wasmtime` crate to avoid having it monomorphized 946 /// elsewhere. 947 fn pre_instantiate_raw( 948 store: &mut StoreOpaque, 949 module: &Module, 950 items: &Arc<[Definition]>, 951 host_funcs: usize, 952 func_refs: &Arc<[VMFuncRef]>, 953 ) -> Result<OwnedImports> { 954 if host_funcs > 0 { 955 // Any linker-defined function of the `Definition::HostFunc` variant 956 // will insert a function into the store automatically as part of 957 // instantiation, so reserve space here to make insertion more efficient 958 // as it won't have to realloc during the instantiation. 959 store.store_data_mut().reserve_funcs(host_funcs); 960 961 // The usage of `to_extern_store_rooted` requires that the items are 962 // rooted via another means, which happens here by cloning the list of 963 // items into the store once. This avoids cloning each individual item 964 // below. 965 store.push_rooted_funcs(items.clone()); 966 store.push_instance_pre_func_refs(func_refs.clone()); 967 } 968 969 let mut func_refs = func_refs.iter().map(|f| NonNull::from(f)); 970 let mut imports = OwnedImports::new(module); 971 for import in items.iter() { 972 if !import.comes_from_same_store(store) { 973 bail!("cross-`Store` instantiation is not currently supported"); 974 } 975 // This unsafety should be encapsulated in the constructor of 976 // `InstancePre` where the `T` of the original item should match the 977 // `T` of the store. Additionally the rooting necessary has happened 978 // above. 979 let item = match import { 980 Definition::Extern(e, _) => e.clone(), 981 Definition::HostFunc(func) => unsafe { 982 func.to_func_store_rooted( 983 store, 984 if func.func_ref().wasm_call.is_none() { 985 Some(func_refs.next().unwrap()) 986 } else { 987 None 988 }, 989 ) 990 .into() 991 }, 992 }; 993 imports.push(&item, store, module); 994 } 995 996 Ok(imports) 997 } 998 999 fn typecheck<I>( 1000 module: &Module, 1001 import_args: &[I], 1002 check: impl Fn(&matching::MatchCx<'_>, &EntityType, &I) -> Result<()>, 1003 ) -> Result<()> { 1004 let env_module = module.compiled_module().module(); 1005 let expected_len = env_module.imports().count(); 1006 let actual_len = import_args.len(); 1007 if expected_len != actual_len { 1008 bail!("expected {expected_len} imports, found {actual_len}"); 1009 } 1010 let cx = matching::MatchCx::new(module.engine()); 1011 for ((name, field, expected_ty), actual) in env_module.imports().zip(import_args) { 1012 debug_assert!(expected_ty.is_canonicalized_for_runtime_usage()); 1013 check(&cx, &expected_ty, actual) 1014 .with_context(|| format!("incompatible import type for `{name}::{field}`"))?; 1015 } 1016 Ok(()) 1017 } 1018