From 76b82910c99fba36fa75efb0a90b92379853f329 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 23 Mar 2022 14:57:34 -0500 Subject: [PATCH] Remove the module linking implementation in Wasmtime (#3958) * Remove the module linking implementation in Wasmtime This commit removes the experimental implementation of the module linking WebAssembly proposal from Wasmtime. The module linking is no longer intended for core WebAssembly but is instead incorporated into the component model now at this point. This means that very large parts of Wasmtime's implementation of module linking are no longer applicable and would change greatly with an implementation of the component model. The main purpose of this is to remove Wasmtime's reliance on the support for module-linking in `wasmparser` and tooling crates. With this reliance removed we can move over to the `component-model` branch of `wasmparser` and use the updated support for the component model. Additionally given the trajectory of the component model proposal the embedding API of Wasmtime will not look like what it looks like today for WebAssembly. For example the core wasm `Instance` will not change and instead a `Component` is likely to be added instead. Some more rationale for this is in #3941, but the basic idea is that I feel that it's not going to be viable to develop support for the component model on a non-`main` branch of Wasmtime. Additionaly I don't think it's viable, for the same reasons as `wasm-tools`, to support the old module linking proposal and the new component model at the same time. This commit takes a moment to not only delete the existing module linking implementation but some abstractions are also simplified. For example module serialization is a bit simpler that there's only one module. Additionally instantiation is much simpler since the only initializer we have to deal with are imports and nothing else. Closes #3941 * Fix doc link * Update comments --- build.rs | 1 - cranelift/wasm/src/environ/mod.rs | 2 +- cranelift/wasm/src/environ/spec.rs | 125 +--- cranelift/wasm/src/lib.rs | 2 +- cranelift/wasm/src/module_translator.rs | 16 +- cranelift/wasm/src/sections_translator.rs | 116 +--- crates/c-api/include/wasmtime/config.h | 8 - crates/c-api/include/wasmtime/extern.h | 27 - crates/c-api/include/wasmtime/instance.h | 56 +- crates/c-api/include/wasmtime/module.h | 53 -- crates/c-api/src/config.rs | 5 - crates/c-api/src/extern.rs | 54 +- crates/c-api/src/instance.rs | 51 +- crates/c-api/src/linker.rs | 10 +- crates/c-api/src/module.rs | 57 +- crates/c-api/src/types.rs | 4 - crates/c-api/src/types/extern.rs | 27 +- crates/c-api/src/types/import.rs | 22 +- crates/c-api/src/types/instance.rs | 68 --- crates/c-api/src/types/module.rs | 92 --- crates/environ/src/module.rs | 89 +-- crates/environ/src/module_environ.rs | 544 ++---------------- crates/fuzzing/src/generators.rs | 1 - crates/fuzzing/src/oracles/dummy.rs | 483 +--------------- crates/jit/src/instantiate.rs | 7 +- crates/runtime/src/instance.rs | 4 - crates/types/src/lib.rs | 30 - crates/wasmtime/src/config.rs | 15 - crates/wasmtime/src/engine.rs | 5 +- crates/wasmtime/src/externals.rs | 74 +-- crates/wasmtime/src/instance.rs | 487 +++------------- crates/wasmtime/src/linker.rs | 67 +-- crates/wasmtime/src/module.rs | 302 +++------- crates/wasmtime/src/module/serialization.rs | 255 ++------ crates/wasmtime/src/trampoline/global.rs | 2 +- crates/wasmtime/src/types.rs | 182 +----- crates/wasmtime/src/types/matching.rs | 235 +------- crates/wast/src/wast.rs | 2 +- src/commands/run.rs | 2 +- src/lib.rs | 21 - tests/all/async_functions.rs | 14 +- tests/all/custom_signal_handler.rs | 2 +- tests/all/host_funcs.rs | 54 +- tests/all/linker.rs | 34 +- tests/all/main.rs | 1 - tests/all/module_linking.rs | 300 ---------- tests/all/wast.rs | 4 +- .../module-linking/alias-outer.wast | 67 --- .../misc_testsuite/module-linking/alias.wast | 143 ----- .../module-linking/import-subtyping.wast | 431 -------------- .../module-linking/instantiate.wast | 308 ---------- 51 files changed, 403 insertions(+), 4558 deletions(-) delete mode 100644 crates/c-api/src/types/instance.rs delete mode 100644 crates/c-api/src/types/module.rs delete mode 100644 tests/all/module_linking.rs delete mode 100644 tests/misc_testsuite/module-linking/alias-outer.wast delete mode 100644 tests/misc_testsuite/module-linking/alias.wast delete mode 100644 tests/misc_testsuite/module-linking/import-subtyping.wast delete mode 100644 tests/misc_testsuite/module-linking/instantiate.wast diff --git a/build.rs b/build.rs index ddf4fbfe4a8e..9e1017ee1f6d 100644 --- a/build.rs +++ b/build.rs @@ -25,7 +25,6 @@ fn main() -> anyhow::Result<()> { with_test_module(&mut out, "misc", |out| { test_directory(out, "tests/misc_testsuite", strategy)?; test_directory_module(out, "tests/misc_testsuite/multi-memory", strategy)?; - test_directory_module(out, "tests/misc_testsuite/module-linking", strategy)?; test_directory_module(out, "tests/misc_testsuite/simd", strategy)?; test_directory_module(out, "tests/misc_testsuite/threads", strategy)?; test_directory_module(out, "tests/misc_testsuite/memory64", strategy)?; diff --git a/cranelift/wasm/src/environ/mod.rs b/cranelift/wasm/src/environ/mod.rs index 21889abf6da6..16a89a1d7a32 100644 --- a/cranelift/wasm/src/environ/mod.rs +++ b/cranelift/wasm/src/environ/mod.rs @@ -6,5 +6,5 @@ mod spec; pub use crate::environ::dummy::DummyEnvironment; pub use crate::environ::spec::{ - Alias, FuncEnvironment, GlobalVariable, ModuleEnvironment, ReturnMode, TargetEnvironment, + FuncEnvironment, GlobalVariable, ModuleEnvironment, ReturnMode, TargetEnvironment, }; diff --git a/cranelift/wasm/src/environ/spec.rs b/cranelift/wasm/src/environ/spec.rs index 2500b5b5b4ee..9822c9f5a4d4 100644 --- a/cranelift/wasm/src/environ/spec.rs +++ b/cranelift/wasm/src/environ/spec.rs @@ -8,9 +8,9 @@ use crate::state::FuncTranslationState; use crate::{ - DataIndex, ElemIndex, EntityIndex, EntityType, FuncIndex, Global, GlobalIndex, InstanceIndex, - InstanceTypeIndex, Memory, MemoryIndex, ModuleIndex, ModuleTypeIndex, SignatureIndex, Table, - TableIndex, Tag, TagIndex, TypeIndex, WasmError, WasmFuncType, WasmResult, WasmType, + DataIndex, ElemIndex, EntityType, FuncIndex, Global, GlobalIndex, Memory, MemoryIndex, + SignatureIndex, Table, TableIndex, Tag, TagIndex, TypeIndex, WasmError, WasmFuncType, + WasmResult, WasmType, }; use core::convert::From; use cranelift_codegen::cursor::FuncCursor; @@ -20,7 +20,6 @@ use cranelift_codegen::isa::TargetFrontendConfig; use cranelift_frontend::FunctionBuilder; use std::boxed::Box; use std::string::ToString; -use std::vec::Vec; use wasmparser::{FuncValidator, FunctionBody, Operator, ValidatorResources, WasmFeatures}; /// The value of a WebAssembly global variable. @@ -52,39 +51,6 @@ pub enum ReturnMode { FallthroughReturn, } -/// An entry in the alias section of a wasm module (from the module linking -/// proposal) -pub enum Alias<'a> { - /// An outer module's module is being aliased into our own index space. - OuterModule { - /// The number of modules above us that we're referencing. - relative_depth: u32, - /// The module index in the outer module's index space we're referencing. - index: ModuleIndex, - }, - - /// An outer module's type is being aliased into our own index space - /// - /// Note that the index here is in the outer module's index space, not our - /// own. - OuterType { - /// The number of modules above us that we're referencing. - relative_depth: u32, - /// The type index in the outer module's index space we're referencing. - index: TypeIndex, - }, - - /// A previously created instance is having one of its exports aliased into - /// our index space. - InstanceExport { - /// The index we're aliasing. - instance: InstanceIndex, - /// The nth export that we're inserting into our own index space - /// locally. - export: &'a str, - }, -} - /// Environment affecting the translation of a WebAssembly. pub trait TargetEnvironment { /// Get the information needed to produce Cranelift IR for the given target. @@ -588,20 +554,6 @@ pub trait ModuleEnvironment<'data> { Err(WasmError::Unsupported("module linking".to_string())) } - /// Translates a type index to its module type index, only called for type - /// indices which point to modules. - fn type_to_module_type(&self, index: TypeIndex) -> WasmResult { - drop(index); - Err(WasmError::Unsupported("module linking".to_string())) - } - - /// Translates a type index to its instance type index, only called for type - /// indices which point to instances. - fn type_to_instance_type(&self, index: TypeIndex) -> WasmResult { - drop(index); - Err(WasmError::Unsupported("module linking".to_string())) - } - /// Provides the number of imports up front. By default this does nothing, but /// implementations can use this to preallocate memory if desired. fn reserve_imports(&mut self, _num: u32) -> WasmResult<()> { @@ -662,17 +614,6 @@ pub trait ModuleEnvironment<'data> { Err(WasmError::Unsupported("module linking".to_string())) } - /// Declares an instance import to the environment. - fn declare_instance_import( - &mut self, - ty_index: TypeIndex, - module: &'data str, - field: Option<&'data str>, - ) -> WasmResult<()> { - drop((ty_index, module, field)); - Err(WasmError::Unsupported("module linking".to_string())) - } - /// Notifies the implementation that all imports have been declared. fn finish_imports(&mut self) -> WasmResult<()> { Ok(()) @@ -759,22 +700,6 @@ pub trait ModuleEnvironment<'data> { name: &'data str, ) -> WasmResult<()>; - /// Declares an instance export to the environment. - fn declare_instance_export( - &mut self, - index: InstanceIndex, - name: &'data str, - ) -> WasmResult<()> { - drop((index, name)); - Err(WasmError::Unsupported("module linking".to_string())) - } - - /// Declares an instance export to the environment. - fn declare_module_export(&mut self, index: ModuleIndex, name: &'data str) -> WasmResult<()> { - drop((index, name)); - Err(WasmError::Unsupported("module linking".to_string())) - } - /// Notifies the implementation that all exports have been declared. fn finish_exports(&mut self) -> WasmResult<()> { Ok(()) @@ -880,48 +805,4 @@ pub trait ModuleEnvironment<'data> { fn wasm_features(&self) -> WasmFeatures { WasmFeatures::default() } - - /// Indicates that this module will have `amount` submodules. - /// - /// Note that this is just child modules of this module, and each child - /// module may have yet more submodules. - fn reserve_modules(&mut self, amount: u32) { - drop(amount); - } - - /// Called at the beginning of translating a module. - /// - /// Note that for nested modules this may be called multiple times. - fn module_start(&mut self) {} - - /// Called at the end of translating a module. - /// - /// Note that for nested modules this may be called multiple times. - fn module_end(&mut self) {} - - /// Indicates that this module will have `amount` instances. - fn reserve_instances(&mut self, amount: u32) { - drop(amount); - } - - /// Declares a new instance which this module will instantiate before it's - /// instantiated. - fn declare_instance( - &mut self, - module: ModuleIndex, - args: Vec<(&'data str, EntityIndex)>, - ) -> WasmResult<()> { - drop((module, args)); - Err(WasmError::Unsupported("wasm instance".to_string())) - } - - /// Declares a new alias being added to this module. - /// - /// The alias comes from the `instance` specified (or the parent if `None` - /// is supplied) and the index is either in the module's own index spaces - /// for the parent or an index into the exports for nested instances. - fn declare_alias(&mut self, alias: Alias<'data>) -> WasmResult<()> { - drop(alias); - Err(WasmError::Unsupported("wasm alias".to_string())) - } } diff --git a/cranelift/wasm/src/lib.rs b/cranelift/wasm/src/lib.rs index a9823681b957..5ae222415885 100644 --- a/cranelift/wasm/src/lib.rs +++ b/cranelift/wasm/src/lib.rs @@ -57,7 +57,7 @@ mod state; mod translation_utils; pub use crate::environ::{ - Alias, DummyEnvironment, FuncEnvironment, GlobalVariable, ModuleEnvironment, ReturnMode, + DummyEnvironment, FuncEnvironment, GlobalVariable, ModuleEnvironment, ReturnMode, TargetEnvironment, }; pub use crate::func_translator::FuncTranslator; diff --git a/cranelift/wasm/src/module_translator.rs b/cranelift/wasm/src/module_translator.rs index b78397c70754..38601b1880d6 100644 --- a/cranelift/wasm/src/module_translator.rs +++ b/cranelift/wasm/src/module_translator.rs @@ -2,10 +2,9 @@ //! to deal with each part of it. use crate::environ::ModuleEnvironment; use crate::sections_translator::{ - parse_alias_section, parse_data_section, parse_element_section, parse_export_section, - parse_function_section, parse_global_section, parse_import_section, parse_instance_section, - parse_memory_section, parse_name_section, parse_start_section, parse_table_section, - parse_tag_section, parse_type_section, + parse_data_section, parse_element_section, parse_export_section, parse_function_section, + parse_global_section, parse_import_section, parse_memory_section, parse_name_section, + parse_start_section, parse_table_section, parse_tag_section, parse_type_section, }; use crate::state::ModuleTranslationState; use crate::WasmResult; @@ -28,11 +27,9 @@ pub fn translate_module<'data>( match payload? { Payload::Version { num, range } => { validator.version(num, &range)?; - environ.module_start(); } Payload::End => { validator.end()?; - environ.module_end(); } Payload::TypeSection(types) => { @@ -109,11 +106,11 @@ pub fn translate_module<'data>( Payload::InstanceSection(s) => { validator.instance_section(&s)?; - parse_instance_section(s, environ)?; + unimplemented!(); } Payload::AliasSection(s) => { validator.alias_section(&s)?; - parse_alias_section(s, environ)?; + unimplemented!(); } Payload::ModuleSectionStart { count, @@ -121,11 +118,12 @@ pub fn translate_module<'data>( size: _, } => { validator.module_section_start(count, &range)?; - environ.reserve_modules(count); + unimplemented!(); } Payload::ModuleSectionEntry { .. } => { validator.module_section_entry(); + unimplemented!(); } Payload::CustomSection { diff --git a/cranelift/wasm/src/sections_translator.rs b/cranelift/wasm/src/sections_translator.rs index a052328bd346..8449f2d6eac6 100644 --- a/cranelift/wasm/src/sections_translator.rs +++ b/cranelift/wasm/src/sections_translator.rs @@ -7,13 +7,12 @@ //! The special case of the initialize expressions for table elements offsets or global variables //! is handled, according to the semantics of WebAssembly, to only specific expressions that are //! interpreted on the fly. -use crate::environ::{Alias, ModuleEnvironment}; +use crate::environ::ModuleEnvironment; use crate::state::ModuleTranslationState; use crate::wasm_unsupported; use crate::{ - DataIndex, ElemIndex, EntityIndex, EntityType, FuncIndex, Global, GlobalIndex, GlobalInit, - InstanceIndex, Memory, MemoryIndex, ModuleIndex, Table, TableIndex, Tag, TagIndex, TypeIndex, - WasmError, WasmResult, + DataIndex, ElemIndex, EntityType, FuncIndex, Global, GlobalIndex, GlobalInit, Memory, + MemoryIndex, Table, TableIndex, Tag, TagIndex, TypeIndex, WasmError, WasmResult, }; use core::convert::TryFrom; use core::convert::TryInto; @@ -37,16 +36,15 @@ fn entity_type( ImportSectionEntryType::Function(sig) => { EntityType::Function(environ.type_to_signature(TypeIndex::from_u32(sig))?) } - ImportSectionEntryType::Module(sig) => { - EntityType::Module(environ.type_to_module_type(TypeIndex::from_u32(sig))?) - } - ImportSectionEntryType::Instance(sig) => { - EntityType::Instance(environ.type_to_instance_type(TypeIndex::from_u32(sig))?) - } ImportSectionEntryType::Memory(ty) => EntityType::Memory(memory(ty)), ImportSectionEntryType::Tag(t) => EntityType::Tag(tag(t)), ImportSectionEntryType::Global(ty) => EntityType::Global(global(ty, GlobalInit::Import)?), ImportSectionEntryType::Table(ty) => EntityType::Table(table(ty)?), + + // doesn't get past validation + ImportSectionEntryType::Module(_) | ImportSectionEntryType::Instance(_) => { + unreachable!() + } }) } @@ -142,20 +140,6 @@ pub fn parse_import_section<'data>( import.field, )?; } - ImportSectionEntryType::Module(sig) => { - environ.declare_module_import( - TypeIndex::from_u32(sig), - import.module, - import.field, - )?; - } - ImportSectionEntryType::Instance(sig) => { - environ.declare_instance_import( - TypeIndex::from_u32(sig), - import.module, - import.field, - )?; - } ImportSectionEntryType::Memory(ty) => { environ.declare_memory_import(memory(ty), import.module, import.field)?; } @@ -170,6 +154,10 @@ pub fn parse_import_section<'data>( let ty = table(ty)?; environ.declare_table_import(ty, import.module, import.field)?; } + + ImportSectionEntryType::Module(_) | ImportSectionEntryType::Instance(_) => { + unimplemented!() + } } } @@ -310,15 +298,9 @@ pub fn parse_export_section<'data>( ExternalKind::Global => { environ.declare_global_export(GlobalIndex::new(index), field)? } - ExternalKind::Module => { - environ.declare_module_export(ModuleIndex::new(index), field)? - } - ExternalKind::Instance => { - environ.declare_instance_export(InstanceIndex::new(index), field)? - } // this never gets past validation - ExternalKind::Type => unreachable!(), + ExternalKind::Module | ExternalKind::Instance | ExternalKind::Type => unreachable!(), } } @@ -506,75 +488,3 @@ pub fn parse_name_section<'data>( } Ok(()) } - -/// Parses the Instance section of the wasm module. -pub fn parse_instance_section<'data>( - section: wasmparser::InstanceSectionReader<'data>, - environ: &mut dyn ModuleEnvironment<'data>, -) -> WasmResult<()> { - environ.reserve_instances(section.get_count()); - - for instance in section { - let instance = instance?; - let module = ModuleIndex::from_u32(instance.module()); - let args = instance - .args()? - .into_iter() - .map(|arg| { - let arg = arg?; - let index = match arg.kind { - ExternalKind::Function => EntityIndex::Function(FuncIndex::from_u32(arg.index)), - ExternalKind::Table => EntityIndex::Table(TableIndex::from_u32(arg.index)), - ExternalKind::Memory => EntityIndex::Memory(MemoryIndex::from_u32(arg.index)), - ExternalKind::Global => EntityIndex::Global(GlobalIndex::from_u32(arg.index)), - ExternalKind::Module => EntityIndex::Module(ModuleIndex::from_u32(arg.index)), - ExternalKind::Instance => { - EntityIndex::Instance(InstanceIndex::from_u32(arg.index)) - } - ExternalKind::Tag => unimplemented!(), - - // this won't pass validation - ExternalKind::Type => unreachable!(), - }; - Ok((arg.name, index)) - }) - .collect::>>()?; - environ.declare_instance(module, args)?; - } - Ok(()) -} - -/// Parses the Alias section of the wasm module. -pub fn parse_alias_section<'data>( - section: wasmparser::AliasSectionReader<'data>, - environ: &mut dyn ModuleEnvironment<'data>, -) -> WasmResult<()> { - for alias in section { - let alias = match alias? { - wasmparser::Alias::OuterType { - relative_depth, - index, - } => Alias::OuterType { - relative_depth, - index: TypeIndex::from_u32(index), - }, - wasmparser::Alias::OuterModule { - relative_depth, - index, - } => Alias::OuterModule { - relative_depth, - index: ModuleIndex::from_u32(index), - }, - wasmparser::Alias::InstanceExport { - instance, - export, - kind: _, - } => Alias::InstanceExport { - instance: InstanceIndex::from_u32(instance), - export, - }, - }; - environ.declare_alias(alias)?; - } - Ok(()) -} diff --git a/crates/c-api/include/wasmtime/config.h b/crates/c-api/include/wasmtime/config.h index ae40d8394f92..92d7c2ea1e65 100644 --- a/crates/c-api/include/wasmtime/config.h +++ b/crates/c-api/include/wasmtime/config.h @@ -185,14 +185,6 @@ WASMTIME_CONFIG_PROP(void, wasm_multi_value, bool) */ WASMTIME_CONFIG_PROP(void, wasm_multi_memory, bool) -/** - * \brief Configures whether the WebAssembly module linking proposal is - * enabled. - * - * This setting is `false` by default. - */ -WASMTIME_CONFIG_PROP(void, wasm_module_linking, bool) - /** * \brief Configures whether the WebAssembly memory64 proposal is * enabled. diff --git a/crates/c-api/include/wasmtime/extern.h b/crates/c-api/include/wasmtime/extern.h index 77d66c8656ae..29dcb217feb6 100644 --- a/crates/c-api/include/wasmtime/extern.h +++ b/crates/c-api/include/wasmtime/extern.h @@ -56,20 +56,6 @@ typedef struct wasmtime_memory { size_t index; } wasmtime_memory_t; -/// \brief Representation of a instance in Wasmtime. -/// -/// Instances are represented with a 64-bit identifying integer in Wasmtime. -/// They do not have any destructor associated with them. Instances cannot -/// interoperate between #wasmtime_store_t instances and if the wrong instance -/// is passed to the wrong store then it may trigger an assertion to abort the -/// process. -typedef struct wasmtime_instance { - /// Internal identifier of what store this belongs to, never zero. - uint64_t store_id; - /// Internal index within the store. - size_t index; -} wasmtime_instance_t; - /// \brief Representation of a global in Wasmtime. /// /// Globals are represented with a 64-bit identifying integer in Wasmtime. @@ -99,12 +85,6 @@ typedef uint8_t wasmtime_extern_kind_t; /// \brief Value of #wasmtime_extern_kind_t meaning that #wasmtime_extern_t is a /// memory #define WASMTIME_EXTERN_MEMORY 3 -/// \brief Value of #wasmtime_extern_kind_t meaning that #wasmtime_extern_t is -/// an instance -#define WASMTIME_EXTERN_INSTANCE 4 -/// \brief Value of #wasmtime_extern_kind_t meaning that #wasmtime_extern_t is -/// a module -#define WASMTIME_EXTERN_MODULE 5 /** * \typedef wasmtime_extern_union_t @@ -125,13 +105,6 @@ typedef union wasmtime_extern_union { wasmtime_table_t table; /// Field used if #wasmtime_extern_t::kind is #WASMTIME_EXTERN_MEMORY wasmtime_memory_t memory; - /// Field used if #wasmtime_extern_t::kind is #WASMTIME_EXTERN_INSTANCE - wasmtime_instance_t instance; - /// Field used if #wasmtime_extern_t::kind is #WASMTIME_EXTERN_MODULE - /// - /// Note that this may be an owned pointer depending on the ownership of the - /// #wasmtime_extern_t container value. - wasmtime_module_t *module; } wasmtime_extern_union_t; /** diff --git a/crates/c-api/include/wasmtime/instance.h b/crates/c-api/include/wasmtime/instance.h index 6058d2170144..544661f9d8fe 100644 --- a/crates/c-api/include/wasmtime/instance.h +++ b/crates/c-api/include/wasmtime/instance.h @@ -16,39 +16,19 @@ extern "C" { #endif -/** - * \brief An opaque object representing the type of an instance. - */ -typedef struct wasmtime_instancetype wasmtime_instancetype_t; - -/// \brief Deletes an instance type -WASM_API_EXTERN void wasmtime_instancetype_delete(wasmtime_instancetype_t *ty); - -/** - * \brief Returns the list of exports that this instance type provides. - * - * This function does not take ownership of the provided instance type but - * ownership of `out` is passed to the caller. Note that `out` is treated as - * uninitialized when passed to this function. - */ -WASM_API_EXTERN void wasmtime_instancetype_exports(const wasmtime_instancetype_t*, wasm_exporttype_vec_t* out); - -/** - * \brief Converts a #wasmtime_instancetype_t to a #wasm_externtype_t - * - * The returned value is owned by the #wasmtime_instancetype_t argument and should not - * be deleted. - */ -WASM_API_EXTERN wasm_externtype_t* wasmtime_instancetype_as_externtype(wasmtime_instancetype_t*); - -/** - * \brief Attempts to convert a #wasm_externtype_t to a #wasmtime_instancetype_t - * - * The returned value is owned by the #wasmtime_instancetype_t argument and should not - * be deleted. Returns `NULL` if the provided argument is not a - * #wasmtime_instancetype_t. - */ -WASM_API_EXTERN wasmtime_instancetype_t* wasmtime_externtype_as_instancetype(wasm_externtype_t*); +/// \brief Representation of a instance in Wasmtime. +/// +/// Instances are represented with a 64-bit identifying integer in Wasmtime. +/// They do not have any destructor associated with them. Instances cannot +/// interoperate between #wasmtime_store_t instances and if the wrong instance +/// is passed to the wrong store then it may trigger an assertion to abort the +/// process. +typedef struct wasmtime_instance { + /// Internal identifier of what store this belongs to, never zero. + uint64_t store_id; + /// Internal index within the store. + size_t index; +} wasmtime_instance_t; /** * \brief Instantiate a wasm module. @@ -91,16 +71,6 @@ WASM_API_EXTERN wasmtime_error_t *wasmtime_instance_new( wasm_trap_t **trap ); -/** - * \brief Returns the type of the specified instance. - * - * The returned type is owned by the caller. - */ -WASM_API_EXTERN wasmtime_instancetype_t *wasmtime_instance_type( - const wasmtime_context_t *store, - const wasmtime_instance_t *instance -); - /** * \brief Get an export by name from an instance. * diff --git a/crates/c-api/include/wasmtime/module.h b/crates/c-api/include/wasmtime/module.h index 326463b87ccc..39b89fa77970 100644 --- a/crates/c-api/include/wasmtime/module.h +++ b/crates/c-api/include/wasmtime/module.h @@ -14,51 +14,6 @@ extern "C" { #endif -/** - * \brief An opaque object representing the type of a module. - */ -typedef struct wasmtime_moduletype wasmtime_moduletype_t; - -/** - * \brief Deletes a module type. - */ -WASM_API_EXTERN void wasmtime_moduletype_delete(wasmtime_moduletype_t *ty); - -/** - * \brief Returns the list of imports that this module type requires. - * - * This function does not take ownership of the provided module type but - * ownership of `out` is passed to the caller. Note that `out` is treated as - * uninitialized when passed to this function. - */ -WASM_API_EXTERN void wasmtime_moduletype_imports(const wasmtime_moduletype_t*, wasm_importtype_vec_t* out); - -/** - * \brief Returns the list of exports that this module type provides. - * - * This function does not take ownership of the provided module type but - * ownership of `out` is passed to the caller. Note that `out` is treated as - * uninitialized when passed to this function. - */ -WASM_API_EXTERN void wasmtime_moduletype_exports(const wasmtime_moduletype_t*, wasm_exporttype_vec_t* out); - -/** - * \brief Converts a #wasmtime_moduletype_t to a #wasm_externtype_t - * - * The returned value is owned by the #wasmtime_moduletype_t argument and should not - * be deleted. - */ -WASM_API_EXTERN wasm_externtype_t* wasmtime_moduletype_as_externtype(wasmtime_moduletype_t*); - -/** - * \brief Attempts to convert a #wasm_externtype_t to a #wasmtime_moduletype_t - * - * The returned value is owned by the #wasmtime_moduletype_t argument and - * should not be deleted. Returns `NULL` if the provided argument is not a - * #wasmtime_moduletype_t. - */ -WASM_API_EXTERN wasmtime_moduletype_t* wasmtime_externtype_as_moduletype(wasm_externtype_t*); - /** * \typedef wasmtime_module_t * \brief Convenience alias for #wasmtime_module @@ -122,14 +77,6 @@ WASM_API_EXTERN wasmtime_error_t *wasmtime_module_validate( size_t wasm_len ); -/** - * \brief Returns the type of this module. - * - * The returned #wasmtime_moduletype_t is expected to be deallocated by the - * caller. - */ -WASM_API_EXTERN wasmtime_moduletype_t* wasmtime_module_type(const wasmtime_module_t*); - /** * \brief This function serializes compiled module artifacts as blob data. * diff --git a/crates/c-api/src/config.rs b/crates/c-api/src/config.rs index 1326f87bc110..c62f3f477947 100644 --- a/crates/c-api/src/config.rs +++ b/crates/c-api/src/config.rs @@ -94,11 +94,6 @@ pub extern "C" fn wasmtime_config_wasm_multi_memory_set(c: &mut wasm_config_t, e c.config.wasm_multi_memory(enable); } -#[no_mangle] -pub extern "C" fn wasmtime_config_wasm_module_linking_set(c: &mut wasm_config_t, enable: bool) { - c.config.wasm_module_linking(enable); -} - #[no_mangle] pub extern "C" fn wasmtime_config_wasm_memory64_set(c: &mut wasm_config_t, enable: bool) { c.config.wasm_memory64(enable); diff --git a/crates/c-api/src/extern.rs b/crates/c-api/src/extern.rs index a8ec69f49af8..106d9ad306af 100644 --- a/crates/c-api/src/extern.rs +++ b/crates/c-api/src/extern.rs @@ -1,9 +1,9 @@ use crate::{ - wasm_externkind_t, wasm_externtype_t, wasm_func_t, wasm_global_t, wasm_instance_t, - wasm_memory_t, wasm_module_t, wasm_table_t, wasmtime_module_t, CStoreContext, StoreRef, + wasm_externkind_t, wasm_externtype_t, wasm_func_t, wasm_global_t, wasm_memory_t, wasm_table_t, + CStoreContext, StoreRef, }; use std::mem::ManuallyDrop; -use wasmtime::{Extern, Func, Global, Instance, Memory, Table}; +use wasmtime::{Extern, Func, Global, Memory, Table}; #[derive(Clone)] pub struct wasm_extern_t { @@ -20,8 +20,6 @@ pub extern "C" fn wasm_extern_kind(e: &wasm_extern_t) -> wasm_externkind_t { Extern::Global(_) => crate::WASM_EXTERN_GLOBAL, Extern::Table(_) => crate::WASM_EXTERN_TABLE, Extern::Memory(_) => crate::WASM_EXTERN_MEMORY, - Extern::Instance(_) => crate::WASM_EXTERN_INSTANCE, - Extern::Module(_) => crate::WASM_EXTERN_MODULE, } } @@ -70,26 +68,6 @@ pub extern "C" fn wasm_extern_as_memory_const(e: &wasm_extern_t) -> Option<&wasm wasm_extern_as_memory(e) } -#[no_mangle] -pub extern "C" fn wasm_extern_as_module(e: &wasm_extern_t) -> Option<&wasm_module_t> { - wasm_module_t::try_from(e) -} - -#[no_mangle] -pub extern "C" fn wasm_extern_as_module_const(e: &wasm_extern_t) -> Option<&wasm_module_t> { - wasm_extern_as_module(e) -} - -#[no_mangle] -pub extern "C" fn wasm_extern_as_instance(e: &wasm_extern_t) -> Option<&wasm_instance_t> { - wasm_instance_t::try_from(e) -} - -#[no_mangle] -pub extern "C" fn wasm_extern_as_instance_const(e: &wasm_extern_t) -> Option<&wasm_instance_t> { - wasm_extern_as_instance(e) -} - #[repr(C)] pub struct wasmtime_extern_t { pub kind: wasmtime_extern_kind_t, @@ -101,17 +79,13 @@ pub const WASMTIME_EXTERN_FUNC: wasmtime_extern_kind_t = 0; pub const WASMTIME_EXTERN_GLOBAL: wasmtime_extern_kind_t = 1; pub const WASMTIME_EXTERN_TABLE: wasmtime_extern_kind_t = 2; pub const WASMTIME_EXTERN_MEMORY: wasmtime_extern_kind_t = 3; -pub const WASMTIME_EXTERN_INSTANCE: wasmtime_extern_kind_t = 4; -pub const WASMTIME_EXTERN_MODULE: wasmtime_extern_kind_t = 5; #[repr(C)] pub union wasmtime_extern_union { pub func: Func, pub table: Table, pub global: Global, - pub instance: Instance, pub memory: Memory, - pub module: ManuallyDrop>, } impl wasmtime_extern_t { @@ -121,8 +95,6 @@ impl wasmtime_extern_t { WASMTIME_EXTERN_GLOBAL => Extern::Global(self.of.global), WASMTIME_EXTERN_TABLE => Extern::Table(self.of.table), WASMTIME_EXTERN_MEMORY => Extern::Memory(self.of.memory), - WASMTIME_EXTERN_INSTANCE => Extern::Instance(self.of.instance), - WASMTIME_EXTERN_MODULE => Extern::Module(self.of.module.module.clone()), other => panic!("unknown wasm_extern_kind_t: {}", other), } } @@ -147,26 +119,6 @@ impl From for wasmtime_extern_t { kind: WASMTIME_EXTERN_MEMORY, of: wasmtime_extern_union { memory }, }, - Extern::Instance(instance) => wasmtime_extern_t { - kind: WASMTIME_EXTERN_INSTANCE, - of: wasmtime_extern_union { instance }, - }, - Extern::Module(module) => wasmtime_extern_t { - kind: WASMTIME_EXTERN_MODULE, - of: wasmtime_extern_union { - module: ManuallyDrop::new(Box::new(wasmtime_module_t { module })), - }, - }, - } - } -} - -impl Drop for wasmtime_extern_t { - fn drop(&mut self) { - if self.kind == WASMTIME_EXTERN_MODULE { - unsafe { - ManuallyDrop::drop(&mut self.of.module); - } } } } diff --git a/crates/c-api/src/instance.rs b/crates/c-api/src/instance.rs index 4c17bc3a069e..4897520bedc4 100644 --- a/crates/c-api/src/instance.rs +++ b/crates/c-api/src/instance.rs @@ -1,41 +1,21 @@ use crate::{ wasm_extern_t, wasm_extern_vec_t, wasm_module_t, wasm_store_t, wasm_trap_t, wasmtime_error_t, - wasmtime_extern_t, wasmtime_instancetype_t, wasmtime_module_t, CStoreContext, CStoreContextMut, - StoreRef, + wasmtime_extern_t, wasmtime_module_t, CStoreContextMut, StoreRef, }; use std::mem::MaybeUninit; -use wasmtime::{Extern, Instance, Trap}; +use wasmtime::{Instance, Trap}; #[derive(Clone)] -#[repr(transparent)] pub struct wasm_instance_t { - ext: wasm_extern_t, + store: StoreRef, + instance: Instance, } wasmtime_c_api_macros::declare_ref!(wasm_instance_t); impl wasm_instance_t { pub(crate) fn new(store: StoreRef, instance: Instance) -> wasm_instance_t { - wasm_instance_t { - ext: wasm_extern_t { - store: store, - which: instance.into(), - }, - } - } - - pub(crate) fn try_from(e: &wasm_extern_t) -> Option<&wasm_instance_t> { - match &e.which { - Extern::Instance(_) => Some(unsafe { &*(e as *const _ as *const _) }), - _ => None, - } - } - - pub(crate) fn instance(&self) -> Instance { - match self.ext.which { - Extern::Instance(i) => i, - _ => unreachable!(), - } + wasm_instance_t { store, instance } } } @@ -54,7 +34,7 @@ pub unsafe extern "C" fn wasm_instance_new( None => None, }) .collect::>(); - match Instance::new(store.store.context_mut(), wasm_module.module(), &imports) { + match Instance::new(store.store.context_mut(), &wasm_module.module, &imports) { Ok(instance) => Some(Box::new(wasm_instance_t::new( store.store.clone(), instance, @@ -68,21 +48,16 @@ pub unsafe extern "C" fn wasm_instance_new( } } -#[no_mangle] -pub extern "C" fn wasm_instance_as_extern(m: &wasm_instance_t) -> &wasm_extern_t { - &m.ext -} - #[no_mangle] pub unsafe extern "C" fn wasm_instance_exports( instance: &mut wasm_instance_t, out: &mut wasm_extern_vec_t, ) { - let store = instance.ext.store.clone(); + let store = instance.store.clone(); out.set_buffer( instance - .instance() - .exports(instance.ext.store.context_mut()) + .instance + .exports(instance.store.context_mut()) .map(|e| { Some(Box::new(wasm_extern_t { which: e.into_extern(), @@ -133,14 +108,6 @@ pub(crate) fn handle_instantiate( } } -#[no_mangle] -pub extern "C" fn wasmtime_instance_type( - store: CStoreContext<'_>, - instance: &Instance, -) -> Box { - Box::new(wasmtime_instancetype_t::new(instance.ty(store))) -} - #[no_mangle] pub unsafe extern "C" fn wasmtime_instance_export_get( store: CStoreContextMut<'_>, diff --git a/crates/c-api/src/linker.rs b/crates/c-api/src/linker.rs index 1ff5624a5257..b712e4a9b898 100644 --- a/crates/c-api/src/linker.rs +++ b/crates/c-api/src/linker.rs @@ -173,13 +173,9 @@ pub unsafe extern "C" fn wasmtime_linker_get( Ok(s) => s, Err(_) => return false, }; - let name = if name.is_null() { - None - } else { - match str::from_utf8(crate::slice_from_raw_parts(name, name_len)) { - Ok(s) => Some(s), - Err(_) => return false, - } + let name = match str::from_utf8(crate::slice_from_raw_parts(name, name_len)) { + Ok(s) => s, + Err(_) => return false, }; match linker.get(store, module, name) { Some(which) => { diff --git a/crates/c-api/src/module.rs b/crates/c-api/src/module.rs index 9dc0eabdd9ea..988440f14385 100644 --- a/crates/c-api/src/module.rs +++ b/crates/c-api/src/module.rs @@ -1,43 +1,22 @@ use crate::{ handle_result, wasm_byte_vec_t, wasm_engine_t, wasm_exporttype_t, wasm_exporttype_vec_t, - wasm_extern_t, wasm_importtype_t, wasm_importtype_vec_t, wasm_store_t, wasmtime_error_t, - wasmtime_moduletype_t, StoreRef, + wasm_importtype_t, wasm_importtype_vec_t, wasm_store_t, wasmtime_error_t, }; use anyhow::Context; use std::ffi::CStr; use std::os::raw::c_char; -use wasmtime::{Engine, Extern, Module}; +use wasmtime::{Engine, Module}; #[derive(Clone)] -#[repr(transparent)] pub struct wasm_module_t { - ext: wasm_extern_t, + pub(crate) module: Module, } wasmtime_c_api_macros::declare_ref!(wasm_module_t); impl wasm_module_t { - pub(crate) fn new(store: StoreRef, module: Module) -> wasm_module_t { - wasm_module_t { - ext: wasm_extern_t { - store: store, - which: module.into(), - }, - } - } - - pub(crate) fn try_from(e: &wasm_extern_t) -> Option<&wasm_module_t> { - match &e.which { - Extern::Module(_) => Some(unsafe { &*(e as *const _ as *const _) }), - _ => None, - } - } - - pub(crate) fn module(&self) -> &Module { - match &self.ext.which { - Extern::Module(i) => i, - _ => unreachable!(), - } + pub(crate) fn new(module: Module) -> wasm_module_t { + wasm_module_t { module } } } @@ -55,7 +34,7 @@ pub unsafe extern "C" fn wasm_module_new( binary: &wasm_byte_vec_t, ) -> Option> { match Module::from_binary(store.store.context().engine(), binary.as_slice()) { - Ok(module) => Some(Box::new(wasm_module_t::new(store.store.clone(), module))), + Ok(module) => Some(Box::new(wasm_module_t::new(module))), Err(_) => None, } } @@ -68,15 +47,10 @@ pub unsafe extern "C" fn wasm_module_validate( Module::validate(store.store.context().engine(), binary.as_slice()).is_ok() } -#[no_mangle] -pub extern "C" fn wasm_module_as_extern(m: &wasm_module_t) -> &wasm_extern_t { - &m.ext -} - #[no_mangle] pub extern "C" fn wasm_module_exports(module: &wasm_module_t, out: &mut wasm_exporttype_vec_t) { let exports = module - .module() + .module .exports() .map(|e| { Some(Box::new(wasm_exporttype_t::new( @@ -91,12 +65,12 @@ pub extern "C" fn wasm_module_exports(module: &wasm_module_t, out: &mut wasm_exp #[no_mangle] pub extern "C" fn wasm_module_imports(module: &wasm_module_t, out: &mut wasm_importtype_vec_t) { let imports = module - .module() + .module .imports() .map(|i| { Some(Box::new(wasm_importtype_t::new( i.module().to_owned(), - i.name().map(|s| s.to_owned()), + i.name().to_owned(), i.ty(), ))) }) @@ -107,7 +81,7 @@ pub extern "C" fn wasm_module_imports(module: &wasm_module_t, out: &mut wasm_imp #[no_mangle] pub extern "C" fn wasm_module_share(module: &wasm_module_t) -> Box { Box::new(wasm_shared_module_t { - module: module.module().clone(), + module: module.module.clone(), }) } @@ -118,7 +92,7 @@ pub unsafe extern "C" fn wasm_module_obtain( ) -> Option> { let module = shared_module.module.clone(); if Engine::same(store.store.context().engine(), module.engine()) { - Some(Box::new(wasm_module_t::new(store.store.clone(), module))) + Some(Box::new(wasm_module_t::new(module))) } else { None } @@ -126,7 +100,7 @@ pub unsafe extern "C" fn wasm_module_obtain( #[no_mangle] pub extern "C" fn wasm_module_serialize(module: &wasm_module_t, ret: &mut wasm_byte_vec_t) { - if let Ok(buf) = module.module().serialize() { + if let Ok(buf) = module.module.serialize() { ret.set_buffer(buf); } } @@ -137,7 +111,7 @@ pub unsafe extern "C" fn wasm_module_deserialize( binary: &wasm_byte_vec_t, ) -> Option> { match Module::deserialize(store.store.context().engine(), binary.as_slice()) { - Ok(module) => Some(Box::new(wasm_module_t::new(store.store.clone(), module))), + Ok(module) => Some(Box::new(wasm_module_t::new(module))), Err(_) => None, } } @@ -180,11 +154,6 @@ pub unsafe extern "C" fn wasmtime_module_validate( handle_result(Module::validate(&engine.engine, binary), |()| {}) } -#[no_mangle] -pub extern "C" fn wasmtime_module_type(m: &wasmtime_module_t) -> Box { - Box::new(wasmtime_moduletype_t::new(m.module.ty())) -} - #[no_mangle] pub extern "C" fn wasmtime_module_serialize( module: &wasmtime_module_t, diff --git a/crates/c-api/src/types.rs b/crates/c-api/src/types.rs index e2f459d7e550..9df1715cf319 100644 --- a/crates/c-api/src/types.rs +++ b/crates/c-api/src/types.rs @@ -20,18 +20,14 @@ mod r#extern; mod func; mod global; mod import; -mod instance; mod memory; -mod module; mod table; mod val; pub use self::export::*; pub use self::func::*; pub use self::global::*; pub use self::import::*; -pub use self::instance::*; pub use self::memory::*; -pub use self::module::*; pub use self::r#extern::*; pub use self::table::*; pub use self::val::*; diff --git a/crates/c-api/src/types/extern.rs b/crates/c-api/src/types/extern.rs index f36ff4b27997..21278a25e722 100644 --- a/crates/c-api/src/types/extern.rs +++ b/crates/c-api/src/types/extern.rs @@ -1,6 +1,5 @@ use crate::{wasm_functype_t, wasm_globaltype_t, wasm_memorytype_t, wasm_tabletype_t}; -use crate::{wasmtime_instancetype_t, wasmtime_moduletype_t}; -use crate::{CFuncType, CGlobalType, CInstanceType, CMemoryType, CModuleType, CTableType}; +use crate::{CFuncType, CGlobalType, CMemoryType, CTableType}; use wasmtime::ExternType; #[repr(C)] @@ -17,8 +16,6 @@ pub(crate) enum CExternType { Global(CGlobalType), Memory(CMemoryType), Table(CTableType), - Instance(CInstanceType), - Module(CModuleType), } pub type wasm_externkind_t = u8; @@ -27,8 +24,6 @@ pub const WASM_EXTERN_FUNC: wasm_externkind_t = 0; pub const WASM_EXTERN_GLOBAL: wasm_externkind_t = 1; pub const WASM_EXTERN_TABLE: wasm_externkind_t = 2; pub const WASM_EXTERN_MEMORY: wasm_externkind_t = 3; -pub const WASM_EXTERN_MODULE: wasm_externkind_t = 4; -pub const WASM_EXTERN_INSTANCE: wasm_externkind_t = 5; impl wasm_externtype_t { pub(crate) fn new(ty: ExternType) -> wasm_externtype_t { @@ -38,8 +33,6 @@ impl wasm_externtype_t { ExternType::Global(f) => CExternType::Global(CGlobalType::new(f)), ExternType::Memory(f) => CExternType::Memory(CMemoryType::new(f)), ExternType::Table(f) => CExternType::Table(CTableType::new(f)), - ExternType::Instance(f) => CExternType::Instance(CInstanceType::new(f)), - ExternType::Module(f) => CExternType::Module(CModuleType::new(f)), }, } } @@ -50,8 +43,6 @@ impl wasm_externtype_t { CExternType::Table(f) => ExternType::Table(f.ty.clone()), CExternType::Global(f) => ExternType::Global(f.ty.clone()), CExternType::Memory(f) => ExternType::Memory(f.ty.clone()), - CExternType::Instance(f) => ExternType::Instance(f.ty.clone()), - CExternType::Module(f) => ExternType::Module(f.ty.clone()), } } } @@ -63,8 +54,6 @@ pub extern "C" fn wasm_externtype_kind(et: &wasm_externtype_t) -> wasm_externkin CExternType::Table(_) => WASM_EXTERN_TABLE, CExternType::Global(_) => WASM_EXTERN_GLOBAL, CExternType::Memory(_) => WASM_EXTERN_MEMORY, - CExternType::Instance(_) => WASM_EXTERN_INSTANCE, - CExternType::Module(_) => WASM_EXTERN_MODULE, } } @@ -121,17 +110,3 @@ pub extern "C" fn wasm_externtype_as_memorytype_const( ) -> Option<&wasm_memorytype_t> { wasm_memorytype_t::try_from(et) } - -#[no_mangle] -pub extern "C" fn wasmtime_externtype_as_moduletype( - et: &wasm_externtype_t, -) -> Option<&wasmtime_moduletype_t> { - wasmtime_moduletype_t::try_from(et) -} - -#[no_mangle] -pub extern "C" fn wasmtime_externtype_as_instancetype( - et: &wasm_externtype_t, -) -> Option<&wasmtime_instancetype_t> { - wasmtime_instancetype_t::try_from(et) -} diff --git a/crates/c-api/src/types/import.rs b/crates/c-api/src/types/import.rs index ca12cf408d6c..f9e97a287074 100644 --- a/crates/c-api/src/types/import.rs +++ b/crates/c-api/src/types/import.rs @@ -6,7 +6,7 @@ use wasmtime::ExternType; #[derive(Clone)] pub struct wasm_importtype_t { pub(crate) module: String, - pub(crate) name: Option, + pub(crate) name: String, pub(crate) ty: ExternType, module_cache: OnceCell, name_cache: OnceCell, @@ -16,7 +16,7 @@ pub struct wasm_importtype_t { wasmtime_c_api_macros::declare_ty!(wasm_importtype_t); impl wasm_importtype_t { - pub(crate) fn new(module: String, name: Option, ty: ExternType) -> wasm_importtype_t { + pub(crate) fn new(module: String, name: String, ty: ExternType) -> wasm_importtype_t { wasm_importtype_t { module, name, @@ -31,16 +31,13 @@ impl wasm_importtype_t { #[no_mangle] pub extern "C" fn wasm_importtype_new( module: &mut wasm_name_t, - name: Option<&mut wasm_name_t>, + name: &mut wasm_name_t, ty: Box, ) -> Option> { let module = module.take(); - let name = name.map(|n| n.take()); + let name = name.take(); let module = String::from_utf8(module).ok()?; - let name = match name { - Some(name) => Some(String::from_utf8(name).ok()?), - None => None, - }; + let name = String::from_utf8(name).ok()?; Some(Box::new(wasm_importtype_t::new(module, name, ty.ty()))) } @@ -51,12 +48,9 @@ pub extern "C" fn wasm_importtype_module(it: &wasm_importtype_t) -> &wasm_name_t } #[no_mangle] -pub extern "C" fn wasm_importtype_name(it: &wasm_importtype_t) -> Option<&wasm_name_t> { - let name = it.name.as_ref()?; - Some( - it.name_cache - .get_or_init(|| wasm_name_t::from_name(name.to_string())), - ) +pub extern "C" fn wasm_importtype_name(it: &wasm_importtype_t) -> &wasm_name_t { + it.name_cache + .get_or_init(|| wasm_name_t::from_name(it.name.to_string())) } #[no_mangle] diff --git a/crates/c-api/src/types/instance.rs b/crates/c-api/src/types/instance.rs deleted file mode 100644 index b4a18d295818..000000000000 --- a/crates/c-api/src/types/instance.rs +++ /dev/null @@ -1,68 +0,0 @@ -use crate::{wasm_exporttype_t, wasm_exporttype_vec_t, wasm_externtype_t, CExternType}; -use wasmtime::InstanceType; - -#[repr(transparent)] -#[derive(Clone)] -pub struct wasmtime_instancetype_t { - ext: wasm_externtype_t, -} - -wasmtime_c_api_macros::declare_ty!(wasmtime_instancetype_t); - -#[derive(Clone)] -pub(crate) struct CInstanceType { - pub(crate) ty: InstanceType, -} - -impl wasmtime_instancetype_t { - pub(crate) fn new(ty: InstanceType) -> wasmtime_instancetype_t { - wasmtime_instancetype_t { - ext: wasm_externtype_t::new(ty.into()), - } - } - - pub(crate) fn try_from(e: &wasm_externtype_t) -> Option<&wasmtime_instancetype_t> { - match &e.which { - CExternType::Instance(_) => Some(unsafe { &*(e as *const _ as *const _) }), - _ => None, - } - } - - pub(crate) fn ty(&self) -> &CInstanceType { - match &self.ext.which { - CExternType::Instance(f) => &f, - _ => unreachable!(), - } - } -} - -impl CInstanceType { - pub(crate) fn new(ty: InstanceType) -> CInstanceType { - CInstanceType { ty } - } -} -#[no_mangle] -pub extern "C" fn wasmtime_instancetype_as_externtype( - ty: &wasmtime_instancetype_t, -) -> &wasm_externtype_t { - &ty.ext -} - -#[no_mangle] -pub extern "C" fn wasmtime_instancetype_exports( - instance: &wasmtime_instancetype_t, - out: &mut wasm_exporttype_vec_t, -) { - let exports = instance - .ty() - .ty - .exports() - .map(|e| { - Some(Box::new(wasm_exporttype_t::new( - e.name().to_owned(), - e.ty(), - ))) - }) - .collect::>(); - out.set_buffer(exports); -} diff --git a/crates/c-api/src/types/module.rs b/crates/c-api/src/types/module.rs deleted file mode 100644 index 3af98b6f6948..000000000000 --- a/crates/c-api/src/types/module.rs +++ /dev/null @@ -1,92 +0,0 @@ -use crate::{ - wasm_exporttype_t, wasm_exporttype_vec_t, wasm_externtype_t, wasm_importtype_t, - wasm_importtype_vec_t, CExternType, -}; -use wasmtime::ModuleType; - -#[repr(transparent)] -#[derive(Clone)] -pub struct wasmtime_moduletype_t { - ext: wasm_externtype_t, -} - -wasmtime_c_api_macros::declare_ty!(wasmtime_moduletype_t); - -#[derive(Clone)] -pub(crate) struct CModuleType { - pub(crate) ty: ModuleType, -} - -impl wasmtime_moduletype_t { - pub(crate) fn new(ty: ModuleType) -> wasmtime_moduletype_t { - wasmtime_moduletype_t { - ext: wasm_externtype_t::new(ty.into()), - } - } - - pub(crate) fn try_from(e: &wasm_externtype_t) -> Option<&wasmtime_moduletype_t> { - match &e.which { - CExternType::Module(_) => Some(unsafe { &*(e as *const _ as *const _) }), - _ => None, - } - } - - pub(crate) fn ty(&self) -> &CModuleType { - match &self.ext.which { - CExternType::Module(f) => &f, - _ => unreachable!(), - } - } -} - -impl CModuleType { - pub(crate) fn new(ty: ModuleType) -> CModuleType { - CModuleType { ty } - } -} - -#[no_mangle] -pub extern "C" fn wasmtime_moduletype_as_externtype( - ty: &wasmtime_moduletype_t, -) -> &wasm_externtype_t { - &ty.ext -} - -#[no_mangle] -pub extern "C" fn wasmtime_moduletype_exports( - module: &wasmtime_moduletype_t, - out: &mut wasm_exporttype_vec_t, -) { - let exports = module - .ty() - .ty - .exports() - .map(|e| { - Some(Box::new(wasm_exporttype_t::new( - e.name().to_owned(), - e.ty(), - ))) - }) - .collect::>(); - out.set_buffer(exports); -} - -#[no_mangle] -pub extern "C" fn wasmtime_moduletype_imports( - module: &wasmtime_moduletype_t, - out: &mut wasm_importtype_vec_t, -) { - let imports = module - .ty() - .ty - .imports() - .map(|i| { - Some(Box::new(wasm_importtype_t::new( - i.module().to_owned(), - i.name().map(|s| s.to_owned()), - i.ty(), - ))) - }) - .collect::>(); - out.set_buffer(imports); -} diff --git a/crates/environ/src/module.rs b/crates/environ/src/module.rs index 15c0389eacf1..e9611be37efa 100644 --- a/crates/environ/src/module.rs +++ b/crates/environ/src/module.rs @@ -836,8 +836,6 @@ impl Default for TableInitialization { #[allow(missing_docs)] pub enum ModuleType { Function(SignatureIndex), - Module(ModuleTypeIndex), - Instance(InstanceTypeIndex), } impl ModuleType { @@ -846,7 +844,6 @@ impl ModuleType { pub fn unwrap_function(&self) -> SignatureIndex { match self { ModuleType::Function(f) => *f, - _ => panic!("not a function type"), } } } @@ -915,12 +912,6 @@ pub struct Module { /// WebAssembly global variables. pub globals: PrimaryMap, - - /// The type of each wasm instance this module defines. - pub instances: PrimaryMap, - - /// The type of each nested wasm module this module contains. - pub modules: PrimaryMap, } /// Initialization routines for creating an instance, encompassing imports, @@ -931,59 +922,12 @@ pub enum Initializer { Import { /// Name of this import name: String, - /// The field name projection of this import. When module-linking is - /// enabled this is always `None`. Otherwise this is always `Some`. - field: Option, + /// The field name projection of this import + field: String, /// Where this import will be placed, which also has type information /// about the import. index: EntityIndex, }, - - /// An export from a previously defined instance is being inserted into our - /// index space. - /// - /// Note that when the module linking proposal is enabled two-level imports - /// will implicitly desugar to this initializer. - AliasInstanceExport { - /// The instance that we're referencing. - instance: InstanceIndex, - /// Which export is being inserted into our index space. - export: String, - }, - - /// A module is being instantiated with previously configured initializers - /// as arguments. - Instantiate { - /// The module that this instance is instantiating. - module: ModuleIndex, - /// The arguments provided to instantiation, along with their name in - /// the instance being instantiated. - args: IndexMap, - }, - - /// A module is being created from a set of compiled artifacts. - CreateModule { - /// The index of the artifact that's being converted into a module. - artifact_index: usize, - /// The list of artifacts that this module value will be inheriting. - artifacts: Vec, - /// The list of modules that this module value will inherit. - modules: Vec, - }, - - /// A module is created from a closed-over-module value, defined when this - /// module was created. - DefineModule(usize), -} - -/// Where module values can come from when creating a new module from a compiled -/// artifact. -#[derive(Debug, Clone, Serialize, Deserialize)] -pub enum ModuleUpvar { - /// A module value is inherited from the module creating the new module. - Inherit(usize), - /// A module value comes from the instance-to-be-created module index space. - Local(ModuleIndex), } impl Module { @@ -1100,12 +1044,11 @@ impl Module { /// Returns an iterator of all the imports in this module, along with their /// module name, field name, and type that's being imported. - pub fn imports(&self) -> impl Iterator, EntityType)> { - self.initializers.iter().filter_map(move |i| match i { + pub fn imports(&self) -> impl Iterator { + self.initializers.iter().map(move |i| match i { Initializer::Import { name, field, index } => { - Some((name.as_str(), field.as_deref(), self.type_of(*index))) + (name.as_str(), field.as_str(), self.type_of(*index)) } - _ => None, }) } @@ -1116,8 +1059,6 @@ impl Module { EntityIndex::Table(i) => EntityType::Table(self.table_plans[i].table), EntityIndex::Memory(i) => EntityType::Memory(self.memory_plans[i].memory), EntityIndex::Function(i) => EntityType::Function(self.functions[i].signature), - EntityIndex::Instance(i) => EntityType::Instance(self.instances[i]), - EntityIndex::Module(i) => EntityType::Module(self.modules[i]), } } @@ -1149,26 +1090,6 @@ impl Module { #[allow(missing_docs)] pub struct TypeTables { pub wasm_signatures: PrimaryMap, - pub module_signatures: PrimaryMap, - pub instance_signatures: PrimaryMap, -} - -/// The type signature of known modules. -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct ModuleSignature { - /// All imports in this module, listed in order with their name and - /// what type they're importing. - pub imports: IndexMap, - /// Exports are what an instance type conveys, so we go through an - /// indirection over there. - pub exports: InstanceTypeIndex, -} - -/// The type signature of known instances. -#[derive(Debug, Clone, Serialize, Deserialize, Default)] -pub struct InstanceSignature { - /// The name of what's being exported as well as its type signature. - pub exports: IndexMap, } /// Type information about functions in a wasm module. diff --git a/crates/environ/src/module_environ.rs b/crates/environ/src/module_environ.rs index 878cf0ed834c..643f12865bbc 100644 --- a/crates/environ/src/module_environ.rs +++ b/crates/environ/src/module_environ.rs @@ -1,24 +1,21 @@ use crate::module::{ - AnyfuncIndex, Initializer, InstanceSignature, MemoryInitialization, MemoryInitializer, - MemoryPlan, Module, ModuleSignature, ModuleType, ModuleUpvar, TableInitializer, TablePlan, - TypeTables, + AnyfuncIndex, Initializer, MemoryInitialization, MemoryInitializer, MemoryPlan, Module, + ModuleType, TableInitializer, TablePlan, TypeTables, }; use crate::{ DataIndex, DefinedFuncIndex, ElemIndex, EntityIndex, EntityType, FuncIndex, Global, - GlobalIndex, GlobalInit, InstanceIndex, InstanceTypeIndex, MemoryIndex, ModuleIndex, - ModuleTypeIndex, PrimaryMap, SignatureIndex, TableIndex, TableInitialization, Tunables, - TypeIndex, WasmError, WasmFuncType, WasmResult, + GlobalIndex, GlobalInit, MemoryIndex, PrimaryMap, SignatureIndex, TableIndex, + TableInitialization, Tunables, TypeIndex, WasmError, WasmFuncType, WasmResult, }; use cranelift_entity::packed_option::ReservedValue; use std::borrow::Cow; -use std::collections::{hash_map::Entry, HashMap}; +use std::collections::HashMap; use std::convert::{TryFrom, TryInto}; -use std::mem; use std::path::PathBuf; use std::sync::Arc; use wasmparser::Type as WasmType; use wasmparser::{ - Alias, DataKind, ElementItem, ElementKind, ExternalKind, FuncValidator, FunctionBody, + DataKind, ElementItem, ElementKind, ExternalKind, FuncValidator, FunctionBody, ImportSectionEntryType, NameSectionReader, Naming, Operator, Parser, Payload, TypeDef, Validator, ValidatorResources, WasmFeatures, }; @@ -28,18 +25,6 @@ pub struct ModuleEnvironment<'data> { /// The current module being translated result: ModuleTranslation<'data>, - /// Modules which have finished translation. This only really applies for - /// the module linking proposal. - results: Vec>, - - /// Modules which are in-progress being translated, or otherwise also known - /// as the outer modules of the current module being processed. - in_progress: Vec>, - - /// How many modules that have not yet made their way into `results` which - /// are coming at some point. - modules_to_be: usize, - /// Intern'd types for this entire translation, shared by all modules. types: TypeTables, @@ -48,7 +33,6 @@ pub struct ModuleEnvironment<'data> { // Various bits and pieces of configuration features: WasmFeatures, tunables: Tunables, - first_module: bool, } /// The result of translating via `ModuleEnvironment`. Function bodies are not @@ -102,16 +86,6 @@ pub struct ModuleTranslation<'data> { /// When we're parsing the code section this will be incremented so we know /// which function is currently being defined. code_index: u32, - - implicit_instances: HashMap<&'data str, InstanceIndex>, - - /// The artifacts which are needed from the parent module when this module - /// is created. This is used to insert into `Initializer::CreateModule` when - /// this module is defined in the parent. - creation_artifacts: Vec, - - /// Same as `creation_artifacts`, but for modules instead of artifacts. - creation_modules: Vec, } /// Contains function data: byte code and its offset in the module. @@ -168,13 +142,9 @@ impl<'data> ModuleEnvironment<'data> { pub fn new(tunables: &Tunables, features: &WasmFeatures) -> Self { Self { result: ModuleTranslation::default(), - results: Vec::with_capacity(1), - in_progress: Vec::new(), - modules_to_be: 1, types: Default::default(), tunables: tunables.clone(), features: *features, - first_module: true, interned_func_types: Default::default(), } } @@ -198,7 +168,7 @@ impl<'data> ModuleEnvironment<'data> { pub fn translate( mut self, data: &'data [u8], - ) -> WasmResult<(usize, Vec>, TypeTables)> { + ) -> WasmResult<(ModuleTranslation<'data>, TypeTables)> { let mut validator = Validator::new(); validator.wasm_features(self.features); @@ -206,8 +176,7 @@ impl<'data> ModuleEnvironment<'data> { self.translate_payload(&mut validator, payload?)?; } - assert!(self.results.len() > 0); - Ok((self.results.len() - 1, self.results, self.types)) + Ok((self.result, self.types)) } fn translate_payload( @@ -218,18 +187,6 @@ impl<'data> ModuleEnvironment<'data> { match payload { Payload::Version { num, range } => { validator.version(num, &range)?; - - // If this is the first time this method is called, nothing to - // do. - if self.first_module { - self.first_module = false; - } else { - // Reset our internal state for a new module by saving the - // current module in `results`. - let in_progress = mem::replace(&mut self.result, ModuleTranslation::default()); - self.in_progress.push(in_progress); - self.modules_to_be -= 1; - } } Payload::End => { @@ -253,46 +210,6 @@ impl<'data> ModuleEnvironment<'data> { .collect(); self.result.exported_signatures.sort_unstable(); self.result.exported_signatures.dedup(); - - self.result.creation_artifacts.shrink_to_fit(); - self.result.creation_modules.shrink_to_fit(); - - let (record_initializer, mut done) = match self.in_progress.pop() { - Some(m) => (true, mem::replace(&mut self.result, m)), - None => (false, mem::take(&mut self.result)), - }; - - if record_initializer { - // Record the type of the module we just finished in our own - // module's list of modules. - let sig = self.gen_type_of_module(&done.module); - self.result.module.modules.push(sig); - - // The root module will store the artifacts for this - // finished module at `artifact_index`. This then needs to - // be inherited by all later modules coming down to our - // now-current `self.result`... - let mut artifact_index = self.results.len(); - for result in self.in_progress.iter_mut().chain(Some(&mut self.result)) { - result.creation_artifacts.push(artifact_index); - artifact_index = result.creation_artifacts.len() - 1; - } - // ... and then `self.result` needs to create a new module - // with whatever was record to save off as its own - // artifacts/modules. - self.result - .module - .initializers - .push(Initializer::CreateModule { - artifact_index, - artifacts: mem::take(&mut done.creation_artifacts), - modules: mem::take(&mut done.creation_modules), - }); - } - - // And the final step is to insert the module into the list of - // finished modules to get returned at the end. - self.results.push(done); } Payload::TypeSection(types) => { @@ -306,26 +223,10 @@ impl<'data> ModuleEnvironment<'data> { TypeDef::Func(wasm_func_ty) => { self.declare_type_func(wasm_func_ty.try_into()?)?; } - TypeDef::Module(t) => { - let imports = t - .imports - .iter() - .map(|i| Ok((i.module, i.field, self.entity_type(i.ty)?))) - .collect::>>()?; - let exports = t - .exports - .iter() - .map(|e| Ok((e.name, self.entity_type(e.ty)?))) - .collect::>>()?; - self.declare_type_module(&imports, &exports)?; - } - TypeDef::Instance(t) => { - let exports = t - .exports - .iter() - .map(|e| Ok((e.name, self.entity_type(e.ty)?))) - .collect::>>()?; - self.declare_type_instance(&exports)?; + + // doesn't get past validation + TypeDef::Module(_) | TypeDef::Instance(_) => { + unreachable!(); } } } @@ -347,16 +248,6 @@ impl<'data> ModuleEnvironment<'data> { self.result.debuginfo.wasm_file.imported_func_count += 1; EntityType::Function(sig_index) } - ImportSectionEntryType::Module(index) => { - let index = TypeIndex::from_u32(index); - let signature = self.type_to_module_type(index)?; - EntityType::Module(signature) - } - ImportSectionEntryType::Instance(index) => { - let index = TypeIndex::from_u32(index); - let signature = self.type_to_instance_type(index)?; - EntityType::Instance(signature) - } ImportSectionEntryType::Memory(ty) => { if ty.shared { return Err(WasmError::Unsupported("shared memories".to_owned())); @@ -374,9 +265,11 @@ impl<'data> ModuleEnvironment<'data> { } // doesn't get past validation - ImportSectionEntryType::Tag(_) => unreachable!(), + ImportSectionEntryType::Module(_) + | ImportSectionEntryType::Instance(_) + | ImportSectionEntryType::Tag(_) => unreachable!(), }; - self.declare_import(import.module, import.field, ty); + self.declare_import(import.module, import.field.unwrap(), ty); } } @@ -485,13 +378,12 @@ impl<'data> ModuleEnvironment<'data> { ExternalKind::Table => EntityIndex::Table(TableIndex::from_u32(index)), ExternalKind::Memory => EntityIndex::Memory(MemoryIndex::from_u32(index)), ExternalKind::Global => EntityIndex::Global(GlobalIndex::from_u32(index)), - ExternalKind::Module => EntityIndex::Module(ModuleIndex::from_u32(index)), - ExternalKind::Instance => { - EntityIndex::Instance(InstanceIndex::from_u32(index)) - } // this never gets past validation - ExternalKind::Tag | ExternalKind::Type => unreachable!(), + ExternalKind::Module + | ExternalKind::Instance + | ExternalKind::Tag + | ExternalKind::Type => unreachable!(), }; self.result .module @@ -725,177 +617,14 @@ impl<'data> ModuleEnvironment<'data> { // the passive count, do not reserve anything here. } - Payload::InstanceSection(s) => { - validator.instance_section(&s)?; - - let cnt = usize::try_from(s.get_count()).unwrap(); - self.result.module.instances.reserve(cnt); - self.result.module.initializers.reserve(cnt); - - for instance in s { - let instance = instance?; - let module = ModuleIndex::from_u32(instance.module()); - let args = instance - .args()? - .into_iter() - .map(|arg| { - let arg = arg?; - let index = match arg.kind { - ExternalKind::Function => { - EntityIndex::Function(FuncIndex::from_u32(arg.index)) - } - ExternalKind::Table => { - EntityIndex::Table(TableIndex::from_u32(arg.index)) - } - ExternalKind::Memory => { - EntityIndex::Memory(MemoryIndex::from_u32(arg.index)) - } - ExternalKind::Global => { - EntityIndex::Global(GlobalIndex::from_u32(arg.index)) - } - ExternalKind::Module => { - EntityIndex::Module(ModuleIndex::from_u32(arg.index)) - } - ExternalKind::Instance => { - EntityIndex::Instance(InstanceIndex::from_u32(arg.index)) - } - - // this won't pass validation - ExternalKind::Tag | ExternalKind::Type => unreachable!(), - }; - Ok((arg.name.to_string(), index)) - }) - .collect::>()?; - - // Record the type of this instance with the type signature of the - // module we're instantiating and then also add an initializer which - // records that we'll be adding to the instance index space here. - let module_ty = self.result.module.modules[module]; - let instance_ty = self.types.module_signatures[module_ty].exports; - self.result.module.instances.push(instance_ty); - self.result - .module - .initializers - .push(Initializer::Instantiate { module, args }); - } - } Payload::AliasSection(s) => { validator.alias_section(&s)?; + unreachable!() // should never get past validation + } - for alias in s { - match alias? { - // Types are easy, we statically know everything so - // we're just copying some pointers from our parent - // module to our own module. - // - // Note that we don't add an initializer for this alias - // because we statically know where all types point to. - Alias::OuterType { - relative_depth, - index, - } => { - let index = TypeIndex::from_u32(index); - let module_idx = self.in_progress.len() - 1 - (relative_depth as usize); - let ty = self.in_progress[module_idx].module.types[index]; - self.result.module.types.push(ty); - } - - // Modules are a bit trickier since we need to record - // how to track the state from the original module down - // to our own. - Alias::OuterModule { - relative_depth, - index, - } => { - let index = ModuleIndex::from_u32(index); - - // First we can copy the type from the parent module - // into our own module to record what type our - // module definition will have. - let module_idx = self.in_progress.len() - 1 - (relative_depth as usize); - let module_ty = self.in_progress[module_idx].module.modules[index]; - self.result.module.modules.push(module_ty); - - // Next we'll be injecting a module value that is - // closed over, and that will be used to define the - // module into the index space. Record an - // initializer about where our module is sourced - // from (which will be stored within each module - // value itself). - let module_index = self.result.creation_modules.len(); - self.result - .module - .initializers - .push(Initializer::DefineModule(module_index)); - - // And finally we need to record a breadcrumb trail - // of how to get the module value into - // `module_index`. The module just after our - // destination module will use a `ModuleIndex` to - // fetch the module value, and everything else - // inbetween will inherit that module's closed-over - // value. - let mut upvar = ModuleUpvar::Local(index); - for outer in self.in_progress[module_idx + 1..].iter_mut() { - let upvar = mem::replace( - &mut upvar, - ModuleUpvar::Inherit(outer.creation_modules.len()), - ); - outer.creation_modules.push(upvar); - } - self.result.creation_modules.push(upvar); - } - - // This case is slightly more involved, we'll be - // recording all the type information for each kind of - // entity, and then we also need to record an - // initialization step to get the export from the - // instance. - Alias::InstanceExport { - instance, - export, - kind: _, - } => { - let instance = InstanceIndex::from_u32(instance); - let ty = self.result.module.instances[instance]; - match &self.types.instance_signatures[ty].exports[export] { - EntityType::Global(g) => { - self.result.module.globals.push(g.clone()); - self.result.module.num_imported_globals += 1; - } - EntityType::Memory(mem) => { - let plan = MemoryPlan::for_memory(*mem, &self.tunables); - self.result.module.memory_plans.push(plan); - self.result.module.num_imported_memories += 1; - } - EntityType::Table(t) => { - let plan = TablePlan::for_table(*t, &self.tunables); - self.result.module.table_plans.push(plan); - self.result.module.num_imported_tables += 1; - } - EntityType::Function(sig) => { - self.result.module.push_function(*sig); - self.result.module.num_imported_funcs += 1; - self.result.debuginfo.wasm_file.imported_func_count += 1; - } - EntityType::Instance(sig) => { - self.result.module.instances.push(*sig); - } - EntityType::Module(sig) => { - self.result.module.modules.push(*sig); - } - EntityType::Tag(_) => unimplemented!(), - } - self.result - .module - .initializers - .push(Initializer::AliasInstanceExport { - instance, - export: export.to_string(), - }) - } - } - } + Payload::InstanceSection(s) => { + validator.instance_section(&s)?; + unreachable!() // should never get past validation } Payload::ModuleSectionStart { @@ -904,22 +633,12 @@ impl<'data> ModuleEnvironment<'data> { size: _, } => { validator.module_section_start(count, &range)?; - - // Go ahead and reserve space in the final `results` array for `amount` - // more modules. - self.modules_to_be += count as usize; - self.results.reserve(self.modules_to_be); - - // Then also reserve space in our own local module's metadata fields - // we'll be adding to. - self.result.module.modules.reserve(count as usize); - self.result.module.initializers.reserve(count as usize); + unreachable!() // should never get past validation } Payload::ModuleSectionEntry { .. } => { validator.module_section_entry(); - // note that nothing else happens here since we rely on the next - // `Version` payload to recurse in the parsed modules. + unreachable!() // should never get past validation } Payload::CustomSection { @@ -1032,95 +751,13 @@ and for re-adding support for interface types you can see this issue: /// When the module linking proposal is disabled, however, disregard this /// logic and instead work directly with two-level imports since no /// instances are defined. - fn declare_import(&mut self, module: &'data str, field: Option<&'data str>, ty: EntityType) { - if !self.features.module_linking { - assert!(field.is_some()); - let index = self.push_type(ty); - self.result.module.initializers.push(Initializer::Import { - name: module.to_owned(), - field: field.map(|s| s.to_string()), - index, - }); - return; - } - - match field { - Some(field) => { - // If this is a two-level import then this is actually an - // implicit import of an instance, where each two-level import - // is an alias directive from the original instance. The first - // thing we do here is lookup our implicit instance, creating a - // blank one if it wasn't already created. - let instance = match self.result.implicit_instances.entry(module) { - Entry::Occupied(e) => *e.get(), - Entry::Vacant(v) => { - let ty = self - .types - .instance_signatures - .push(InstanceSignature::default()); - let idx = self.result.module.instances.push(ty); - self.result.module.initializers.push(Initializer::Import { - name: module.to_owned(), - field: None, - index: EntityIndex::Instance(idx), - }); - *v.insert(idx) - } - }; - - // Update the implicit instance's type signature with this new - // field and its type. - self.types.instance_signatures[self.result.module.instances[instance]] - .exports - .insert(field.to_string(), ty.clone()); - - // Record our implicit alias annotation which corresponds to - // this import that we're processing. - self.result - .module - .initializers - .push(Initializer::AliasInstanceExport { - instance, - export: field.to_string(), - }); - - // And then record the type information for the item that we're - // processing. - self.push_type(ty); - } - None => { - // Without a field then this is a single-level import (a feature - // of module linking) which means we're simply importing that - // name with the specified type. Record the type information and - // then the name that we're importing. - let index = self.push_type(ty); - self.result.module.initializers.push(Initializer::Import { - name: module.to_owned(), - field: None, - index, - }); - } - } - } - - fn entity_type(&self, ty: ImportSectionEntryType) -> WasmResult { - Ok(match ty { - ImportSectionEntryType::Function(sig) => { - EntityType::Function(self.type_to_signature(TypeIndex::from_u32(sig))?) - } - ImportSectionEntryType::Module(sig) => { - EntityType::Module(self.type_to_module_type(TypeIndex::from_u32(sig))?) - } - ImportSectionEntryType::Instance(sig) => { - EntityType::Instance(self.type_to_instance_type(TypeIndex::from_u32(sig))?) - } - ImportSectionEntryType::Memory(ty) => EntityType::Memory(ty.into()), - ImportSectionEntryType::Tag(t) => EntityType::Tag(t.into()), - ImportSectionEntryType::Global(ty) => { - EntityType::Global(Global::new(ty, GlobalInit::Import)?) - } - ImportSectionEntryType::Table(ty) => EntityType::Table(ty.try_into()?), - }) + fn declare_import(&mut self, module: &'data str, field: &'data str, ty: EntityType) { + let index = self.push_type(ty); + self.result.module.initializers.push(Initializer::Import { + name: module.to_owned(), + field: field.to_owned(), + index, + }); } fn push_type(&mut self, ty: EntityType) -> EntityIndex { @@ -1135,39 +772,10 @@ and for re-adding support for interface types you can see this issue: EntityIndex::Memory(self.result.module.memory_plans.push(plan)) } EntityType::Global(ty) => EntityIndex::Global(self.result.module.globals.push(ty)), - EntityType::Instance(ty) => { - EntityIndex::Instance(self.result.module.instances.push(ty)) - } - EntityType::Module(ty) => EntityIndex::Module(self.result.module.modules.push(ty)), EntityType::Tag(_) => unimplemented!(), } } - fn gen_type_of_module(&mut self, module: &Module) -> ModuleTypeIndex { - let imports = module - .imports() - .map(|(s, field, ty)| { - assert!(field.is_none()); - (s.to_string(), ty) - }) - .collect(); - let exports = module - .exports - .iter() - .map(|(name, idx)| (name.clone(), module.type_of(*idx))) - .collect(); - - // FIXME(#2469): this instance/module signature insertion should likely - // be deduplicated. - let exports = self - .types - .instance_signatures - .push(InstanceSignature { exports }); - self.types - .module_signatures - .push(ModuleSignature { imports, exports }) - } - fn flag_func_escaped(&mut self, func: FuncIndex) { let ty = &mut self.result.module.functions[func]; // If this was already assigned an anyfunc index no need to re-assign it. @@ -1197,90 +805,6 @@ and for re-adding support for interface types you can see this issue: Ok(()) } - fn declare_type_module( - &mut self, - declared_imports: &[(&'data str, Option<&'data str>, EntityType)], - exports: &[(&'data str, EntityType)], - ) -> WasmResult<()> { - let mut imports = indexmap::IndexMap::new(); - let mut instance_types = HashMap::new(); - for (module, field, ty) in declared_imports { - match field { - Some(field) => { - let idx = *instance_types - .entry(module) - .or_insert_with(|| self.types.instance_signatures.push(Default::default())); - self.types.instance_signatures[idx] - .exports - .insert(field.to_string(), ty.clone()); - if !imports.contains_key(*module) { - imports.insert(module.to_string(), EntityType::Instance(idx)); - } - } - None => { - imports.insert(module.to_string(), ty.clone()); - } - } - } - let exports = exports - .iter() - .map(|e| (e.0.to_string(), e.1.clone())) - .collect(); - - // FIXME(#2469): Like signatures above we should probably deduplicate - // the listings of module types since with module linking it's possible - // you'll need to write down the module type in multiple locations. - let exports = self - .types - .instance_signatures - .push(InstanceSignature { exports }); - let idx = self - .types - .module_signatures - .push(ModuleSignature { imports, exports }); - self.result.module.types.push(ModuleType::Module(idx)); - Ok(()) - } - - fn declare_type_instance(&mut self, exports: &[(&'data str, EntityType)]) -> WasmResult<()> { - let exports = exports - .iter() - .map(|e| (e.0.to_string(), e.1.clone())) - .collect(); - - // FIXME(#2469): Like signatures above we should probably deduplicate - // the listings of instance types since with module linking it's - // possible you'll need to write down the module type in multiple - // locations. - let idx = self - .types - .instance_signatures - .push(InstanceSignature { exports }); - self.result.module.types.push(ModuleType::Instance(idx)); - Ok(()) - } - - fn type_to_signature(&self, index: TypeIndex) -> WasmResult { - match self.result.module.types[index] { - ModuleType::Function(sig) => Ok(sig), - _ => unreachable!(), - } - } - - fn type_to_module_type(&self, index: TypeIndex) -> WasmResult { - match self.result.module.types[index] { - ModuleType::Module(sig) => Ok(sig), - _ => unreachable!(), - } - } - - fn type_to_instance_type(&self, index: TypeIndex) -> WasmResult { - match self.result.module.types[index] { - ModuleType::Instance(sig) => Ok(sig), - _ => unreachable!(), - } - } - /// Parses the Name section of the wasm module. fn name_section(&mut self, names: NameSectionReader<'data>) -> WasmResult<()> { for subsection in names { diff --git a/crates/fuzzing/src/generators.rs b/crates/fuzzing/src/generators.rs index 6c595dec8f84..f9a59909b300 100644 --- a/crates/fuzzing/src/generators.rs +++ b/crates/fuzzing/src/generators.rs @@ -382,7 +382,6 @@ impl Config { let mut cfg = wasmtime::Config::new(); cfg.wasm_bulk_memory(true) .wasm_reference_types(true) - .wasm_module_linking(self.module_config.config.module_linking_enabled) .wasm_multi_value(self.module_config.config.multi_value_enabled) .wasm_multi_memory(self.module_config.config.max_memories > 1) .wasm_simd(self.module_config.config.simd_enabled) diff --git a/crates/fuzzing/src/oracles/dummy.rs b/crates/fuzzing/src/oracles/dummy.rs index 2b727ddaed4b..7e9601560f8c 100644 --- a/crates/fuzzing/src/oracles/dummy.rs +++ b/crates/fuzzing/src/oracles/dummy.rs @@ -1,7 +1,6 @@ //! Dummy implementations of things that a Wasm module can import. use anyhow::Result; -use std::fmt::Write; use wasmtime::*; /// Create a set of dummy functions/globals/etc for the given imports. @@ -9,27 +8,13 @@ pub fn dummy_linker<'module, T>(store: &mut Store, module: &Module) -> Result let mut linker = Linker::new(store.engine()); linker.allow_shadowing(true); for import in module.imports() { - match import.name() { - Some(name) => { - linker - .define(import.module(), name, dummy_extern(store, import.ty())?) - .unwrap(); - } - None => match import.ty() { - ExternType::Instance(ty) => { - for ty in ty.exports() { - linker - .define(import.module(), ty.name(), dummy_extern(store, ty.ty())?) - .unwrap(); - } - } - other => { - linker - .define_name(import.module(), dummy_extern(store, other)?) - .unwrap(); - } - }, - } + linker + .define( + import.module(), + import.name(), + dummy_extern(store, import.ty())?, + ) + .unwrap(); } Ok(linker) } @@ -41,8 +26,6 @@ pub fn dummy_extern(store: &mut Store, ty: ExternType) -> Result { ExternType::Global(global_ty) => Extern::Global(dummy_global(store, global_ty)), ExternType::Table(table_ty) => Extern::Table(dummy_table(store, table_ty)?), ExternType::Memory(mem_ty) => Extern::Memory(dummy_memory(store, mem_ty)?), - ExternType::Instance(instance_ty) => Extern::Instance(dummy_instance(store, instance_ty)?), - ExternType::Module(module_ty) => Extern::Module(dummy_module(store.engine(), module_ty)), }) } @@ -91,297 +74,12 @@ pub fn dummy_memory(store: &mut Store, ty: MemoryType) -> Result { Memory::new(store, ty) } -/// Construct a dummy instance for the given instance type. -/// -/// This is done by using the expected type to generate a module on-the-fly -/// which we the instantiate. -pub fn dummy_instance(store: &mut Store, ty: InstanceType) -> Result { - let mut wat = WatGenerator::new(); - for ty in ty.exports() { - wat.export(&ty); - } - let module = Module::new(store.engine(), &wat.finish()).unwrap(); - Instance::new(store, &module, &[]) -} - -/// Construct a dummy module for the given module type. -/// -/// This is done by using the expected type to generate a module on-the-fly. -pub fn dummy_module(engine: &Engine, ty: ModuleType) -> Module { - let mut wat = WatGenerator::new(); - for ty in ty.imports() { - wat.import(&ty); - } - for ty in ty.exports() { - wat.export(&ty); - } - Module::new(engine, &wat.finish()).unwrap() -} - -struct WatGenerator { - tmp: usize, - dst: String, -} - -impl WatGenerator { - fn new() -> WatGenerator { - WatGenerator { - tmp: 0, - dst: String::from("(module\n"), - } - } - - fn finish(mut self) -> String { - self.dst.push_str(")\n"); - self.dst - } - - fn import(&mut self, ty: &ImportType<'_>) { - write!(self.dst, "(import ").unwrap(); - self.str(ty.module()); - write!(self.dst, " ").unwrap(); - if let Some(field) = ty.name() { - self.str(field); - write!(self.dst, " ").unwrap(); - } - self.item_ty(&ty.ty()); - writeln!(self.dst, ")").unwrap(); - } - - fn item_ty(&mut self, ty: &ExternType) { - match ty { - ExternType::Memory(mem) => { - write!( - self.dst, - "(memory {} {})", - mem.minimum(), - match mem.maximum() { - Some(max) => max.to_string(), - None => String::new(), - } - ) - .unwrap(); - } - ExternType::Table(table) => { - write!( - self.dst, - "(table {} {} {})", - table.minimum(), - match table.maximum() { - Some(max) => max.to_string(), - None => String::new(), - }, - wat_ty(&table.element()), - ) - .unwrap(); - } - ExternType::Global(ty) => { - if ty.mutability() == Mutability::Const { - write!(self.dst, "(global {})", wat_ty(ty.content())).unwrap(); - } else { - write!(self.dst, "(global (mut {}))", wat_ty(ty.content())).unwrap(); - } - } - ExternType::Func(ty) => { - write!(self.dst, "(func ").unwrap(); - self.func_sig(ty); - write!(self.dst, ")").unwrap(); - } - ExternType::Instance(ty) => { - writeln!(self.dst, "(instance").unwrap(); - for ty in ty.exports() { - write!(self.dst, "(export ").unwrap(); - self.str(ty.name()); - write!(self.dst, " ").unwrap(); - self.item_ty(&ty.ty()); - writeln!(self.dst, ")").unwrap(); - } - write!(self.dst, ")").unwrap(); - } - ExternType::Module(ty) => { - writeln!(self.dst, "(module").unwrap(); - for ty in ty.imports() { - self.import(&ty); - writeln!(self.dst, "").unwrap(); - } - for ty in ty.exports() { - write!(self.dst, "(export ").unwrap(); - self.str(ty.name()); - write!(self.dst, " ").unwrap(); - self.item_ty(&ty.ty()); - writeln!(self.dst, ")").unwrap(); - } - write!(self.dst, ")").unwrap(); - } - } - } - - fn export(&mut self, ty: &ExportType<'_>) { - let wat_name = format!("item{}", self.tmp); - self.tmp += 1; - let item_ty = ty.ty(); - self.item(&wat_name, &item_ty); - - write!(self.dst, "(export ").unwrap(); - self.str(ty.name()); - write!(self.dst, " (").unwrap(); - match item_ty { - ExternType::Memory(_) => write!(self.dst, "memory").unwrap(), - ExternType::Global(_) => write!(self.dst, "global").unwrap(), - ExternType::Func(_) => write!(self.dst, "func").unwrap(), - ExternType::Instance(_) => write!(self.dst, "instance").unwrap(), - ExternType::Table(_) => write!(self.dst, "table").unwrap(), - ExternType::Module(_) => write!(self.dst, "module").unwrap(), - } - writeln!(self.dst, " ${}))", wat_name).unwrap(); - } - - fn item(&mut self, name: &str, ty: &ExternType) { - match ty { - ExternType::Memory(mem) => { - write!( - self.dst, - "(memory ${} {} {})\n", - name, - mem.minimum(), - match mem.maximum() { - Some(max) => max.to_string(), - None => String::new(), - } - ) - .unwrap(); - } - ExternType::Table(table) => { - write!( - self.dst, - "(table ${} {} {} {})\n", - name, - table.minimum(), - match table.maximum() { - Some(max) => max.to_string(), - None => String::new(), - }, - wat_ty(&table.element()), - ) - .unwrap(); - } - ExternType::Global(ty) => { - write!(self.dst, "(global ${} ", name).unwrap(); - if ty.mutability() == Mutability::Var { - write!(self.dst, "(mut ").unwrap(); - } - write!(self.dst, "{}", wat_ty(ty.content())).unwrap(); - if ty.mutability() == Mutability::Var { - write!(self.dst, ")").unwrap(); - } - write!(self.dst, " (").unwrap(); - self.value(ty.content()); - writeln!(self.dst, "))").unwrap(); - } - ExternType::Func(ty) => { - write!(self.dst, "(func ${} ", name).unwrap(); - self.func_sig(ty); - for ty in ty.results() { - writeln!(self.dst, "").unwrap(); - self.value(&ty); - } - writeln!(self.dst, ")").unwrap(); - } - ExternType::Module(ty) => { - writeln!(self.dst, "(module ${}", name).unwrap(); - for ty in ty.imports() { - self.import(&ty); - } - for ty in ty.exports() { - self.export(&ty); - } - self.dst.push_str(")\n"); - } - ExternType::Instance(ty) => { - writeln!(self.dst, "(module ${}_module", name).unwrap(); - for ty in ty.exports() { - self.export(&ty); - } - self.dst.push_str(")\n"); - writeln!(self.dst, "(instance ${} (instantiate ${0}_module))", name).unwrap(); - } - } - } - - fn func_sig(&mut self, ty: &FuncType) { - write!(self.dst, "(param ").unwrap(); - for ty in ty.params() { - write!(self.dst, "{} ", wat_ty(&ty)).unwrap(); - } - write!(self.dst, ") (result ").unwrap(); - for ty in ty.results() { - write!(self.dst, "{} ", wat_ty(&ty)).unwrap(); - } - write!(self.dst, ")").unwrap(); - } - - fn value(&mut self, ty: &ValType) { - match ty { - ValType::I32 => write!(self.dst, "i32.const 0").unwrap(), - ValType::I64 => write!(self.dst, "i64.const 0").unwrap(), - ValType::F32 => write!(self.dst, "f32.const 0").unwrap(), - ValType::F64 => write!(self.dst, "f64.const 0").unwrap(), - ValType::V128 => write!(self.dst, "v128.const i32x4 0 0 0 0").unwrap(), - ValType::ExternRef => write!(self.dst, "ref.null extern").unwrap(), - ValType::FuncRef => write!(self.dst, "ref.null func").unwrap(), - } - } - - fn str(&mut self, name: &str) { - let mut bytes = [0; 4]; - self.dst.push_str("\""); - for c in name.chars() { - let v = c as u32; - if v >= 0x20 && v < 0x7f && c != '"' && c != '\\' && v < 0xff { - self.dst.push(c); - } else { - for byte in c.encode_utf8(&mut bytes).as_bytes() { - self.hex_byte(*byte); - } - } - } - self.dst.push_str("\""); - } - - fn hex_byte(&mut self, byte: u8) { - fn to_hex(b: u8) -> char { - if b < 10 { - (b'0' + b) as char - } else { - (b'a' + b - 10) as char - } - } - self.dst.push('\\'); - self.dst.push(to_hex((byte >> 4) & 0xf)); - self.dst.push(to_hex(byte & 0xf)); - } -} - -fn wat_ty(ty: &ValType) -> &'static str { - match ty { - ValType::I32 => "i32", - ValType::I64 => "i64", - ValType::F32 => "f32", - ValType::F64 => "f64", - ValType::V128 => "v128", - ValType::ExternRef => "externref", - ValType::FuncRef => "funcref", - } -} - #[cfg(test)] mod tests { use super::*; - use std::collections::HashSet; fn store() -> Store<()> { let mut config = Config::default(); - config.wasm_module_linking(true); config.wasm_multi_memory(true); let engine = wasmtime::Engine::new(&config).unwrap(); Store::new(&engine, ()) @@ -423,171 +121,4 @@ mod tests { let func = dummy_func(&mut store, func_ty.clone()); assert_eq!(func.ty(&store), func_ty); } - - #[test] - fn dummy_instance_import() { - let mut store = store(); - - let mut instance_ty = InstanceType::new(); - - // Functions. - instance_ty.add_named_export("func0", FuncType::new(vec![ValType::I32], vec![]).into()); - instance_ty.add_named_export("func1", FuncType::new(vec![], vec![ValType::I64]).into()); - - // Globals. - instance_ty.add_named_export( - "global0", - GlobalType::new(ValType::I32, Mutability::Const).into(), - ); - instance_ty.add_named_export( - "global1", - GlobalType::new(ValType::I64, Mutability::Var).into(), - ); - - // Tables. - instance_ty.add_named_export("table0", TableType::new(ValType::ExternRef, 1, None).into()); - instance_ty.add_named_export("table1", TableType::new(ValType::ExternRef, 1, None).into()); - - // Memories. - instance_ty.add_named_export("memory0", MemoryType::new(1, None).into()); - instance_ty.add_named_export("memory1", MemoryType::new(1, None).into()); - - // Modules. - instance_ty.add_named_export("module0", ModuleType::new().into()); - instance_ty.add_named_export("module1", ModuleType::new().into()); - - // Instances. - instance_ty.add_named_export("instance0", InstanceType::new().into()); - instance_ty.add_named_export("instance1", InstanceType::new().into()); - - let instance = dummy_instance(&mut store, instance_ty.clone()).unwrap(); - - let mut expected_exports = vec![ - "func0", - "func1", - "global0", - "global1", - "table0", - "table1", - "memory0", - "memory1", - "module0", - "module1", - "instance0", - "instance1", - ] - .into_iter() - .collect::>(); - for exp in instance.ty(&store).exports() { - let was_expected = expected_exports.remove(exp.name()); - assert!(was_expected); - } - assert!(expected_exports.is_empty()); - } - - #[test] - fn dummy_module_import() { - let store = store(); - - let mut module_ty = ModuleType::new(); - - // Multiple exported and imported functions. - module_ty.add_named_export("func0", FuncType::new(vec![ValType::I32], vec![]).into()); - module_ty.add_named_export("func1", FuncType::new(vec![], vec![ValType::I64]).into()); - module_ty.add_named_import( - "func2", - None, - FuncType::new(vec![ValType::I64], vec![]).into(), - ); - module_ty.add_named_import( - "func3", - None, - FuncType::new(vec![], vec![ValType::I32]).into(), - ); - - // Multiple exported and imported globals. - module_ty.add_named_export( - "global0", - GlobalType::new(ValType::I32, Mutability::Const).into(), - ); - module_ty.add_named_export( - "global1", - GlobalType::new(ValType::I64, Mutability::Var).into(), - ); - module_ty.add_named_import( - "global2", - None, - GlobalType::new(ValType::I32, Mutability::Var).into(), - ); - module_ty.add_named_import( - "global3", - None, - GlobalType::new(ValType::I64, Mutability::Const).into(), - ); - - // Multiple exported and imported tables. - module_ty.add_named_export("table0", TableType::new(ValType::ExternRef, 1, None).into()); - module_ty.add_named_export("table1", TableType::new(ValType::ExternRef, 1, None).into()); - module_ty.add_named_import( - "table2", - None, - TableType::new(ValType::ExternRef, 1, None).into(), - ); - module_ty.add_named_import( - "table3", - None, - TableType::new(ValType::ExternRef, 1, None).into(), - ); - - // Multiple exported and imported memories. - module_ty.add_named_export("memory0", MemoryType::new(1, None).into()); - module_ty.add_named_export("memory1", MemoryType::new(1, None).into()); - module_ty.add_named_import("memory2", None, MemoryType::new(1, None).into()); - module_ty.add_named_import("memory3", None, MemoryType::new(1, None).into()); - - // An exported and an imported module. - module_ty.add_named_export("module0", ModuleType::new().into()); - module_ty.add_named_import("module1", None, ModuleType::new().into()); - - // An exported and an imported instance. - module_ty.add_named_export("instance0", InstanceType::new().into()); - module_ty.add_named_import("instance1", None, InstanceType::new().into()); - - // Create the module. - let module = dummy_module(store.engine(), module_ty); - - // Check that we have the expected exports. - assert!(module.get_export("func0").is_some()); - assert!(module.get_export("func1").is_some()); - assert!(module.get_export("global0").is_some()); - assert!(module.get_export("global1").is_some()); - assert!(module.get_export("table0").is_some()); - assert!(module.get_export("table1").is_some()); - assert!(module.get_export("memory0").is_some()); - assert!(module.get_export("memory1").is_some()); - assert!(module.get_export("instance0").is_some()); - assert!(module.get_export("module0").is_some()); - - // Check that we have the exported imports. - let mut expected_imports = vec![ - "func2", - "func3", - "global2", - "global3", - "table2", - "table3", - "memory2", - "memory3", - "instance1", - "module1", - ] - .into_iter() - .collect::>(); - for imp in module.imports() { - assert!(imp.name().is_none()); - let was_expected = expected_imports.remove(imp.module()); - assert!(was_expected); - } - assert!(expected_imports.is_empty()); - } } diff --git a/crates/jit/src/instantiate.rs b/crates/jit/src/instantiate.rs index 76624260d378..83549bccb05a 100644 --- a/crates/jit/src/instantiate.rs +++ b/crates/jit/src/instantiate.rs @@ -16,9 +16,8 @@ use std::str; use std::sync::Arc; use thiserror::Error; use wasmtime_environ::{ - CompileError, DefinedFuncIndex, FuncIndex, FunctionInfo, InstanceSignature, InstanceTypeIndex, - Module, ModuleSignature, ModuleTranslation, ModuleTypeIndex, PrimaryMap, SignatureIndex, - StackMapInformation, Trampoline, Tunables, WasmFuncType, ELF_WASMTIME_ADDRMAP, + CompileError, DefinedFuncIndex, FuncIndex, FunctionInfo, Module, ModuleTranslation, PrimaryMap, + SignatureIndex, StackMapInformation, Trampoline, Tunables, WasmFuncType, ELF_WASMTIME_ADDRMAP, ELF_WASMTIME_TRAPS, }; use wasmtime_runtime::{ @@ -365,8 +364,6 @@ pub fn mmap_vec_from_obj(obj: Object) -> Result { #[allow(missing_docs)] pub struct TypeTables { pub wasm_signatures: PrimaryMap, - pub module_signatures: PrimaryMap, - pub instance_signatures: PrimaryMap, } /// A compiled wasm module, ready to be instantiated. diff --git a/crates/runtime/src/instance.rs b/crates/runtime/src/instance.rs index edc7cce4553b..22be3f0ca0b1 100644 --- a/crates/runtime/src/instance.rs +++ b/crates/runtime/src/instance.rs @@ -336,10 +336,6 @@ impl Instance { global: self.module().globals[*index], } .into(), - - EntityIndex::Instance(_) | EntityIndex::Module(_) => { - panic!("can't use this api for modules/instances") - } } } diff --git a/crates/types/src/lib.rs b/crates/types/src/lib.rs index 7db21a2a010b..eb058f3fd34b 100644 --- a/crates/types/src/lib.rs +++ b/crates/types/src/lib.rs @@ -213,31 +213,11 @@ entity_impl!(ElemIndex); pub struct TypeIndex(u32); entity_impl!(TypeIndex); -/// Index type of a module inside the WebAssembly module. -#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)] -pub struct ModuleIndex(u32); -entity_impl!(ModuleIndex); - -/// Index type of an instance inside the WebAssembly module. -#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)] -pub struct InstanceIndex(u32); -entity_impl!(InstanceIndex); - /// Index type of an event inside the WebAssembly module. #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)] pub struct TagIndex(u32); entity_impl!(TagIndex); -/// Specialized index for just module types. -#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)] -pub struct ModuleTypeIndex(u32); -entity_impl!(ModuleTypeIndex); - -/// Specialized index for just instance types. -#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)] -pub struct InstanceTypeIndex(u32); -entity_impl!(InstanceTypeIndex); - /// An index of an entity. #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)] pub enum EntityIndex { @@ -249,10 +229,6 @@ pub enum EntityIndex { Memory(MemoryIndex), /// Global index. Global(GlobalIndex), - /// Module index. - Module(ModuleIndex), - /// Instance index. - Instance(InstanceIndex), } /// A type of an item in a wasm module where an item is typically something that @@ -271,12 +247,6 @@ pub enum EntityType { /// A function type where the index points to the type section and records a /// function signature. Function(SignatureIndex), - /// An instance where the index points to the type section and records a - /// instance's exports. - Instance(InstanceTypeIndex), - /// A module where the index points to the type section and records a - /// module's imports and exports. - Module(ModuleTypeIndex), } /// A WebAssembly global. diff --git a/crates/wasmtime/src/config.rs b/crates/wasmtime/src/config.rs index 646a795497a4..b16cc7019c1a 100644 --- a/crates/wasmtime/src/config.rs +++ b/crates/wasmtime/src/config.rs @@ -602,20 +602,6 @@ impl Config { self } - /// Configures whether the WebAssembly module linking [proposal] will - /// be enabled for compilation. - /// - /// Note that development of this feature is still underway, so enabling - /// this is likely to be full of bugs. - /// - /// This is `false` by default. - /// - /// [proposal]: https://github.com/webassembly/module-linking - pub fn wasm_module_linking(&mut self, enable: bool) -> &mut Self { - self.features.module_linking = enable; - self - } - /// Configures whether the WebAssembly memory64 [proposal] will /// be enabled for compilation. /// @@ -1374,7 +1360,6 @@ impl fmt::Debug for Config { .field("wasm_bulk_memory", &self.features.bulk_memory) .field("wasm_simd", &self.features.simd) .field("wasm_multi_value", &self.features.multi_value) - .field("wasm_module_linking", &self.features.module_linking) .field( "static_memory_maximum_size", &(u64::from(self.tunables.static_memory_bound) diff --git a/crates/wasmtime/src/engine.rs b/crates/wasmtime/src/engine.rs index 1c6d858384ce..083905e53323 100644 --- a/crates/wasmtime/src/engine.rs +++ b/crates/wasmtime/src/engine.rs @@ -193,9 +193,8 @@ impl Engine { pub fn precompile_module(&self, bytes: &[u8]) -> Result> { #[cfg(feature = "wat")] let bytes = wat::parse_bytes(&bytes)?; - let (_, artifacts, types) = crate::Module::build_artifacts(self, &bytes)?; - let artifacts = artifacts.into_iter().map(|i| i.0).collect::>(); - crate::module::SerializedModule::from_artifacts(self, &artifacts, &types) + let (mmap, _, types) = crate::Module::build_artifacts(self, &bytes)?; + crate::module::SerializedModule::from_artifacts(self, &mmap, &types) .to_bytes(&self.config().module_version) } diff --git a/crates/wasmtime/src/externals.rs b/crates/wasmtime/src/externals.rs index 71b03bf057d1..e65c66469363 100644 --- a/crates/wasmtime/src/externals.rs +++ b/crates/wasmtime/src/externals.rs @@ -1,8 +1,8 @@ use crate::store::{StoreData, StoreOpaque, Stored}; use crate::trampoline::{generate_global_export, generate_table_export}; use crate::{ - AsContext, AsContextMut, ExternRef, ExternType, Func, GlobalType, Instance, Memory, Module, - Mutability, TableType, Trap, Val, ValType, + AsContext, AsContextMut, ExternRef, ExternType, Func, GlobalType, Memory, Mutability, + TableType, Trap, Val, ValType, }; use anyhow::{anyhow, bail, Result}; use std::mem; @@ -29,10 +29,6 @@ pub enum Extern { Table(Table), /// A WebAssembly linear memory. Memory(Memory), - /// A WebAssembly instance. - Instance(Instance), - /// A WebAssembly module. - Module(Module), } impl Extern { @@ -76,26 +72,6 @@ impl Extern { } } - /// Returns the underlying `Instance`, if this external is a instance. - /// - /// Returns `None` if this is not a instance. - pub fn into_instance(self) -> Option { - match self { - Extern::Instance(instance) => Some(instance), - _ => None, - } - } - - /// Returns the underlying `Module`, if this external is a module. - /// - /// Returns `None` if this is not a module. - pub fn into_module(self) -> Option { - match self { - Extern::Module(module) => Some(module), - _ => None, - } - } - /// Returns the type associated with this `Extern`. /// /// The `store` argument provided must own this `Extern` and is used to look @@ -111,8 +87,6 @@ impl Extern { Extern::Memory(ft) => ExternType::Memory(ft.ty(store)), Extern::Table(tt) => ExternType::Table(tt.ty(store)), Extern::Global(gt) => ExternType::Global(gt.ty(store)), - Extern::Instance(i) => ExternType::Instance(i.ty(store)), - Extern::Module(m) => ExternType::Module(m.ty()), } } @@ -142,10 +116,6 @@ impl Extern { Extern::Global(g) => store.store_data().contains(g.0), Extern::Memory(m) => m.comes_from_same_store(store), Extern::Table(t) => store.store_data().contains(t.0), - Extern::Instance(i) => i.comes_from_same_store(store), - // Modules don't live in stores right now, so they're compatible - // with all stores. - Extern::Module(_) => true, } } @@ -155,8 +125,6 @@ impl Extern { Extern::Table(_) => "table", Extern::Memory(_) => "memory", Extern::Global(_) => "global", - Extern::Instance(_) => "instance", - Extern::Module(_) => "module", } } } @@ -185,18 +153,6 @@ impl From for Extern { } } -impl From for Extern { - fn from(r: Instance) -> Self { - Extern::Instance(r) - } -} - -impl From for Extern { - fn from(r: Module) -> Self { - Extern::Module(r) - } -} - /// A WebAssembly `global` value which can be read and written to. /// /// A `global` in WebAssembly is sort of like a global variable within an @@ -205,9 +161,10 @@ impl From for Extern { /// can either be imported or exported from wasm modules. /// /// A [`Global`] "belongs" to the store that it was originally created within -/// (either via [`Global::new`] or via instantiating a [`Module`]). Operations -/// on a [`Global`] only work with the store it belongs to, and if another store -/// is passed in by accident then methods will panic. +/// (either via [`Global::new`] or via instantiating a +/// [`Module`](crate::Module)). Operations on a [`Global`] only work with the +/// store it belongs to, and if another store is passed in by accident then +/// methods will panic. #[derive(Copy, Clone, Debug)] #[repr(transparent)] // here for the C API pub struct Global(Stored); @@ -385,9 +342,10 @@ impl Global { /// `funcref` table), where each element has the `ValType::FuncRef` type. /// /// A [`Table`] "belongs" to the store that it was originally created within -/// (either via [`Table::new`] or via instantiating a [`Module`]). Operations -/// on a [`Table`] only work with the store it belongs to, and if another store -/// is passed in by accident then methods will panic. +/// (either via [`Table::new`] or via instantiating a +/// [`Module`](crate::Module)). Operations on a [`Table`] only work with the +/// store it belongs to, and if another store is passed in by accident then +/// methods will panic. #[derive(Copy, Clone, Debug)] #[repr(transparent)] // here for the C API pub struct Table(Stored); @@ -787,16 +745,4 @@ impl<'instance> Export<'instance> { pub fn into_global(self) -> Option { self.definition.into_global() } - - /// Consume this `Export` and return the contained `Instance`, if it's a - /// instance, or `None` otherwise. - pub fn into_instance(self) -> Option { - self.definition.into_instance() - } - - /// Consume this `Export` and return the contained `Module`, if it's a - /// module, or `None` otherwise. - pub fn into_module(self) -> Option { - self.definition.into_module() - } } diff --git a/crates/wasmtime/src/instance.rs b/crates/wasmtime/src/instance.rs index 613d88f5fc34..dbde69252dbf 100644 --- a/crates/wasmtime/src/instance.rs +++ b/crates/wasmtime/src/instance.rs @@ -1,19 +1,16 @@ use crate::linker::Definition; -use crate::signatures::SignatureCollection; -use crate::store::{InstanceId, StoreData, StoreOpaque, Stored}; +use crate::store::{InstanceId, StoreOpaque, Stored}; use crate::types::matching; use crate::{ - AsContext, AsContextMut, Engine, Export, Extern, ExternType, Func, Global, InstanceType, - Memory, Module, StoreContextMut, Table, Trap, TypedFunc, + AsContextMut, Engine, Export, Extern, Func, Global, Memory, Module, StoreContextMut, Table, + Trap, TypedFunc, }; use anyhow::{anyhow, bail, Context, Error, Result}; use std::mem; use std::sync::Arc; use wasmtime_environ::{ - EntityIndex, EntityType, FuncIndex, GlobalIndex, Initializer, InstanceIndex, MemoryIndex, - ModuleIndex, PrimaryMap, TableIndex, + EntityIndex, EntityType, FuncIndex, GlobalIndex, MemoryIndex, PrimaryMap, TableIndex, }; -use wasmtime_jit::TypeTables; use wasmtime_runtime::{ Imports, InstanceAllocationRequest, InstantiationError, StorePtr, VMContext, VMFunctionBody, VMFunctionImport, VMGlobalImport, VMMemoryImport, VMTableImport, @@ -36,25 +33,14 @@ use wasmtime_runtime::{ #[repr(transparent)] pub struct Instance(Stored); -pub(crate) enum InstanceData { - /// This variant is used for instances created through instantiation of a - /// module, e.g. `Instance::new` or various linker methods. - Instantiated { - /// The id of the instance within the store, used to find the original - /// `InstanceHandle`. - id: InstanceId, - /// A lazily-populated list of exports of this instance. The order of - /// exports here matches the order of the exports in the the original - /// module. - exports: Vec>, - /// The type information of the module that this was instantiated with. - types: Arc, - signatures: Arc, - }, - - /// This variant is used for synthetically created instances via `Linker` - /// APIs. This is only used for the module linking proposal at this time. - Synthetic(Arc>), +pub(crate) struct InstanceData { + /// The id of the instance within the store, used to find the original + /// `InstanceHandle`. + id: InstanceId, + /// A lazily-populated list of exports of this instance. The order of + /// exports here matches the order of the exports in the the original + /// module. + exports: Vec>, } impl Instance { @@ -181,39 +167,6 @@ impl Instance { Instance(store.store_data_mut().insert(handle)) } - /// Returns the type signature of this instance. - /// - /// # Panics - /// - /// Panics if `store` does not own this instance. - pub fn ty(&self, store: impl AsContext) -> InstanceType { - let store = store.as_context(); - let mut ty = InstanceType::new(); - match &store[self.0] { - InstanceData::Synthetic(items) => { - for (name, item) in items.iter() { - ty.add_named_export(name, item.ty(&store)); - } - } - InstanceData::Instantiated { id, types, .. } => { - let module = store.0.instance(*id).module(); - for (name, idx) in module.exports.iter() { - let export_ty = module.type_of(*idx); - ty.add_named_export(name, ExternType::from_wasmtime(types, &export_ty)); - } - } - } - ty - } - - pub(crate) fn data<'a>(&self, store: &'a StoreData) -> &'a InstanceData { - &store[self.0] - } - - pub(crate) fn comes_from_same_store(&self, store: &StoreOpaque) -> bool { - store.store_data().contains(self.0) - } - /// Returns the list of exported items from this [`Instance`]. /// /// # Panics @@ -232,70 +185,21 @@ impl Instance { ) -> impl ExactSizeIterator> + 'a { // If this is an `Instantiated` instance then all the `exports` may not // be filled in. Fill them all in now if that's the case. - if let InstanceData::Instantiated { exports, id, .. } = &store[self.0] { - if exports.iter().any(|e| e.is_none()) { - let module = Arc::clone(store.instance(*id).module()); - for name in module.exports.keys() { - self._get_export(store, name); - } - } - } - - return match &store.store_data()[self.0] { - InstanceData::Synthetic(names) => { - Either::A(names.iter().map(|(k, v)| Export::new(k, v.clone()))) - } - InstanceData::Instantiated { exports, id, .. } => { - let module = store.instance(*id).module(); - Either::B( - module - .exports - .iter() - .zip(exports) - .map(|((name, _), export)| Export::new(name, export.clone().unwrap())), - ) - } - }; - - enum Either { - A(A), - B(B), - } - - impl Iterator for Either - where - A: Iterator, - B: Iterator, - { - type Item = A::Item; - - fn next(&mut self) -> Option { - match self { - Either::A(a) => a.next(), - Either::B(b) => b.next(), - } - } - - fn size_hint(&self) -> (usize, Option) { - match self { - Either::A(a) => a.size_hint(), - Either::B(b) => b.size_hint(), - } + let InstanceData { exports, id, .. } = &store[self.0]; + if exports.iter().any(|e| e.is_none()) { + let module = Arc::clone(store.instance(*id).module()); + for name in module.exports.keys() { + self._get_export(store, name); } } - impl ExactSizeIterator for Either - where - A: ExactSizeIterator, - B: ExactSizeIterator, - { - fn len(&self) -> usize { - match self { - Either::A(a) => a.len(), - Either::B(b) => b.len(), - } - } - } + let data = &store.store_data()[self.0]; + let module = store.instance(data.id).module(); + module + .exports + .iter() + .zip(&data.exports) + .map(|((name, _), export)| Export::new(name, export.clone().unwrap())) } /// Looks up an exported [`Extern`] value by name. @@ -320,33 +224,23 @@ impl Instance { } fn _get_export(&self, store: &mut StoreOpaque, name: &str) -> Option { - match &store[self.0] { - // Synthetic instances always have their entire list of exports - // already specified. - InstanceData::Synthetic(names) => names.get(name).cloned(), - - // Instantiated instances will lazily fill in exports, so we process - // all that lazy logic here. - InstanceData::Instantiated { id, exports, .. } => { - let id = *id; - let instance = store.instance(id); - let (i, _, &index) = instance.module().exports.get_full(name)?; - if let Some(export) = &exports[i] { - return Some(export.clone()); - } - - let instance = store.instance_mut(id); // reborrow the &mut Instancehandle - let item = unsafe { - Extern::from_wasmtime_export(instance.lookup_by_declaration(&index), store) - }; - let exports = match &mut store[self.0] { - InstanceData::Instantiated { exports, .. } => exports, - _ => unreachable!(), - }; - exports[i] = Some(item.clone()); - Some(item) - } + // Instantiated instances will lazily fill in exports, so we process + // all that lazy logic here. + let data = &store[self.0]; + + let instance = store.instance(data.id); + let (i, _, &index) = instance.module().exports.get_full(name)?; + if let Some(export) = &data.exports[i] { + return Some(export.clone()); } + + let id = data.id; + let instance = store.instance_mut(id); // reborrow the &mut Instancehandle + let item = + unsafe { Extern::from_wasmtime_export(instance.lookup_by_declaration(&index), store) }; + let data = &mut store[self.0]; + data.exports[i] = Some(item.clone()); + Some(item) } /// Looks up an exported [`Func`] value by name. @@ -428,26 +322,17 @@ impl Instance { } struct Instantiator<'a> { - in_progress: Vec>, - cur: ImportsBuilder<'a>, -} - -struct ImportsBuilder<'a> { - src: ImportSource<'a>, + imports: ImportSource<'a>, functions: PrimaryMap, tables: PrimaryMap, memories: PrimaryMap, globals: PrimaryMap, - instances: PrimaryMap, - modules: PrimaryMap, - initializer: usize, - module: Module, + module: &'a Module, } enum ImportSource<'a> { Externs(&'a [Extern]), Definitions(&'a [Definition]), - Outer { initializer: usize }, } impl<'a> Instantiator<'a> { @@ -473,225 +358,77 @@ impl<'a> Instantiator<'a> { /// * The `imports` must all come from the `store` specified. unsafe fn new( store: &StoreOpaque, - module: &Module, + module: &'a Module, imports: ImportSource<'a>, ) -> Result> { if !Engine::same(store.engine(), module.engine()) { bail!("cross-`Engine` instantiation is not currently supported"); } + let raw = module.compiled_module().module(); Ok(Instantiator { - in_progress: Vec::new(), - cur: ImportsBuilder::new(module, imports), + imports, + functions: PrimaryMap::with_capacity(raw.num_imported_funcs), + tables: PrimaryMap::with_capacity(raw.num_imported_tables), + memories: PrimaryMap::with_capacity(raw.num_imported_memories), + globals: PrimaryMap::with_capacity(raw.num_imported_globals), + module, }) } fn run(&mut self, store: &mut StoreContextMut<'_, T>) -> Result { - loop { - if let Some((instance, start, toplevel)) = self.step(store.0)? { - if let Some(start) = start { - Instantiator::start_raw(store, instance, start)?; - } - if toplevel { - break Ok(instance); - } - } + let (instance, start) = self.resolve_imports(store.0)?; + if let Some(start) = start { + Instantiator::start_raw(store, instance, start)?; } + Ok(instance) } - /// Processes the next initializer for the next instance being created - /// without running any wasm code. - /// - /// This function will process module initializers, handling recursive - /// instantiations of modules for module linking if necessary as well. This - /// does not actually execute any WebAssembly code, which means that it - /// will return whenever an instance is created (because its `start` - /// function may need to be executed). - /// - /// If this function returns `None`, then it simply needs to be called - /// again to execute the next initializer. Otherwise this function has two - /// return values: - /// - /// * The first is the raw handle to the instance that was just created. - /// This instance must have its start function executed by the caller. - /// * The second is an optional list of items to get wrapped up in an - /// `Instance`. This is only `Some` for the outermost instance that was - /// created. If this is `None` callers need to keep calling this function - /// since the instance created was simply for a recursive instance - /// defined here. - fn step( + /// Resolve all the imports for the module being instantiated, extracting + /// the raw representations and building up the `PrimaryMap` instance for + /// each set of exports. + fn resolve_imports( &mut self, store: &mut StoreOpaque, - ) -> Result, bool)>> { - if self.cur.initializer == 0 { - store.bump_resource_counts(&self.cur.module)?; - } + ) -> Result<(Instance, Option)> { + store.bump_resource_counts(&self.module)?; // Read the current module's initializer and move forward the // initializer pointer as well. - self.cur.initializer += 1; - match self - .cur - .module - .env_module() - .initializers - .get(self.cur.initializer - 1) - { - Some(Initializer::Import { name, field, .. }) => { - match &mut self.cur.src { - // If imports are coming from the runtime-provided list - // (e.g. the root module being instantiated) then we - // need to typecheck each item here before recording it. - // - // Note the `unwrap` here should be ok given the validation - // above in `Instantiation::new`. - ImportSource::Externs(list) => { - let (head, remaining) = list.split_first().unwrap(); - *list = remaining; - self.cur.push(head.clone(), store); - } - ImportSource::Definitions(list) => { - let (head, remaining) = list.split_first().unwrap(); - *list = remaining; - // This unsafety is encapsulated with - // `Instantiator::new`, documented above. - self.cur.push(unsafe { head.to_extern(store) }, store); - } - - // Otherwise if arguments are coming from our outer - // instance due to a recursive instantiation then we - // look in the previous initializer's mapping of - // arguments to figure out where to load the item from. - // Note that no typechecking is necessary here due to - // validation. - ImportSource::Outer { initializer } => { - debug_assert!(field.is_none()); - let outer = self.in_progress.last().unwrap(); - let args = match &outer.module.env_module().initializers[*initializer] { - Initializer::Instantiate { args, .. } => args, - _ => unreachable!(), - }; - let index = args.get(name).expect("should be present after validation"); - match *index { - EntityIndex::Global(i) => { - self.cur.globals.push(outer.globals[i]); - } - EntityIndex::Function(i) => { - self.cur.functions.push(outer.functions[i]); - } - EntityIndex::Table(i) => { - self.cur.tables.push(outer.tables[i]); - } - EntityIndex::Memory(i) => { - self.cur.memories.push(outer.memories[i]); - } - EntityIndex::Module(i) => { - self.cur.modules.push(outer.modules[i].clone()); - } - EntityIndex::Instance(i) => { - self.cur.instances.push(outer.instances[i].clone()); - } - } - } + let num_imports = self.module.env_module().initializers.len(); + match &self.imports { + ImportSource::Externs(list) => { + assert_eq!(list.len(), num_imports); + for item in list.iter() { + self.push(item.clone(), store); } } - - // Here we lookup our instance handle, find the right export, - // and then push that item into our own index space. We eschew - // type-checking since only valid modules should reach this point. - Some(Initializer::AliasInstanceExport { instance, export }) => { - let instance = self.cur.instances[*instance]; - let export = instance._get_export(store, export).unwrap(); - self.cur.push(export, store); - } - - // A recursive instantiation of an instance. - // - // The `module` argument is used to create an import builder - // object, and we specify that the source of imports for the builder is - // this initializer's position so we can look at the `args` payload - // later. - // - // Once that's set up we save off `self.cur` into - // `self.in_progress` and start the instantiation of the child - // instance on the next execution of this function. - Some(Initializer::Instantiate { module, args: _ }) => { - let module = &self.cur.modules[*module]; - let imports = ImportsBuilder::new( - module, - ImportSource::Outer { - initializer: self.cur.initializer - 1, - }, - ); - let prev = mem::replace(&mut self.cur, imports); - self.in_progress.push(prev); - } - - // A new module is being defined, and the source of this module is - // our module's list of closed-over-modules. - // - // This is used for outer aliases. - Some(Initializer::DefineModule(upvar_index)) => { - self.cur - .modules - .push(self.cur.module.module_upvar(*upvar_index).clone()); - } - - // A new module is defined, created from a set of compiled - // artifacts. The new module value will be created with the - // specified artifacts being closed over as well as the specified - // set of module values in our index/upvar index spaces being closed - // over. - // - // This is used for defining submodules. - Some(Initializer::CreateModule { - artifact_index, - artifacts, - modules, - }) => { - let submodule = self.cur.module.create_submodule( - *artifact_index, - artifacts, - modules, - &self.cur.modules, - )?; - self.cur.modules.push(submodule); - } - - // All initializers have been processed, which means we're ready to - // perform the actual raw instantiation with the raw import values. - // Once that's done if there's an in-progress module we record the - // instance in the index space. Otherwise this is the final module - // and we return the items out. - // - // Note that in all cases we return the raw instance handle to get - // the start function executed by the outer context. - None => { - let (instance, start) = self.instantiate_raw(store)?; - let toplevel = match self.in_progress.pop() { - Some(imports) => { - self.cur = imports; - self.cur.instances.push(instance); - false - } - None => true, - }; - return Ok(Some((instance, start, toplevel))); + ImportSource::Definitions(list) => { + assert_eq!(list.len(), num_imports); + for item in list.iter() { + // This unsafety is encapsulated with + // `Instantiator::new`, documented above. + self.push(unsafe { item.to_extern(store) }, store); + } } } - Ok(None) + // All initializers have been processed, which means we're ready to + // perform the actual raw instantiation with the raw import values. This + // will register everything except the start function's completion and + // the finished instance will be returned. + self.instantiate_raw(store) } fn instantiate_raw( &mut self, store: &mut StoreOpaque, ) -> Result<(Instance, Option)> { - let compiled_module = self.cur.module.compiled_module(); + let compiled_module = self.module.compiled_module(); // Register the module just before instantiation to ensure we keep the module // properly referenced while in use by the store. - store.modules_mut().register(&self.cur.module); + store.modules_mut().register(&self.module); unsafe { // The first thing we do is issue an instance allocation request @@ -710,8 +447,8 @@ impl<'a> Instantiator<'a> { .engine() .allocator() .allocate(InstanceAllocationRequest { - runtime_info: &self.cur.module.runtime_info(), - imports: self.cur.build(), + runtime_info: &self.module.runtime_info(), + imports: self.build(), host_state: Box::new(Instance(instance_to_be)), store: StorePtr::new(store.traitobj()), })?; @@ -747,28 +484,9 @@ impl<'a> Instantiator<'a> { .module() .exports .values() - .map(|index| { - // Note that instances and modules are not handled by - // `wasmtime_runtime`, they're handled by us in this crate. That - // means we need to handle that here, otherwise we defer to the - // instance to load the values. - match *index { - EntityIndex::Instance(i) => { - Some(Extern::Instance(self.cur.instances[i].clone())) - } - EntityIndex::Module(i) => { - Some(Extern::Module(self.cur.modules[i].clone())) - } - _ => None, - } - }) + .map(|_index| None) .collect(); - let data = InstanceData::Instantiated { - id, - exports, - types: Arc::clone(self.cur.module.types()), - signatures: Arc::clone(self.cur.module.signatures()), - }; + let data = InstanceData { id, exports }; Instance::from_wasmtime(data, store) }; @@ -810,10 +528,7 @@ impl<'a> Instantiator<'a> { instance: Instance, start: FuncIndex, ) -> Result<()> { - let id = match &store.0.store_data()[instance.0] { - InstanceData::Instantiated { id, .. } => *id, - InstanceData::Synthetic(_) => return Ok(()), - }; + let id = store.0.store_data()[instance.0].id; // If a start function is present, invoke it. Make sure we use all the // trap-handling configuration in `store` as well. let instance = store.0.instance_mut(id); @@ -834,23 +549,6 @@ impl<'a> Instantiator<'a> { } Ok(()) } -} - -impl<'a> ImportsBuilder<'a> { - fn new(module: &Module, src: ImportSource<'a>) -> ImportsBuilder<'a> { - let raw = module.compiled_module().module(); - ImportsBuilder { - src, - functions: PrimaryMap::with_capacity(raw.num_imported_funcs), - tables: PrimaryMap::with_capacity(raw.num_imported_tables), - memories: PrimaryMap::with_capacity(raw.num_imported_memories), - globals: PrimaryMap::with_capacity(raw.num_imported_globals), - instances: PrimaryMap::with_capacity(raw.instances.len()), - modules: PrimaryMap::with_capacity(raw.modules.len()), - module: module.clone(), - initializer: 0, - } - } fn push(&mut self, item: Extern, store: &mut StoreOpaque) { match item { @@ -866,12 +564,6 @@ impl<'a> ImportsBuilder<'a> { Extern::Memory(i) => { self.memories.push(i.vmimport(store)); } - Extern::Instance(i) => { - self.instances.push(i); - } - Extern::Module(m) => { - self.modules.push(m); - } } } @@ -1067,13 +759,8 @@ fn typecheck( engine: store.engine(), }; for ((name, field, expected_ty), actual) in env_module.imports().zip(imports) { - check(&cx, &expected_ty, actual).with_context(|| { - let extra = match field { - Some(name) => format!("::{}", name), - None => String::new(), - }; - format!("incompatible import type for `{}{}`", name, extra) - })?; + check(&cx, &expected_ty, actual) + .with_context(|| format!("incompatible import type for `{name}::{field}`"))?; } Ok(()) } diff --git a/crates/wasmtime/src/linker.rs b/crates/wasmtime/src/linker.rs index d4df9d73321b..8f298f83b57e 100644 --- a/crates/wasmtime/src/linker.rs +++ b/crates/wasmtime/src/linker.rs @@ -1,9 +1,9 @@ use crate::func::HostFunc; -use crate::instance::{InstanceData, InstancePre}; +use crate::instance::InstancePre; use crate::store::StoreOpaque; use crate::{ - AsContextMut, Caller, Engine, Extern, ExternType, Func, FuncType, ImportType, Instance, - IntoFunc, Module, StoreContextMut, Trap, Val, ValRaw, + AsContextMut, Caller, Engine, Extern, Func, FuncType, ImportType, Instance, IntoFunc, Module, + StoreContextMut, Trap, Val, ValRaw, }; use anyhow::{anyhow, bail, Context, Result}; use log::warn; @@ -115,7 +115,6 @@ struct ImportKey { pub(crate) enum Definition { Extern(Extern), HostFunc(Arc), - Instance(Arc>), } macro_rules! generate_wrap_async_func { @@ -622,7 +621,7 @@ impl Linker { /// "#; /// let module = Module::new(&engine, wat)?; /// linker.module(&mut store, "", &module)?; - /// let run = linker.get(&mut store, "", Some("run")).unwrap().into_func().unwrap(); + /// let run = linker.get(&mut store, "", "run").unwrap().into_func().unwrap(); /// let count = run.typed::<(), i32, _>(&store)?.call(&mut store, ())?; /// assert_eq!(count, 0, "a Command should get a fresh instance on each invocation"); /// @@ -1093,20 +1092,17 @@ impl Linker { &self, mut store: impl AsContextMut, module: &str, - name: Option<&str>, + name: &str, ) -> Option { let store = store.as_context_mut().0; // Should be safe since `T` is connecting the linker and store Some(unsafe { self._get(module, name)?.to_extern(store) }) } - fn _get(&self, module: &str, name: Option<&str>) -> Option<&Definition> { + fn _get(&self, module: &str, name: &str) -> Option<&Definition> { let key = ImportKey { module: *self.string2idx.get(module)?, - name: match name { - Some(name) => *self.string2idx.get(name)?, - None => usize::max_value(), - }, + name: *self.string2idx.get(name)?, }; self.map.get(&key) } @@ -1139,37 +1135,11 @@ impl Linker { return Ok(item.clone()); } - if let Some(name) = import.name() { - return Err(undef_err(&format!("{}::{}", import.module(), name))); - } - - if let ExternType::Instance(t) = import.ty() { - // This is a key location where the module linking proposal is - // implemented. This logic allows single-level imports of an instance to - // get satisfied by multiple definitions of items within this `Linker`. - // - // The instance being import is iterated over to load the names from - // this `Linker` (recursively calling `get`). If anything isn't defined - // we return `None` since the entire value isn't defined. Otherwise when - // all values are loaded it's assembled into an `Instance` and - // returned`. - // - // Note that this isn't exactly the speediest implementation in the - // world. Ideally we would pre-create the `Instance` instead of creating - // it each time a module is instantiated. For now though while the - // module linking proposal is under development this should hopefully - // suffice. - let mut map = indexmap::IndexMap::new(); - for export in t.exports() { - let item = self - ._get(import.module(), Some(export.name())) - .ok_or_else(|| undef_err(&format!("{}::{}", import.module(), export.name())))?; - map.insert(export.name().to_string(), item.clone()); - } - return Ok(Definition::Instance(Arc::new(map))); - } - - Err(undef_err(&import.module())) + Err(undef_err(&format!( + "{}::{}", + import.module(), + import.name() + ))) } /// Returns the "default export" of a module. @@ -1187,7 +1157,7 @@ impl Linker { mut store: impl AsContextMut, module: &str, ) -> Result { - if let Some(external) = self.get(&mut store, module, Some("")) { + if let Some(external) = self.get(&mut store, module, "") { if let Extern::Func(func) = external { return Ok(func.clone()); } @@ -1195,7 +1165,7 @@ impl Linker { } // For compatibility, also recognize "_start". - if let Some(external) = self.get(&mut store, module, Some("_start")) { + if let Some(external) = self.get(&mut store, module, "_start") { if let Extern::Func(func) = external { return Ok(func.clone()); } @@ -1221,14 +1191,6 @@ impl Definition { match self { Definition::Extern(e) => e.clone(), Definition::HostFunc(func) => func.to_func(store).into(), - Definition::Instance(i) => { - let items = Arc::new( - i.iter() - .map(|(name, item)| (name.clone(), item.to_extern(store))) - .collect(), - ); - Instance::from_wasmtime(InstanceData::Synthetic(items), store).into() - } } } @@ -1236,7 +1198,6 @@ impl Definition { match self { Definition::Extern(e) => e.comes_from_same_store(store), Definition::HostFunc(_func) => true, - Definition::Instance(i) => i.values().all(|e| e.comes_from_same_store(store)), } } } diff --git a/crates/wasmtime/src/module.rs b/crates/wasmtime/src/module.rs index d5da545b2501..f17eaf274acb 100644 --- a/crates/wasmtime/src/module.rs +++ b/crates/wasmtime/src/module.rs @@ -1,8 +1,8 @@ +use crate::Engine; use crate::{ signatures::SignatureCollection, types::{ExportType, ExternType, ImportType}, }; -use crate::{Engine, ModuleType}; use anyhow::{bail, Context, Result}; use once_cell::sync::OnceCell; use std::fs; @@ -12,7 +12,7 @@ use std::path::Path; use std::sync::Arc; use wasmparser::{Parser, ValidPayload, Validator}; use wasmtime_environ::{ - DefinedFuncIndex, DefinedMemoryIndex, FunctionInfo, ModuleEnvironment, ModuleIndex, PrimaryMap, + DefinedFuncIndex, DefinedMemoryIndex, FunctionInfo, ModuleEnvironment, PrimaryMap, SignatureIndex, }; use wasmtime_jit::{CompiledModule, CompiledModuleInfo, TypeTables}; @@ -104,14 +104,7 @@ struct ModuleInner { /// The compiled artifacts for this module that will be instantiated and /// executed. module: Arc, - /// Closed-over compilation artifacts used to create submodules when this - /// module is instantiated. - artifact_upvars: Vec>, - /// Closed-over module values which are used when this module is - /// instantiated. - module_upvars: Vec, - /// Type information of this module and all `artifact_upvars` compiled - /// modules. + /// Type information of this module. types: Arc, /// Registered shared signature for the module. signatures: Arc, @@ -307,7 +300,7 @@ impl Module { cfg_if::cfg_if! { if #[cfg(feature = "cache")] { let state = (HashedEngineCompileEnv(engine), binary); - let (main_module, artifacts, types) = wasmtime_cache::ModuleCacheEntry::new( + let (mmap, info, types) = wasmtime_cache::ModuleCacheEntry::new( "wasmtime", engine.cache_config(), ) @@ -318,40 +311,35 @@ impl Module { |(engine, wasm)| Module::build_artifacts(engine.0, wasm), // Implementation of how to serialize artifacts - |(engine, _wasm), (_, artifacts, types)| { + |(engine, _wasm), (mmap, _info, types)| { SerializedModule::from_artifacts( engine.0, - artifacts.iter().map(|p| &p.0), + mmap, types, ).to_bytes(&engine.0.config().module_version).ok() }, // Cache hit, deserialize the provided artifacts |(engine, _wasm), serialized_bytes| { - let (i, m, t, upvars) = SerializedModule::from_bytes(&serialized_bytes, &engine.0.config().module_version) + SerializedModule::from_bytes(&serialized_bytes, &engine.0.config().module_version) .ok()? .into_parts(engine.0) - .ok()?; - // This upvars list is always empty for top-level modules - assert!(upvars.is_empty()); - Some((i, m, t)) + .ok() }, )?; } else { - let (main_module, artifacts, types) = Module::build_artifacts(engine, binary)?; + let (mmap, info, types) = Module::build_artifacts(engine, binary)?; } }; - let modules = engine.run_maybe_parallel(artifacts, |(a, b)| { - CompiledModule::from_artifacts( - a, - b, - &*engine.config().profiler, - engine.unique_id_allocator(), - ) - })?; + let module = CompiledModule::from_artifacts( + mmap, + info, + &*engine.config().profiler, + engine.unique_id_allocator(), + )?; - Self::from_parts(engine, modules, main_module, Arc::new(types), &[]) + Self::from_parts(engine, module, Arc::new(types)) } /// Converts an input binary-encoded WebAssembly module to compilation @@ -375,79 +363,66 @@ impl Module { pub(crate) fn build_artifacts( engine: &Engine, wasm: &[u8], - ) -> Result<( - usize, - Vec<(MmapVec, Option)>, - TypeTables, - )> { + ) -> Result<(MmapVec, Option, TypeTables)> { let tunables = &engine.config().tunables; // First a `ModuleEnvironment` is created which records type information // about the wasm module. This is where the WebAssembly is parsed and // validated. Afterwards `types` will have all the type information for // this module. - let (main_module, translations, types) = - ModuleEnvironment::new(tunables, &engine.config().features) - .translate(wasm) - .context("failed to parse WebAssembly module")?; - - // Perform a two-level map/reduce here to get the final list of - // compilation artifacts. The first level of map/reduce maps over all - // modules found and reduces to collection into a vector. The second - // level of map/reduce here maps over all functions within each wasm - // module found and collects into an ELF image via `emit_obj`. - let list = engine.run_maybe_parallel(translations, |mut translation| -> Result<_> { - let functions = mem::take(&mut translation.function_body_inputs); - let functions = functions.into_iter().collect::>(); - - let funcs = engine - .run_maybe_parallel(functions, |(index, func)| { - engine - .compiler() - .compile_function(&translation, index, func, tunables, &types) - })? - .into_iter() - .collect(); - - let mut obj = engine.compiler().object()?; - let (funcs, trampolines) = + let (mut translation, types) = ModuleEnvironment::new(tunables, &engine.config().features) + .translate(wasm) + .context("failed to parse WebAssembly module")?; + + // Next compile all functions in parallel using rayon. This will perform + // the actual validation of all the function bodies. + let functions = mem::take(&mut translation.function_body_inputs); + let functions = functions.into_iter().collect::>(); + let funcs = engine + .run_maybe_parallel(functions, |(index, func)| { engine .compiler() - .emit_obj(&translation, &types, funcs, tunables, &mut obj)?; + .compile_function(&translation, index, func, tunables, &types) + })? + .into_iter() + .collect(); - // If configured, attempt to use paged memory initialization - // instead of the default mode of memory initialization - if engine.config().paged_memory_initialization { - translation.try_paged_init(); - } + // Collect all the function results into a final ELF object. + let mut obj = engine.compiler().object()?; + let (funcs, trampolines) = + engine + .compiler() + .emit_obj(&translation, &types, funcs, tunables, &mut obj)?; + + // If configured, attempt to use paged memory initialization + // instead of the default mode of memory initialization + if engine.config().paged_memory_initialization { + translation.try_paged_init(); + } - // If configured attempt to use static memory initialization which - // can either at runtime be implemented as a single memcpy to - // initialize memory or otherwise enabling virtual-memory-tricks - // such as mmap'ing from a file to get copy-on-write. - if engine.config().memory_init_cow { - let align = engine.compiler().page_size_align(); - let max_always_allowed = engine.config().memory_guaranteed_dense_image_size; - translation.try_static_init(align, max_always_allowed); - } + // If configured attempt to use static memory initialization which + // can either at runtime be implemented as a single memcpy to + // initialize memory or otherwise enabling virtual-memory-tricks + // such as mmap'ing from a file to get copy-on-write. + if engine.config().memory_init_cow { + let align = engine.compiler().page_size_align(); + let max_always_allowed = engine.config().memory_guaranteed_dense_image_size; + translation.try_static_init(align, max_always_allowed); + } - // Attempt to convert table initializer segments to - // FuncTable representation where possible, to enable - // table lazy init. - translation.try_func_table_init(); + // Attempt to convert table initializer segments to + // FuncTable representation where possible, to enable + // table lazy init. + translation.try_func_table_init(); - let (mmap, info) = - wasmtime_jit::finish_compile(translation, obj, funcs, trampolines, tunables)?; - Ok((mmap, Some(info))) - })?; + let (mmap, info) = + wasmtime_jit::finish_compile(translation, obj, funcs, trampolines, tunables)?; Ok(( - main_module, - list, + mmap, + Some(info), TypeTables { wasm_signatures: types.wasm_signatures, - module_signatures: types.module_signatures, - instance_signatures: types.instance_signatures, }, )) } @@ -529,91 +504,27 @@ impl Module { fn from_parts( engine: &Engine, - mut modules: Vec>, - main_module: usize, + module: Arc, types: Arc, - module_upvars: &[serialization::SerializedModuleUpvar], ) -> Result { - // Validate all modules can be used with the current allocator - for module in modules.iter() { - engine.allocator().validate(module.module())?; - } + // Validate the module can be used with the current allocator + engine.allocator().validate(module.module())?; let signatures = Arc::new(SignatureCollection::new_for_module( engine.signatures(), &types.wasm_signatures, - modules - .iter() - .flat_map(|m| m.trampolines().map(|(idx, f, _)| (idx, f))), + module.trampolines().map(|(idx, f, _)| (idx, f)), )); - let module = modules.remove(main_module); - - let module_upvars = module_upvars - .iter() - .map(|m| { - mk( - engine, - &modules, - &types, - m.index, - &m.artifact_upvars, - &m.module_upvars, - &signatures, - ) - }) - .collect(); - - return Ok(Self { + Ok(Self { inner: Arc::new(ModuleInner { engine: engine.clone(), types, - artifact_upvars: modules, - module_upvars, signatures, memory_images: OnceCell::new(), module, }), - }); - - fn mk( - engine: &Engine, - artifacts: &[Arc], - types: &Arc, - module_index: usize, - artifact_upvars: &[usize], - module_upvars: &[serialization::SerializedModuleUpvar], - signatures: &Arc, - ) -> Module { - let module = artifacts[module_index].clone(); - Module { - inner: Arc::new(ModuleInner { - engine: engine.clone(), - types: types.clone(), - memory_images: OnceCell::new(), - module, - artifact_upvars: artifact_upvars - .iter() - .map(|i| artifacts[*i].clone()) - .collect(), - module_upvars: module_upvars - .into_iter() - .map(|m| { - mk( - engine, - artifacts, - types, - m.index, - &m.artifact_upvars, - &m.module_upvars, - signatures, - ) - }) - .collect(), - signatures: signatures.clone(), - }), - } - } + }) } /// Validates `binary` input data as a WebAssembly binary given the @@ -650,23 +561,6 @@ impl Module { Ok(()) } - /// Returns the type signature of this module. - pub fn ty(&self) -> ModuleType { - let mut sig = ModuleType::new(); - let env_module = self.compiled_module().module(); - let types = self.types(); - for (module, field, ty) in env_module.imports() { - sig.add_named_import(module, field, ExternType::from_wasmtime(types, &ty)); - } - for (name, index) in env_module.exports.iter() { - sig.add_named_export( - name, - ExternType::from_wasmtime(types, &env_module.type_of(*index)), - ); - } - sig - } - /// Serializes this module to a vector of bytes. /// /// This function is similar to the [`Engine::precompile_module`] method @@ -682,60 +576,6 @@ impl Module { SerializedModule::new(self).to_bytes(&self.inner.engine.config().module_version) } - /// Creates a submodule `Module` value from the specified parameters. - /// - /// This is used for creating submodules as part of module instantiation. - /// - /// * `artifact_index` - the index in `artifact_upvars` that we're creating - /// a module for - /// * `artifact_upvars` - the mapping of indices of what artifact upvars are - /// needed for the submodule. The length of this array is the length of - /// the upvars array in the submodule to be created, and each element of - /// this array is an index into this module's upvar array. - /// * `module_upvars` - similar to `artifact_upvars` this is a mapping of - /// how to create the `module_upvars` of the submodule being created. - /// Each entry in this array is either an index into this module's own - /// module upvars array or it's an index into `modules`, the list of - /// modules so far for the instance where this submodule is being - /// created. - /// * `modules` - array indexed by `module_upvars`. - /// - /// Note that the real meat of this happens in `ModuleEnvironment` - /// translation inside of `wasmtime_environ`. This just does the easy thing - /// of handling all the indices, over there is where the indices are - /// actually calculated and such. - pub(crate) fn create_submodule( - &self, - artifact_index: usize, - artifact_upvars: &[usize], - module_upvars: &[wasmtime_environ::ModuleUpvar], - modules: &PrimaryMap, - ) -> Result { - let module = self.inner.artifact_upvars[artifact_index].clone(); - Ok(Module { - inner: Arc::new(ModuleInner { - types: self.inner.types.clone(), - engine: self.inner.engine.clone(), - memory_images: OnceCell::new(), - module, - artifact_upvars: artifact_upvars - .iter() - .map(|i| self.inner.artifact_upvars[*i].clone()) - .collect(), - module_upvars: module_upvars - .iter() - .map(|i| match *i { - wasmtime_environ::ModuleUpvar::Inherit(i) => { - self.inner.module_upvars[i].clone() - } - wasmtime_environ::ModuleUpvar::Local(i) => modules[i].clone(), - }) - .collect(), - signatures: self.inner.signatures.clone(), - }), - }) - } - pub(crate) fn compiled_module(&self) -> &Arc { &self.inner.module } @@ -752,14 +592,6 @@ impl Module { &self.inner.signatures } - /// Looks up the module upvar value at the `index` specified. - /// - /// Note that this panics if `index` is out of bounds since this should - /// only be called for valid indices as part of instantiation. - pub(crate) fn module_upvar(&self, index: usize) -> &Module { - &self.inner.module_upvars[index] - } - /// Returns identifier/name that this [`Module`] has. This name /// is used in traps/backtrace details. /// @@ -829,7 +661,7 @@ impl Module { /// assert_eq!(module.imports().len(), 1); /// let import = module.imports().next().unwrap(); /// assert_eq!(import.module(), "host"); - /// assert_eq!(import.name(), Some("foo")); + /// assert_eq!(import.name(), "foo"); /// match import.ty() { /// ExternType::Func(_) => { /* ... */ } /// _ => panic!("unexpected import type!"), diff --git a/crates/wasmtime/src/module/serialization.rs b/crates/wasmtime/src/module/serialization.rs index 83dca9a0261c..c3fc283352b9 100644 --- a/crates/wasmtime/src/module/serialization.rs +++ b/crates/wasmtime/src/module/serialization.rs @@ -6,36 +6,22 @@ //! //! There are two main pieces of data associated with a binary artifact: //! -//! 1. A list of compiled modules. The reason this is a list as opposed to one -//! singular module is that a module-linking module may encompass a number -//! of other modules. -//! 2. Compilation metadata shared by all modules, including the global -//! `TypeTables` information. This metadata is validated for compilation -//! settings and also has information shared by all modules (such as the -//! shared `TypeTables`). +//! 1. The compiled module image, currently an ELF file. +//! 2. Compilation metadata for the module, including the `TypeTables` +//! information. This metadata is validated for compilation settings. //! //! Compiled modules are, at this time, represented as an ELF file. This ELF -//! file contains all the necessary data needed to decode each individual -//! module, and conveniently also handles things like alignment so we can -//! actually directly `mmap` compilation artifacts from disk. +//! file contains all the necessary data needed to decode a module, and +//! conveniently also handles things like alignment so we can actually directly +//! `mmap` compilation artifacts from disk. //! -//! With all this in mind, the current serialization format is as follows: +//! With this in mind, the current serialization format is as follows: //! -//! * The first, primary, module starts the final artifact. This means that the -//! final artifact is actually, and conveniently, a valid ELF file. ELF files -//! don't place any restrictions on data coming after the ELF file itself, -//! so that's where everything else will go. Another reason for using this -//! format is that our compilation artifacts are then consumable by standard -//! debugging tools like `objdump` to poke around and see what's what. +//! * First the ELF image for the compiled module starts the artifact. This +//! helps developers use standard ELF-reading utilities like `objdump` to poke +//! around and see what's inside the compiled image. //! -//! * Next, all other modules are encoded. Each module has its own alignment, -//! though, so modules aren't simply concatenated. Instead directly after an -//! ELF file there is a 64-bit little-endian integer which is the offset, -//! from the end of the previous ELF file, to the next ELF file. -//! -//! * Finally, once all modules have been encoded (there's always at least -//! one), the 8-byte value `u64::MAX` is encoded. Following this is a -//! number of fields: +//! * After the ELF file is a number of fields: //! //! 1. The `HEADER` value //! 2. A byte indicating how long the next field is @@ -46,15 +32,19 @@ //! other random ELF files, as well as provide better error messages for //! using wasmtime artifacts across versions. //! +//! Note that the structure of the ELF format is what enables this +//! representation. We can have trailing data after an ELF file which isn't read +//! by any parsing of the ELF itself, which provides a convenient location for +//! the metadata information to go. +//! //! This format is implemented by the `to_bytes` and `from_mmap` function. use crate::{Engine, Module, ModuleVersionStrategy}; use anyhow::{anyhow, bail, Context, Result}; use object::read::elf::FileHeader; -use object::{Bytes, File, Object, ObjectSection}; +use object::Bytes; use serde::{Deserialize, Serialize}; use std::collections::BTreeMap; -use std::convert::TryFrom; use std::path::Path; use std::str::FromStr; use std::sync::Arc; @@ -165,50 +155,8 @@ impl<'a, 'b, T: Deserialize<'a>> Deserialize<'a> for MyCow<'b, T> { } } -/// A small helper struct for serialized module upvars. -#[derive(Serialize, Deserialize)] -pub struct SerializedModuleUpvar { - /// The module's index into the compilation artifact. - pub index: usize, - /// Indexes into the list of all compilation artifacts for this module. - pub artifact_upvars: Vec, - /// Closed-over module values that are also needed for this module. - pub module_upvars: Vec, -} - -impl SerializedModuleUpvar { - pub fn new(module: &Module, artifacts: &[Arc]) -> Self { - // TODO: improve upon the linear searches in the artifact list - let index = artifacts - .iter() - .position(|a| Arc::as_ptr(a) == Arc::as_ptr(&module.inner.module)) - .expect("module should be in artifacts list"); - - SerializedModuleUpvar { - index, - artifact_upvars: module - .inner - .artifact_upvars - .iter() - .map(|m| { - artifacts - .iter() - .position(|a| Arc::as_ptr(a) == Arc::as_ptr(m)) - .expect("artifact should be in artifacts list") - }) - .collect(), - module_upvars: module - .inner - .module_upvars - .iter() - .map(|m| SerializedModuleUpvar::new(m, artifacts)) - .collect(), - } - } -} - pub struct SerializedModule<'a> { - artifacts: Vec>, + artifacts: MyCow<'a, MmapVec>, metadata: Metadata<'a>, } @@ -219,54 +167,28 @@ struct Metadata<'a> { isa_flags: BTreeMap, tunables: Tunables, features: WasmFeatures, - module_upvars: Vec, types: MyCow<'a, TypeTables>, } impl<'a> SerializedModule<'a> { #[cfg(compiler)] pub fn new(module: &'a Module) -> Self { - let artifacts = module - .inner - .artifact_upvars - .iter() - .map(|m| MyCow::Borrowed(m.mmap())) - .chain(Some(MyCow::Borrowed(module.inner.module.mmap()))) - .collect::>(); - let module_upvars = module - .inner - .module_upvars - .iter() - .map(|m| SerializedModuleUpvar::new(m, &module.inner.artifact_upvars)) - .collect::>(); - Self::with_data( module.engine(), - artifacts, - module_upvars, + MyCow::Borrowed(module.compiled_module().mmap()), MyCow::Borrowed(module.types()), ) } #[cfg(compiler)] - pub fn from_artifacts( - engine: &Engine, - artifacts: impl IntoIterator, - types: &'a TypeTables, - ) -> Self { - Self::with_data( - engine, - artifacts.into_iter().map(MyCow::Borrowed).collect(), - Vec::new(), - MyCow::Borrowed(types), - ) + pub fn from_artifacts(engine: &Engine, artifacts: &'a MmapVec, types: &'a TypeTables) -> Self { + Self::with_data(engine, MyCow::Borrowed(artifacts), MyCow::Borrowed(types)) } #[cfg(compiler)] fn with_data( engine: &Engine, - artifacts: Vec>, - module_upvars: Vec, + artifacts: MyCow<'a, MmapVec>, types: MyCow<'a, TypeTables>, ) -> Self { Self { @@ -277,35 +199,27 @@ impl<'a> SerializedModule<'a> { isa_flags: engine.compiler().isa_flags(), tunables: engine.config().tunables.clone(), features: (&engine.config().features).into(), - module_upvars, types, }, } } pub fn into_module(self, engine: &Engine) -> Result { - let (main_module, modules, types, upvars) = self.into_parts(engine)?; - let modules = engine.run_maybe_parallel(modules, |(i, m)| { - CompiledModule::from_artifacts( - i, - m, - &*engine.config().profiler, - engine.unique_id_allocator(), - ) - })?; - - Module::from_parts(engine, modules, main_module, Arc::new(types), &upvars) + let (mmap, info, types) = self.into_parts(engine)?; + let module = CompiledModule::from_artifacts( + mmap, + info, + &*engine.config().profiler, + engine.unique_id_allocator(), + )?; + + Module::from_parts(engine, module, Arc::new(types)) } pub fn into_parts( mut self, engine: &Engine, - ) -> Result<( - usize, - Vec<(MmapVec, Option)>, - TypeTables, - Vec, - )> { + ) -> Result<(MmapVec, Option, TypeTables)> { // Verify that the compilation settings in the engine match the // compilation settings of the module that's being loaded. self.check_triple(engine)?; @@ -315,45 +229,18 @@ impl<'a> SerializedModule<'a> { self.check_tunables(&engine.config().tunables)?; self.check_features(&engine.config().features)?; - assert!(!self.artifacts.is_empty()); - let modules = self.artifacts.into_iter().map(|i| (i.unwrap_owned(), None)); - - let main_module = modules.len() - 1; + let module = self.artifacts.unwrap_owned(); - Ok(( - main_module, - modules.collect(), - self.metadata.types.unwrap_owned(), - self.metadata.module_upvars, - )) + Ok((module, None, self.metadata.types.unwrap_owned())) } pub fn to_bytes(&self, version_strat: &ModuleVersionStrategy) -> Result> { - // First up, create a linked-ish list of ELF files. For more - // information on this format, see the doc comment on this module. - // The only semi-tricky bit here is that we leave an - // offset-to-the-next-file between each set of ELF files. The list - // is then terminated with `u64::MAX`. - let mut ret = Vec::new(); - for (i, obj) in self.artifacts.iter().enumerate() { - // Anything after the first object needs to respect the alignment of - // the object's sections, so insert padding as necessary. Note that - // the +8 to the length here is to accomodate the size we'll write - // to get to the next object. - if i > 0 { - let obj = File::parse(&obj.as_ref()[..])?; - let align = obj.sections().map(|s| s.align()).max().unwrap_or(0).max(1); - let align = usize::try_from(align).unwrap(); - let new_size = align_to(ret.len() + 8, align); - ret.extend_from_slice(&(new_size as u64).to_le_bytes()); - ret.resize(new_size, 0); - } - ret.extend_from_slice(obj.as_ref()); - } - ret.extend_from_slice(&[0xff; 8]); + // Start off with a copy of the ELF image. + let mut ret = self.artifacts.as_ref().to_vec(); - // The last part of our artifact is the bincode-encoded `Metadata` - // section with a few other guards to help give better error messages. + // Append the bincode-encoded `Metadata` section with a few other guards + // to help give better error messages during deserialization if + // something goes wrong. ret.extend_from_slice(HEADER); let version = match version_strat { ModuleVersionStrategy::WasmtimeVersion => env!("CARGO_PKG_VERSION"), @@ -385,37 +272,14 @@ impl<'a> SerializedModule<'a> { ) } - pub fn from_mmap(mut mmap: MmapVec, version_strat: &ModuleVersionStrategy) -> Result { - // Artifacts always start with an ELF file, so read that first. - // Afterwards we continually read ELF files until we see the `u64::MAX` - // marker, meaning we've reached the end. - let first_module = read_file(&mut mmap)?; - let mut pos = first_module.len(); - let mut artifacts = vec![MyCow::Owned(first_module)]; - - let metadata = loop { - if mmap.len() < 8 { - bail!("invalid serialized data"); - } - let next_file_start = u64::from_le_bytes([ - mmap[0], mmap[1], mmap[2], mmap[3], mmap[4], mmap[5], mmap[6], mmap[7], - ]); - if next_file_start == u64::MAX { - mmap.drain(..8); - break mmap; - } - - // Remove padding leading up to the next file - let next_file_start = usize::try_from(next_file_start).unwrap(); - let _padding = mmap.drain(..next_file_start - pos); - let data = read_file(&mut mmap)?; - pos = next_file_start + data.len(); - artifacts.push(MyCow::Owned(data)); - }; + pub fn from_mmap(mmap: MmapVec, version_strat: &ModuleVersionStrategy) -> Result { + // First validate that this is at least somewhat an elf file within + // `mmap` and additionally skip to the end of the elf file to find our + // metadata. + let metadata = data_after_elf(&mmap)?; - // Once we've reached the end we parse a `Metadata` object. This has a - // few guards up front which we process first, and eventually this - // bottoms out in a `bincode::deserialize` call. + // The metadata has a few guards up front which we process first, and + // eventually this bottoms out in a `bincode::deserialize` call. let metadata = metadata .strip_prefix(HEADER) .ok_or_else(|| anyhow!("bytes are not a compatible serialized wasmtime module"))?; @@ -453,18 +317,13 @@ impl<'a> SerializedModule<'a> { .context("deserialize compilation artifacts")?; return Ok(SerializedModule { - artifacts, + artifacts: MyCow::Owned(mmap), metadata, }); - /// This function will drain the beginning contents of `mmap` which - /// correspond to an ELF object file. The ELF file is only very lightly - /// validated. - /// - /// The `mmap` passed in will be reset to just after the ELF file, and - /// the `MmapVec` returned represents the extend of the ELF file - /// itself. - fn read_file(mmap: &mut MmapVec) -> Result { + /// This function will return the trailing data behind the ELF file + /// parsed from `data` which is where we find our metadata section. + fn data_after_elf(data: &[u8]) -> Result<&[u8]> { use object::NativeEndian as NE; // There's not actually a great utility for figuring out where // the end of an ELF file is in the `object` crate. In lieu of that @@ -472,7 +331,7 @@ impl<'a> SerializedModule<'a> { // is that the header comes first, that tells us where the section // headers are, and for our ELF files the end of the file is the // end of the section headers. - let mut bytes = Bytes(mmap); + let mut bytes = Bytes(data); let header = bytes .read::>() .map_err(|()| anyhow!("artifact truncated, can't read header"))?; @@ -480,10 +339,10 @@ impl<'a> SerializedModule<'a> { bail!("invalid elf header"); } let sections = header - .section_headers(NE, &mmap[..]) + .section_headers(NE, data) .context("failed to read section headers")?; - let range = subslice_range(object::bytes_of_slice(sections), mmap); - Ok(mmap.drain(..range.end)) + let range = subslice_range(object::bytes_of_slice(sections), data); + Ok(&data[range.end..]) } } @@ -697,12 +556,6 @@ impl<'a> SerializedModule<'a> { } } -/// Aligns the `val` specified up to `align`, which must be a power of two -fn align_to(val: usize, align: usize) -> usize { - debug_assert!(align.is_power_of_two()); - (val + (align - 1)) & (!(align - 1)) -} - #[cfg(test)] mod test { use super::*; diff --git a/crates/wasmtime/src/trampoline/global.rs b/crates/wasmtime/src/trampoline/global.rs index 45c255264d19..69b63487bc0a 100644 --- a/crates/wasmtime/src/trampoline/global.rs +++ b/crates/wasmtime/src/trampoline/global.rs @@ -49,7 +49,7 @@ pub fn create_global(store: &mut StoreOpaque, gt: &GlobalType, val: Val) -> Resu .initializers .push(wasmtime_environ::Initializer::Import { name: "".into(), - field: None, + field: "".into(), index: EntityIndex::Function(func_index), }); diff --git a/crates/wasmtime/src/types.rs b/crates/wasmtime/src/types.rs index 738cc1c7ddf7..feacd37e43ee 100644 --- a/crates/wasmtime/src/types.rs +++ b/crates/wasmtime/src/types.rs @@ -115,10 +115,6 @@ pub enum ExternType { Table(TableType), /// This external type is the type of a WebAssembly memory. Memory(MemoryType), - /// This external type is the type of a WebAssembly instance. - Instance(InstanceType), - /// This external type is the type of a WebAssembly module. - Module(ModuleType), } macro_rules! accessors { @@ -151,8 +147,6 @@ impl ExternType { (Global(GlobalType) global unwrap_global) (Table(TableType) table unwrap_table) (Memory(MemoryType) memory unwrap_memory) - (Module(ModuleType) module unwrap_module) - (Instance(InstanceType) instance unwrap_instance) } pub(crate) fn from_wasmtime(types: &TypeTables, ty: &EntityType) -> ExternType { @@ -163,14 +157,6 @@ impl ExternType { EntityType::Global(ty) => GlobalType::from_wasmtime_global(ty).into(), EntityType::Memory(ty) => MemoryType::from_wasmtime_memory(ty).into(), EntityType::Table(ty) => TableType::from_wasmtime_table(ty).into(), - EntityType::Module(ty) => { - let ty = &types.module_signatures[*ty]; - ModuleType::from_wasmtime(types, ty).into() - } - EntityType::Instance(ty) => { - let ty = &types.instance_signatures[*ty]; - InstanceType::from_wasmtime(types, ty).into() - } EntityType::Tag(_) => unimplemented!("wasm tag support"), } } @@ -200,18 +186,6 @@ impl From for ExternType { } } -impl From for ExternType { - fn from(ty: ModuleType) -> ExternType { - ExternType::Module(ty) - } -} - -impl From for ExternType { - fn from(ty: InstanceType) -> ExternType { - ExternType::Instance(ty) - } -} - /// A descriptor for a function in a WebAssembly module. /// /// WebAssembly functions can have 0 or more parameters and results. @@ -439,122 +413,6 @@ impl MemoryType { } } -// Module Types - -/// A descriptor for a WebAssembly module type. -/// -/// This is a part of the [WebAssembly module-linking proposal][proposal]. -/// -/// [proposal]: https://github.com/webassembly/module-linking -#[derive(Debug, Clone)] -pub struct ModuleType { - imports: Vec<(String, Option, ExternType)>, - exports: Vec<(String, ExternType)>, -} - -impl ModuleType { - /// Creates a new empty module type. - pub fn new() -> ModuleType { - ModuleType { - imports: Vec::new(), - exports: Vec::new(), - } - } - - /// Adds a new export to this `ModuleType`. - pub fn add_named_export(&mut self, name: &str, ty: ExternType) { - self.exports.push((name.to_string(), ty)); - } - - /// Adds a new import to this `ModuleType`. - pub fn add_named_import(&mut self, module: &str, field: Option<&str>, ty: ExternType) { - self.imports - .push((module.to_string(), field.map(|f| f.to_string()), ty)); - } - - /// Returns the list of imports associated with this module type. - pub fn imports(&self) -> impl ExactSizeIterator> { - self.imports.iter().map(|(name, field, ty)| ImportType { - module: name, - name: field.as_deref(), - ty: EntityOrExtern::Extern(ty), - }) - } - - /// Returns the list of exports associated with this module type. - pub fn exports(&self) -> impl ExactSizeIterator> { - self.exports.iter().map(|(name, ty)| ExportType { - name, - ty: EntityOrExtern::Extern(ty), - }) - } - - pub(crate) fn from_wasmtime( - types: &TypeTables, - ty: &wasmtime_environ::ModuleSignature, - ) -> ModuleType { - let exports = &types.instance_signatures[ty.exports].exports; - ModuleType { - exports: exports - .iter() - .map(|(name, ty)| (name.to_string(), ExternType::from_wasmtime(types, ty))) - .collect(), - imports: ty - .imports - .iter() - .map(|(m, ty)| (m.to_string(), None, ExternType::from_wasmtime(types, ty))) - .collect(), - } - } -} - -// Instance Types - -/// A descriptor for a WebAssembly instance type. -/// -/// This is a part of the [WebAssembly module-linking proposal][proposal]. -/// -/// [proposal]: https://github.com/webassembly/module-linking -#[derive(Debug, Clone)] -pub struct InstanceType { - exports: Vec<(String, ExternType)>, -} - -impl InstanceType { - /// Creates a new empty instance type. - pub fn new() -> InstanceType { - InstanceType { - exports: Vec::new(), - } - } - - /// Adds a new export to this `ModuleType`. - pub fn add_named_export(&mut self, name: &str, ty: ExternType) { - self.exports.push((name.to_string(), ty)); - } - - /// Returns the list of exports associated with this module type. - pub fn exports(&self) -> impl ExactSizeIterator> { - self.exports.iter().map(|(name, ty)| ExportType { - name, - ty: EntityOrExtern::Extern(ty), - }) - } - - pub(crate) fn from_wasmtime( - types: &TypeTables, - ty: &wasmtime_environ::InstanceSignature, - ) -> InstanceType { - InstanceType { - exports: ty - .exports - .iter() - .map(|(name, ty)| (name.to_string(), ExternType::from_wasmtime(types, ty))) - .collect(), - } - } -} - // Import Types /// A descriptor for an imported value into a wasm module. @@ -569,16 +427,11 @@ pub struct ImportType<'module> { module: &'module str, /// The field of the import. - name: Option<&'module str>, + name: &'module str, /// The type of the import. - ty: EntityOrExtern<'module>, -} - -#[derive(Clone)] -enum EntityOrExtern<'a> { - Entity(EntityType, &'a TypeTables), - Extern(&'a ExternType), + ty: EntityType, + types: &'module TypeTables, } impl<'module> ImportType<'module> { @@ -586,14 +439,15 @@ impl<'module> ImportType<'module> { /// is of type `ty`. pub(crate) fn new( module: &'module str, - name: Option<&'module str>, + name: &'module str, ty: EntityType, types: &'module TypeTables, ) -> ImportType<'module> { ImportType { module, name, - ty: EntityOrExtern::Entity(ty, types), + ty, + types, } } @@ -604,20 +458,13 @@ impl<'module> ImportType<'module> { /// Returns the field name of the module that this import is expected to /// come from. - /// - /// Note that this is optional due to the module linking proposal. If the - /// module linking proposal is enabled this is always `None`, otherwise this - /// is always `Some`. - pub fn name(&self) -> Option<&'module str> { + pub fn name(&self) -> &'module str { self.name } /// Returns the expected type of this import. pub fn ty(&self) -> ExternType { - match &self.ty { - EntityOrExtern::Entity(e, types) => ExternType::from_wasmtime(types, e), - EntityOrExtern::Extern(e) => (*e).clone(), - } + ExternType::from_wasmtime(self.types, &self.ty) } } @@ -645,7 +492,8 @@ pub struct ExportType<'module> { name: &'module str, /// The type of the export. - ty: EntityOrExtern<'module>, + ty: EntityType, + types: &'module TypeTables, } impl<'module> ExportType<'module> { @@ -656,10 +504,7 @@ impl<'module> ExportType<'module> { ty: EntityType, types: &'module TypeTables, ) -> ExportType<'module> { - ExportType { - name, - ty: EntityOrExtern::Entity(ty, types), - } + ExportType { name, ty, types } } /// Returns the name by which this export is known. @@ -669,10 +514,7 @@ impl<'module> ExportType<'module> { /// Returns the type of this export. pub fn ty(&self) -> ExternType { - match &self.ty { - EntityOrExtern::Entity(e, types) => ExternType::from_wasmtime(types, e), - EntityOrExtern::Extern(e) => (*e).clone(), - } + ExternType::from_wasmtime(self.types, &self.ty) } } diff --git a/crates/wasmtime/src/types/matching.rs b/crates/wasmtime/src/types/matching.rs index 4df6170394f5..c6a200cadb65 100644 --- a/crates/wasmtime/src/types/matching.rs +++ b/crates/wasmtime/src/types/matching.rs @@ -1,12 +1,8 @@ -use crate::instance::InstanceData; use crate::linker::Definition; use crate::store::StoreOpaque; use crate::{signatures::SignatureCollection, Engine, Extern}; -use anyhow::{bail, Context, Result}; -use wasmtime_environ::{ - EntityType, Global, InstanceTypeIndex, Memory, ModuleTypeIndex, SignatureIndex, Table, - WasmFuncType, WasmType, -}; +use anyhow::{bail, Result}; +use wasmtime_environ::{EntityType, Global, Memory, SignatureIndex, Table, WasmFuncType, WasmType}; use wasmtime_jit::TypeTables; use wasmtime_runtime::VMSharedSignatureIndex; @@ -156,206 +152,6 @@ impl MatchCx<'_> { ) } - pub fn instance(&self, expected: InstanceTypeIndex, actual: &crate::Instance) -> Result<()> { - for (name, expected) in self.types.instance_signatures[expected].exports.iter() { - match actual.data(self.store.store_data()) { - InstanceData::Synthetic(names) => match names.get(name) { - Some(item) => { - self.extern_(expected, item) - .with_context(|| format!("instance export {:?} incompatible", name))?; - } - None => bail!("instance type missing export {:?}", name), - }, - InstanceData::Instantiated { - id, - types, - signatures, - .. - } => { - let module = self.store.instance(*id).module(); - match module.exports.get(name) { - Some(index) => { - let actual_ty = module.type_of(*index); - self.extern_ty_matches(expected, &actual_ty, signatures, types) - .with_context(|| { - format!("instance export {:?} incompatible", name) - })?; - } - None => bail!("instance type missing export {:?}", name), - } - - // let - } - } - } - Ok(()) - } - - /// Validates that the type signature of `actual` matches the `expected` - /// module type signature. - pub fn module(&self, expected: ModuleTypeIndex, actual: &crate::Module) -> Result<()> { - // This should only ever be invoked with module linking, and this is an - // early check that our `field` assertion below should always work as - // well. - assert!(self.engine.config().features.module_linking); - - let expected_sig = &self.types.module_signatures[expected]; - let module = actual.compiled_module().module(); - self.imports_match( - expected, - actual.signatures(), - actual.types(), - module.imports().map(|(name, field, ty)| { - assert!(field.is_none()); // should be true if module linking is enabled - (name, ty) - }), - )?; - self.exports_match( - expected_sig.exports, - actual.signatures(), - actual.types(), - |name| module.exports.get(name).map(|idx| module.type_of(*idx)), - )?; - Ok(()) - } - - /// Validates that the `actual_imports` list of module imports matches the - /// `expected` module type signature. - /// - /// Types specified in `actual_imports` are relative to `actual_types`. - fn imports_match<'a>( - &self, - expected: ModuleTypeIndex, - actual_signatures: &SignatureCollection, - actual_types: &TypeTables, - actual_imports: impl Iterator, - ) -> Result<()> { - // Imports match if all of the actual imports are satisfied by the - // expected set of imports. Note that we're reversing the order of the - // subtytpe matching here too. - let expected_sig = &self.types.module_signatures[expected]; - for (name, actual_ty) in actual_imports { - let expected_ty = match expected_sig.imports.get(name) { - Some(ty) => ty, - None => bail!("expected type doesn't import {:?}", name), - }; - MatchCx { - signatures: actual_signatures, - types: actual_types, - store: self.store, - engine: self.engine, - } - .extern_ty_matches(&actual_ty, expected_ty, self.signatures, self.types) - .with_context(|| format!("module import {:?} incompatible", name))?; - } - Ok(()) - } - - /// Validates that all exports in `expected` are defined by `lookup` within - /// `actual_types`. - fn exports_match( - &self, - expected: InstanceTypeIndex, - actual_signatures: &SignatureCollection, - actual_types: &TypeTables, - lookup: impl Fn(&str) -> Option, - ) -> Result<()> { - // The `expected` type must be a subset of `actual`, meaning that all - // names in `expected` must be present in `actual`. Note that we do - // name-based lookup here instead of index-based lookup. - for (name, expected) in self.types.instance_signatures[expected].exports.iter() { - match lookup(name) { - Some(ty) => self - .extern_ty_matches(expected, &ty, actual_signatures, actual_types) - .with_context(|| format!("export {:?} incompatible", name))?, - None => bail!("failed to find export {:?}", name), - } - } - Ok(()) - } - - /// Validates that the `expected` entity matches the `actual_ty` defined - /// within `actual_types`. - fn extern_ty_matches( - &self, - expected: &EntityType, - actual_ty: &EntityType, - actual_signatures: &SignatureCollection, - actual_types: &TypeTables, - ) -> Result<()> { - let actual_desc = match actual_ty { - EntityType::Global(_) => "global", - EntityType::Module(_) => "module", - EntityType::Memory(_) => "memory", - EntityType::Tag(_) => "tag", - EntityType::Instance(_) => "instance", - EntityType::Table(_) => "table", - EntityType::Function(_) => "function", - }; - match expected { - EntityType::Global(expected) => match actual_ty { - EntityType::Global(actual) => self.global_ty(expected, actual), - _ => bail!("expected global, but found {}", actual_desc), - }, - EntityType::Table(expected) => match actual_ty { - EntityType::Table(actual) => self.table_ty(expected, actual, None), - _ => bail!("expected table, but found {}", actual_desc), - }, - EntityType::Memory(expected) => match actual_ty { - EntityType::Memory(actual) => self.memory_ty(expected, actual, None), - _ => bail!("expected memory, but found {}", actual_desc), - }, - EntityType::Function(expected) => match *actual_ty { - EntityType::Function(actual) => { - if self.types.wasm_signatures[*expected] == actual_types.wasm_signatures[actual] - { - Ok(()) - } else { - bail!("function types incompatible") - } - } - _ => bail!("expected function, but found {}", actual_desc), - }, - EntityType::Instance(expected) => match actual_ty { - EntityType::Instance(actual) => { - let sig = &actual_types.instance_signatures[*actual]; - self.exports_match(*expected, actual_signatures, actual_types, |name| { - sig.exports.get(name).cloned() - })?; - Ok(()) - } - _ => bail!("expected instance, but found {}", actual_desc), - }, - EntityType::Module(expected) => match actual_ty { - EntityType::Module(actual) => { - let expected_module_sig = &self.types.module_signatures[*expected]; - let actual_module_sig = &actual_types.module_signatures[*actual]; - let actual_instance_sig = - &actual_types.instance_signatures[actual_module_sig.exports]; - - self.imports_match( - *expected, - actual_signatures, - actual_types, - actual_module_sig - .imports - .iter() - .map(|(module, ty)| (module.as_str(), ty.clone())), - )?; - self.exports_match( - expected_module_sig.exports, - actual_signatures, - actual_types, - |name| actual_instance_sig.exports.get(name).cloned(), - )?; - Ok(()) - } - _ => bail!("expected module, but found {}", actual_desc), - }, - EntityType::Tag(_) => unimplemented!(), - } - } - /// Validates that the `expected` type matches the type of `actual` pub fn extern_(&self, expected: &EntityType, actual: &Extern) -> Result<()> { match expected { @@ -375,14 +171,6 @@ impl MatchCx<'_> { Extern::Func(actual) => self.func(*expected, actual), _ => bail!("expected func, but found {}", actual.desc()), }, - EntityType::Instance(expected) => match actual { - Extern::Instance(actual) => self.instance(*expected, actual), - _ => bail!("expected instance, but found {}", actual.desc()), - }, - EntityType::Module(expected) => match actual { - Extern::Module(actual) => self.module(*expected, actual), - _ => bail!("expected module, but found {}", actual.desc()), - }, EntityType::Tag(_) => unimplemented!(), } } @@ -395,23 +183,6 @@ impl MatchCx<'_> { EntityType::Function(expected) => self.host_func(*expected, f), _ => bail!("expected {}, but found func", entity_desc(expected)), }, - Definition::Instance(items) => match expected { - EntityType::Instance(expected) => { - for (name, expected) in self.types.instance_signatures[*expected].exports.iter() - { - match items.get(name) { - Some(item) => { - self.definition(expected, item).with_context(|| { - format!("instance export {:?} incompatible", name) - })?; - } - None => bail!("instance type missing export {:?}", name), - } - } - Ok(()) - } - _ => bail!("expected {}, but found instance", entity_desc(expected)), - }, } } } @@ -485,8 +256,6 @@ fn entity_desc(ty: &EntityType) -> &'static str { EntityType::Table(_) => "table", EntityType::Memory(_) => "memory", EntityType::Function(_) => "func", - EntityType::Instance(_) => "instance", - EntityType::Module(_) => "module", EntityType::Tag(_) => "tag", } } diff --git a/crates/wast/src/wast.rs b/crates/wast/src/wast.rs index b54ae273dcda..36da72697013 100644 --- a/crates/wast/src/wast.rs +++ b/crates/wast/src/wast.rs @@ -74,7 +74,7 @@ impl WastContext { match module { Some(module) => self .linker - .get(&mut self.store, module, Some(name)) + .get(&mut self.store, module, name) .ok_or_else(|| anyhow!("no item named `{}::{}` found", module, name)), None => self .current diff --git a/src/commands/run.rs b/src/commands/run.rs index b6da5b6556f2..46c180751c50 100644 --- a/src/commands/run.rs +++ b/src/commands/run.rs @@ -336,7 +336,7 @@ impl RunCommand { name: &str, ) -> Result<()> { let func = match linker - .get(&mut *store, "", Some(name)) + .get(&mut *store, "", name) .ok_or_else(|| anyhow!("no export named `{}` found", name))? .into_func() { diff --git a/src/lib.rs b/src/lib.rs index 4da060dd706a..a65ecbb63fd7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -29,10 +29,6 @@ const SUPPORTED_WASM_FEATURES: &[(&str, &str)] = &[ "bulk-memory", "enables support for bulk memory instructions", ), - ( - "module-linking", - "enables support for the module-linking proposal", - ), ( "multi-memory", "enables support for the multi-memory proposal", @@ -374,7 +370,6 @@ impl CommonOptions { threads, multi_memory, memory64, - module_linking, } = self.wasm_features.unwrap_or_default(); if let Some(enable) = simd { @@ -400,9 +395,6 @@ impl CommonOptions { if let Some(enable) = memory64 { config.wasm_memory64(enable); } - if let Some(enable) = module_linking { - config.wasm_module_linking(enable); - } } fn opt_level(&self) -> wasmtime::OptLevel { @@ -432,7 +424,6 @@ struct WasmFeatures { multi_value: Option, bulk_memory: Option, simd: Option, - module_linking: Option, threads: Option, multi_memory: Option, memory64: Option, @@ -480,7 +471,6 @@ fn parse_wasm_features(features: &str) -> Result { reference_types: all.or(values["reference-types"]), multi_value: all.or(values["multi-value"]), bulk_memory: all.or(values["bulk-memory"]), - module_linking: all.or(values["module-linking"]), simd: all.or(values["simd"]), threads: all.or(values["threads"]), multi_memory: all.or(values["multi-memory"]), @@ -583,7 +573,6 @@ mod test { reference_types, multi_value, bulk_memory, - module_linking, simd, threads, multi_memory, @@ -593,7 +582,6 @@ mod test { assert_eq!(reference_types, Some(true)); assert_eq!(multi_value, Some(true)); assert_eq!(bulk_memory, Some(true)); - assert_eq!(module_linking, Some(true)); assert_eq!(simd, Some(true)); assert_eq!(threads, Some(true)); assert_eq!(multi_memory, Some(true)); @@ -610,7 +598,6 @@ mod test { reference_types, multi_value, bulk_memory, - module_linking, simd, threads, multi_memory, @@ -620,7 +607,6 @@ mod test { assert_eq!(reference_types, Some(false)); assert_eq!(multi_value, Some(false)); assert_eq!(bulk_memory, Some(false)); - assert_eq!(module_linking, Some(false)); assert_eq!(simd, Some(false)); assert_eq!(threads, Some(false)); assert_eq!(multi_memory, Some(false)); @@ -640,7 +626,6 @@ mod test { reference_types, multi_value, bulk_memory, - module_linking, simd, threads, multi_memory, @@ -650,7 +635,6 @@ mod test { assert_eq!(reference_types, Some(false)); assert_eq!(multi_value, None); assert_eq!(bulk_memory, None); - assert_eq!(module_linking, None); assert_eq!(simd, Some(true)); assert_eq!(threads, None); assert_eq!(multi_memory, Some(true)); @@ -691,11 +675,6 @@ mod test { ); feature_test!(test_multi_value_feature, multi_value, "multi-value"); feature_test!(test_bulk_memory_feature, bulk_memory, "bulk-memory"); - feature_test!( - test_module_linking_feature, - module_linking, - "module-linking" - ); feature_test!(test_simd_feature, simd, "simd"); feature_test!(test_threads_feature, threads, "threads"); feature_test!(test_multi_memory_feature, multi_memory, "multi-memory"); diff --git a/tests/all/async_functions.rs b/tests/all/async_functions.rs index e4aaf9c6aa62..9c325385dc9e 100644 --- a/tests/all/async_functions.rs +++ b/tests/all/async_functions.rs @@ -50,7 +50,7 @@ fn smoke_host_func() -> Result<()> { linker.func_wrap0_async("", "second", move |_caller| Box::new(async { Ok(()) }))?; let func = linker - .get(&mut store, "", Some("first")) + .get(&mut store, "", "first") .unwrap() .into_func() .unwrap(); @@ -58,7 +58,7 @@ fn smoke_host_func() -> Result<()> { run_smoke_typed_test(&mut store, func); let func = linker - .get(&mut store, "", Some("second")) + .get(&mut store, "", "second") .unwrap() .into_func() .unwrap(); @@ -119,7 +119,7 @@ fn smoke_host_func_with_suspension() -> Result<()> { })?; let func = linker - .get(&mut store, "", Some("first")) + .get(&mut store, "", "first") .unwrap() .into_func() .unwrap(); @@ -127,7 +127,7 @@ fn smoke_host_func_with_suspension() -> Result<()> { run_smoke_typed_test(&mut store, func); let func = linker - .get(&mut store, "", Some("second")) + .get(&mut store, "", "second") .unwrap() .into_func() .unwrap(); @@ -474,11 +474,7 @@ fn async_host_func_with_pooling_stacks() -> Result<()> { move |_caller, _params, _results| Box::new(async { Ok(()) }), )?; - let func = linker - .get(&mut store, "", Some("")) - .unwrap() - .into_func() - .unwrap(); + let func = linker.get(&mut store, "", "").unwrap().into_func().unwrap(); run_smoke_test(&mut store, func); run_smoke_typed_test(&mut store, func); Ok(()) diff --git a/tests/all/custom_signal_handler.rs b/tests/all/custom_signal_handler.rs index 047856c9ed1b..bcaa3fae150b 100644 --- a/tests/all/custom_signal_handler.rs +++ b/tests/all/custom_signal_handler.rs @@ -106,7 +106,7 @@ mod tests { module .imports() .map(|import| { - assert_eq!(Some("hostcall_read"), import.name()); + assert_eq!("hostcall_read", import.name()); let func = Func::wrap(&mut *store, { move |mut caller: Caller<'_, _>| { let mem = caller.get_export("memory").unwrap().into_memory().unwrap(); diff --git a/tests/all/host_funcs.rs b/tests/all/host_funcs.rs index 3af5aa92d6e1..0c33c60a90f8 100644 --- a/tests/all/host_funcs.rs +++ b/tests/all/host_funcs.rs @@ -104,7 +104,7 @@ fn drop_delayed() -> Result<()> { let module = Module::new(&engine, &wat::parse_str(r#"(import "" "" (func))"#)?)?; let mut store = Store::new(&engine, ()); - let func = linker.get(&mut store, "", Some("")).unwrap(); + let func = linker.get(&mut store, "", "").unwrap(); Instance::new(&mut store, &module, &[func])?; drop(store); @@ -112,7 +112,7 @@ fn drop_delayed() -> Result<()> { assert_eq!(HITS.load(SeqCst), 0); let mut store = Store::new(&engine, ()); - let func = linker.get(&mut store, "", Some("")).unwrap(); + let func = linker.get(&mut store, "", "").unwrap(); Instance::new(&mut store, &module, &[func])?; drop(store); @@ -147,7 +147,7 @@ fn signatures_match() -> Result<()> { let mut store = Store::new(&engine, ()); let f = linker - .get(&mut store, "", Some("f1")) + .get(&mut store, "", "f1") .unwrap() .into_func() .unwrap(); @@ -155,7 +155,7 @@ fn signatures_match() -> Result<()> { assert_eq!(f.ty(&store).results().collect::>(), &[]); let f = linker - .get(&mut store, "", Some("f2")) + .get(&mut store, "", "f2") .unwrap() .into_func() .unwrap(); @@ -163,7 +163,7 @@ fn signatures_match() -> Result<()> { assert_eq!(f.ty(&store).results().collect::>(), &[ValType::I32]); let f = linker - .get(&mut store, "", Some("f3")) + .get(&mut store, "", "f3") .unwrap() .into_func() .unwrap(); @@ -171,7 +171,7 @@ fn signatures_match() -> Result<()> { assert_eq!(f.ty(&store).results().collect::>(), &[ValType::I64]); let f = linker - .get(&mut store, "", Some("f4")) + .get(&mut store, "", "f4") .unwrap() .into_func() .unwrap(); @@ -179,7 +179,7 @@ fn signatures_match() -> Result<()> { assert_eq!(f.ty(&store).results().collect::>(), &[ValType::F32]); let f = linker - .get(&mut store, "", Some("f5")) + .get(&mut store, "", "f5") .unwrap() .into_func() .unwrap(); @@ -187,7 +187,7 @@ fn signatures_match() -> Result<()> { assert_eq!(f.ty(&store).results().collect::>(), &[ValType::F64]); let f = linker - .get(&mut store, "", Some("f6")) + .get(&mut store, "", "f6") .unwrap() .into_func() .unwrap(); @@ -448,11 +448,7 @@ fn trap_smoke() -> Result<()> { let mut store = Store::new(&engine, ()); - let f = linker - .get(&mut store, "", Some("")) - .unwrap() - .into_func() - .unwrap(); + let f = linker.get(&mut store, "", "").unwrap().into_func().unwrap(); let err = f .call(&mut store, &[], &mut []) @@ -506,7 +502,7 @@ fn new_from_signature() -> Result<()> { let mut store = Store::new(&engine, ()); let f = linker - .get(&mut store, "", Some("f1")) + .get(&mut store, "", "f1") .unwrap() .into_func() .unwrap(); @@ -515,7 +511,7 @@ fn new_from_signature() -> Result<()> { assert!(f.typed::(&store).is_err()); let f = linker - .get(&mut store, "", Some("f2")) + .get(&mut store, "", "f2") .unwrap() .into_func() .unwrap(); @@ -551,7 +547,7 @@ fn call_wrapped_func() -> Result<()> { let mut store = Store::new(&engine, ()); let f = linker - .get(&mut store, "", Some("f1")) + .get(&mut store, "", "f1") .unwrap() .into_func() .unwrap(); @@ -564,7 +560,7 @@ fn call_wrapped_func() -> Result<()> { .call(&mut store, (1, 2, 3.0, 4.0))?; let f = linker - .get(&mut store, "", Some("f2")) + .get(&mut store, "", "f2") .unwrap() .into_func() .unwrap(); @@ -573,7 +569,7 @@ fn call_wrapped_func() -> Result<()> { assert_eq!(f.typed::<(), i32, _>(&store)?.call(&mut store, ())?, 1); let f = linker - .get(&mut store, "", Some("f3")) + .get(&mut store, "", "f3") .unwrap() .into_func() .unwrap(); @@ -582,7 +578,7 @@ fn call_wrapped_func() -> Result<()> { assert_eq!(f.typed::<(), i64, _>(&store)?.call(&mut store, ())?, 2); let f = linker - .get(&mut store, "", Some("f4")) + .get(&mut store, "", "f4") .unwrap() .into_func() .unwrap(); @@ -591,7 +587,7 @@ fn call_wrapped_func() -> Result<()> { assert_eq!(f.typed::<(), f32, _>(&store)?.call(&mut store, ())?, 3.0); let f = linker - .get(&mut store, "", Some("f5")) + .get(&mut store, "", "f5") .unwrap() .into_func() .unwrap(); @@ -610,11 +606,7 @@ fn func_return_nothing() -> Result<()> { linker.func_new("", "", ty, |_, _, _| Ok(()))?; let mut store = Store::new(&engine, ()); - let f = linker - .get(&mut store, "", Some("")) - .unwrap() - .into_func() - .unwrap(); + let f = linker.get(&mut store, "", "").unwrap().into_func().unwrap(); let err = f .call(&mut store, &[], &mut [Val::I32(0)]) .unwrap_err() @@ -661,11 +653,7 @@ fn call_via_funcref() -> Result<()> { let mut store = Store::new(&engine, ()); let instance = Instance::new(&mut store, &module, &[])?; - let f = linker - .get(&mut store, "", Some("")) - .unwrap() - .into_func() - .unwrap(); + let f = linker.get(&mut store, "", "").unwrap().into_func().unwrap(); let mut results = [Val::I32(0), Val::I32(0)]; instance .get_func(&mut store, "call") @@ -708,11 +696,7 @@ fn store_with_context() -> Result<()> { let mut store = Store::new(&engine, Ctx { called: false }); - let f = linker - .get(&mut store, "", Some("")) - .unwrap() - .into_func() - .unwrap(); + let f = linker.get(&mut store, "", "").unwrap().into_func().unwrap(); f.call(&mut store, &[], &mut [])?; assert!(store.data().called); diff --git a/tests/all/linker.rs b/tests/all/linker.rs index da4929810a5b..c356fedbc990 100644 --- a/tests/all/linker.rs +++ b/tests/all/linker.rs @@ -23,34 +23,6 @@ fn link_undefined() -> Result<()> { Ok(()) } -#[test] -fn undefined_error_message_with_linking() { - let mut config = Config::new(); - config.wasm_module_linking(true); - let engine = Engine::new(&config).unwrap(); - let module = Module::new( - &engine, - r#" - (module - (import "foo" "bar" (func)) - ) - "#, - ) - .unwrap(); - let linker = Linker::new(&engine); - let mut store = Store::new(&engine, ()); - assert!(linker - .instantiate(&mut store, &module) - .unwrap_err() - .to_string() - .contains("foo")); - assert!(linker - .instantiate(&mut store, &module) - .unwrap_err() - .to_string() - .contains("bar")); -} - #[test] fn link_twice_bad() -> Result<()> { let mut store = Store::<()>::default(); @@ -312,7 +284,7 @@ fn funcs_live_on_to_fight_another_day() -> Result<()> { let get_and_call = || -> Result<()> { assert_eq!(flag.load(SeqCst), 0); let mut store = Store::new(&engine, ()); - let func = linker.get(&mut store, "", Some("")).unwrap(); + let func = linker.get(&mut store, "", "").unwrap(); func.into_func().unwrap().call(&mut store, &[], &mut [])?; assert_eq!(flag.load(SeqCst), 0); Ok(()) @@ -332,8 +304,8 @@ fn alias_one() -> Result<()> { assert!(linker.alias("a", "b", "c", "d").is_err()); linker.func_wrap("a", "b", || {})?; assert!(linker.alias("a", "b", "c", "d").is_ok()); - assert!(linker.get(&mut store, "a", Some("b")).is_some()); - assert!(linker.get(&mut store, "c", Some("d")).is_some()); + assert!(linker.get(&mut store, "a", "b").is_some()); + assert!(linker.get(&mut store, "c", "d").is_some()); Ok(()) } diff --git a/tests/all/main.rs b/tests/all/main.rs index 45db806f6cdf..461bf8d84fba 100644 --- a/tests/all/main.rs +++ b/tests/all/main.rs @@ -21,7 +21,6 @@ mod linker; mod memory; mod memory_creator; mod module; -mod module_linking; mod module_serialize; mod name; mod pooling_allocator; diff --git a/tests/all/module_linking.rs b/tests/all/module_linking.rs deleted file mode 100644 index b1418552833e..000000000000 --- a/tests/all/module_linking.rs +++ /dev/null @@ -1,300 +0,0 @@ -use anyhow::Result; -use wasmtime::*; - -fn engine() -> Engine { - let mut config = Config::new(); - config.wasm_module_linking(true); - Engine::new(&config).unwrap() -} - -#[test] -fn compile() -> Result<()> { - let engine = engine(); - Module::new(&engine, "(module (module))")?; - Module::new(&engine, "(module (module) (module))")?; - Module::new(&engine, "(module (module (module)))")?; - Module::new( - &engine, - " - (module - (func) - (module (func)) - (module (func)) - ) - ", - )?; - let m = Module::new( - &engine, - " - (module - (global i32 (i32.const 0)) - (func) - (module (memory 1) (func)) - (module (memory 2) (func)) - (module (table 2 funcref) (func)) - (module (global i64 (i64.const 0)) (func)) - ) - ", - )?; - assert_eq!(m.imports().len(), 0); - assert_eq!(m.exports().len(), 0); - let bytes = m.serialize()?; - unsafe { - Module::deserialize(&engine, &bytes)?; - } - assert_eq!(m.imports().len(), 0); - assert_eq!(m.exports().len(), 0); - Ok(()) -} - -#[test] -fn types() -> Result<()> { - let engine = engine(); - Module::new(&engine, "(module (type (module)))")?; - Module::new(&engine, "(module (type (instance)))")?; - Ok(()) -} - -#[test] -fn imports_exports() -> Result<()> { - let engine = engine(); - - // empty module type - let module = Module::new(&engine, "(module (module (export \"\")))")?; - let mut e = module.exports(); - assert_eq!(e.len(), 1); - let export = e.next().unwrap(); - assert_eq!(export.name(), ""); - let module_ty = match export.ty() { - ExternType::Module(m) => m, - _ => panic!("unexpected type"), - }; - assert_eq!(module_ty.imports().len(), 0); - assert_eq!(module_ty.exports().len(), 0); - - // empty instance type - let module = Module::new( - &engine, - " - (module - (module) - (instance (export \"\") (instantiate 0))) - ", - )?; - let mut e = module.exports(); - assert_eq!(e.len(), 1); - let export = e.next().unwrap(); - assert_eq!(export.name(), ""); - let instance_ty = match export.ty() { - ExternType::Instance(i) => i, - _ => panic!("unexpected type"), - }; - assert_eq!(instance_ty.exports().len(), 0); - - // full module type - let module = Module::new( - &engine, - " - (module - (import \"\" \"a\" (module - (import \"a\" (func)) - (export \"\" (global i32)) - )) - ) - ", - )?; - let mut i = module.imports(); - assert_eq!(i.len(), 1); - let import = i.next().unwrap(); - assert_eq!(import.module(), ""); - assert_eq!(import.name(), None); - let instance_ty = match import.ty() { - ExternType::Instance(t) => t, - _ => panic!("unexpected type"), - }; - assert_eq!(instance_ty.exports().len(), 1); - let module_ty = match instance_ty.exports().next().unwrap().ty() { - ExternType::Module(m) => m, - _ => panic!("unexpected type"), - }; - assert_eq!(module_ty.imports().len(), 1); - assert_eq!(module_ty.exports().len(), 1); - let import = module_ty.imports().next().unwrap(); - assert_eq!(import.module(), "a"); - assert_eq!(import.name(), None); - match import.ty() { - ExternType::Func(f) => { - assert_eq!(f.results().len(), 0); - assert_eq!(f.params().len(), 0); - } - _ => panic!("unexpected type"), - } - let export = module_ty.exports().next().unwrap(); - assert_eq!(export.name(), ""); - match export.ty() { - ExternType::Global(g) => { - assert_eq!(*g.content(), ValType::I32); - assert_eq!(g.mutability(), Mutability::Const); - } - _ => panic!("unexpected type"), - } - - // full instance type - let module = Module::new( - &engine, - " - (module - (import \"\" \"b\" (instance - (export \"m\" (memory 1)) - (export \"t\" (table 1 funcref)) - )) - ) - ", - )?; - let mut i = module.imports(); - assert_eq!(i.len(), 1); - let import = i.next().unwrap(); - assert_eq!(import.module(), ""); - assert_eq!(import.name(), None); - let instance_ty = match import.ty() { - ExternType::Instance(t) => t, - _ => panic!("unexpected type"), - }; - assert_eq!(instance_ty.exports().len(), 1); - let instance_ty = match instance_ty.exports().next().unwrap().ty() { - ExternType::Instance(m) => m, - _ => panic!("unexpected type"), - }; - assert_eq!(instance_ty.exports().len(), 2); - let mem_export = instance_ty.exports().nth(0).unwrap(); - assert_eq!(mem_export.name(), "m"); - match mem_export.ty() { - ExternType::Memory(m) => { - assert_eq!(m.minimum(), 1); - assert_eq!(m.maximum(), None); - } - _ => panic!("unexpected type"), - } - let table_export = instance_ty.exports().nth(1).unwrap(); - assert_eq!(table_export.name(), "t"); - match table_export.ty() { - ExternType::Table(t) => { - assert_eq!(t.minimum(), 1); - assert_eq!(t.maximum(), None); - assert_eq!(t.element(), ValType::FuncRef); - } - _ => panic!("unexpected type"), - } - Ok(()) -} - -#[test] -fn limit_instances() -> Result<()> { - let mut config = Config::new(); - config.wasm_module_linking(true); - let engine = Engine::new(&config)?; - let module = Module::new( - &engine, - r#" - (module $PARENT - (module $m0) - (module $m1 - (instance (instantiate (module outer $PARENT $m0))) - (instance (instantiate (module outer $PARENT $m0)))) - (module $m2 - (instance (instantiate (module outer $PARENT $m1))) - (instance (instantiate (module outer $PARENT $m1)))) - (module $m3 - (instance (instantiate (module outer $PARENT $m2))) - (instance (instantiate (module outer $PARENT $m2)))) - (module $m4 - (instance (instantiate (module outer $PARENT $m3))) - (instance (instantiate (module outer $PARENT $m3)))) - (module $m5 - (instance (instantiate (module outer $PARENT $m4))) - (instance (instantiate (module outer $PARENT $m4)))) - (instance (instantiate $m5)) - ) - "#, - )?; - let mut store = Store::new(&engine, StoreLimitsBuilder::new().instances(10).build()); - store.limiter(|s| s as &mut dyn ResourceLimiter); - let err = Instance::new(&mut store, &module, &[]).err().unwrap(); - assert!( - err.to_string().contains("resource limit exceeded"), - "bad error: {}", - err - ); - Ok(()) -} - -#[test] -fn limit_memories() -> Result<()> { - let mut config = Config::new(); - config.wasm_module_linking(true); - config.wasm_multi_memory(true); - let engine = Engine::new(&config)?; - let module = Module::new( - &engine, - r#" - (module - (module $m0 - (memory 1 1) - (memory 1 1) - (memory 1 1) - (memory 1 1) - (memory 1 1) - ) - - (instance (instantiate $m0)) - (instance (instantiate $m0)) - (instance (instantiate $m0)) - (instance (instantiate $m0)) - ) - "#, - )?; - let mut store = Store::new(&engine, StoreLimitsBuilder::new().memories(10).build()); - store.limiter(|s| s as &mut dyn ResourceLimiter); - let err = Instance::new(&mut store, &module, &[]).err().unwrap(); - assert!( - err.to_string().contains("resource limit exceeded"), - "bad error: {}", - err - ); - Ok(()) -} - -#[test] -fn limit_tables() -> Result<()> { - let mut config = Config::new(); - config.wasm_module_linking(true); - let engine = Engine::new(&config)?; - let module = Module::new( - &engine, - r#" - (module - (module $m0 - (table 1 1 funcref) - (table 1 1 funcref) - (table 1 1 funcref) - (table 1 1 funcref) - (table 1 1 funcref) - ) - - (instance (instantiate $m0)) - (instance (instantiate $m0)) - (instance (instantiate $m0)) - (instance (instantiate $m0)) - ) - "#, - )?; - let mut store = Store::new(&engine, StoreLimitsBuilder::new().tables(10).build()); - store.limiter(|s| s as &mut dyn ResourceLimiter); - let err = Instance::new(&mut store, &module, &[]).err().unwrap(); - assert!( - err.to_string().contains("resource limit exceeded"), - "bad error: {}", - err - ); - Ok(()) -} diff --git a/tests/all/wast.rs b/tests/all/wast.rs index 240a68fb72fb..5d96f21fa5c5 100644 --- a/tests/all/wast.rs +++ b/tests/all/wast.rs @@ -21,13 +21,11 @@ fn run_wast(wast: &str, strategy: Strategy, pooling: bool) -> anyhow::Result<()> let simd = feature_found(wast, "simd"); let memory64 = feature_found(wast, "memory64"); let multi_memory = feature_found(wast, "multi-memory"); - let module_linking = feature_found(wast, "module-linking"); let threads = feature_found(wast, "threads"); let mut cfg = Config::new(); cfg.wasm_simd(simd) - .wasm_multi_memory(multi_memory || module_linking) - .wasm_module_linking(module_linking) + .wasm_multi_memory(multi_memory) .wasm_threads(threads) .wasm_memory64(memory64) .cranelift_debug_verifier(true); diff --git a/tests/misc_testsuite/module-linking/alias-outer.wast b/tests/misc_testsuite/module-linking/alias-outer.wast deleted file mode 100644 index 114c19ff4acb..000000000000 --- a/tests/misc_testsuite/module-linking/alias-outer.wast +++ /dev/null @@ -1,67 +0,0 @@ -(module $a - (module $m1) - (module $b - (module $m2) - (module $c - (instance (instantiate (module outer $a $m1))) - (instance (instantiate (module outer $b $m2))) - ) - (instance (instantiate $c)) - ) - (instance (instantiate $b)) -) - -(module $a - (module (export "m")) -) - -(module $PARENT - (import "a" "m" (module $b)) - (module $c - (module $d - (instance (instantiate (module outer $PARENT $b))) - ) - (instance (instantiate $d)) - ) - (instance (instantiate $c)) -) - -;; Instantiate `$b` here below twice with two different imports. Ensure the -;; exported modules close over the captured state correctly to ensure that we -;; get the right functions. -(module $a - (module $b (export "close_over_imports") - (import "m" (module $m (export "f" (func (result i32))))) - (module (export "m") - (instance $a (instantiate (module outer $b $m))) - (func (export "f") (result i32) - call (func $a "f")) - ) - ) -) - -(module - (import "a" "close_over_imports" (module $m0 - (import "m" (module (export "f" (func (result i32))))) - (export "m" (module (export "f" (func (result i32))))) - )) - - (module $m1 - (func (export "f") (result i32) - i32.const 0)) - (instance $m_g1 (instantiate $m0 (import "m" (module $m1)))) - (instance $g1 (instantiate (module $m_g1 "m"))) - (module $m2 - (func (export "f") (result i32) - i32.const 1)) - (instance $m_g2 (instantiate $m0 (import "m" (module $m2)))) - (instance $g2 (instantiate (module $m_g2 "m"))) - - (func (export "get1") (result i32) - call (func $g1 "f")) - (func (export "get2") (result i32) - call (func $g2 "f")) -) - -(assert_return (invoke "get1") (i32.const 0)) -(assert_return (invoke "get2") (i32.const 1)) diff --git a/tests/misc_testsuite/module-linking/alias.wast b/tests/misc_testsuite/module-linking/alias.wast deleted file mode 100644 index fbcbea5bbb20..000000000000 --- a/tests/misc_testsuite/module-linking/alias.wast +++ /dev/null @@ -1,143 +0,0 @@ -;; functions -(module - (module $m - (func $foo (export "foo") (result i32) - i32.const 1) - ) - (instance $a (instantiate $m)) - - (func (export "get") (result i32) - call (func $a "foo")) -) -(assert_return (invoke "get") (i32.const 1)) - -;; globals -(module - (module $m - (global $g (export "g") (mut i32) (i32.const 2)) - ) - (instance $a (instantiate $m)) - - (func (export "get") (result i32) - global.get (global $a "g")) -) -(assert_return (invoke "get") (i32.const 2)) - -;; memories -(module - (module $m - (memory $m (export "m") 1) - (data (i32.const 0) "\03\00\00\00") - ) - (instance $a (instantiate $m)) - (alias $a "m" (memory $m)) - - (func (export "get") (result i32) - i32.const 0 - i32.load) -) -(assert_return (invoke "get") (i32.const 3)) - -;; tables -(module - (module $m - (table $t (export "t") 1 funcref) - (func (result i32) - i32.const 4) - (elem (i32.const 0) 0) - ) - (instance $a (instantiate $m)) - - (func (export "get") (result i32) - i32.const 0 - call_indirect (table $a "t") (result i32)) -) -(assert_return (invoke "get") (i32.const 4)) - -;; modules -(module - (module $m - (module $sub (export "module") - (func $f (export "") (result i32) - i32.const 5)) - ) - (instance $a (instantiate $m)) - (instance $b (instantiate (module $a "module"))) - - (func (export "get") (result i32) - call (func $b "")) -) -(assert_return (invoke "get") (i32.const 5)) - -;; instances -(module - (module $m - (module $sub - (func $f (export "") (result i32) - i32.const 6)) - (instance $i (export "") (instantiate $sub)) - ) - (instance $a (instantiate $m)) - - (func (export "get") (result i32) - call (func $a "" "")) -) -(assert_return (invoke "get") (i32.const 6)) - -;; alias parent -- type -(module - (type $t (func)) - (module $m - (func $f (type outer 0 $t)) - ) - (instance $a (instantiate $m)) -) - -;; alias outer -- module -(module - (module $a) - (module $m - (instance (instantiate (module outer 0 $a))) - ) - (instance (instantiate $m)) -) - -;; The alias, import, type, module, and instance sections can all be interleaved -(module $ROOT - (module $a) - (type $t (func)) - (module $m - ;; alias - (alias outer 0 $t (type $thunk)) - ;; import - (import "" "" (func (type $thunk))) - ;; module (referencing parent type) - (module - (func (type outer $m $thunk)) - (func (type outer $ROOT $t)) - ) - ;; type - (type $thunk2 (func)) - ;; module (referencing previous alias) - (module $m2 - (func (export "") (type outer $m $thunk2)) - ) - ;; instance - (instance $i (instantiate $m2)) - ;; alias that instance - (alias $i "" (func $my_f)) - ;; module - (module $m3 - (import "" (func))) - ;; use our aliased function to create the module - (instance $i2 (instantiate $m3 (import "" (func $my_f)))) - ;; module - (module $m4 - (import "" (func))) - ) - - ;; instantiate the above module - (module $smol (func $f (export ""))) - (instance $smol (instantiate $smol)) - (instance (instantiate $m (import "" (instance $smol)))) -) diff --git a/tests/misc_testsuite/module-linking/import-subtyping.wast b/tests/misc_testsuite/module-linking/import-subtyping.wast deleted file mode 100644 index 2055f848f322..000000000000 --- a/tests/misc_testsuite/module-linking/import-subtyping.wast +++ /dev/null @@ -1,431 +0,0 @@ -;; subsets of imports -(module $a - (module (export "m") - (func (export "")) - (func (export "a")) - (global (export "b") i32 (i32.const 0)) - ) -) - -(module - (import "a" "m" (module)) -) -(module - (import "a" "m" (module (export "" (func)))) -) -(module - (import "a" "m" (module (export "a" (func)))) -) -(module - (import "a" "m" (module (export "b" (global i32)))) -) -(module - (import "a" "m" (module - (export "" (func)) - (export "a" (func)) - )) -) -(module - (import "a" "m" (module - (export "a" (func)) - (export "" (func)) - )) -) -(module - (import "a" "m" (module - (export "a" (func)) - (export "" (func)) - (export "b" (global i32)) - )) -) -(module - (import "a" "m" (module - (export "b" (global i32)) - (export "a" (func)) - (export "" (func)) - )) -) - -;; functions -(module $a - (module (export "m") - (func (export "")))) - -(module (import "a" "m" (module))) -(module (import "a" "m" (module (export "" (func))))) -(assert_unlinkable - (module (import "a" "m" (module (export "" (func (param i32)))))) - "incompatible import type for `a`") -(assert_unlinkable - (module (import "a" "m" (module (export "" (func (result i32)))))) - "incompatible import type for `a`") -(assert_unlinkable - (module (import "a" "m" (module (export "" (global i32))))) - "incompatible import type for `a`") -(assert_unlinkable - (module (import "a" "m" (module (export "" (table 1 funcref))))) - "incompatible import type for `a`") -(assert_unlinkable - (module (import "a" "m" (module (export "" (memory 1))))) - "incompatible import type for `a`") -(assert_unlinkable - (module (import "a" "m" (module (export "" (module))))) - "incompatible import type for `a`") -(assert_unlinkable - (module (import "a" "m" (module (export "" (instance))))) - "incompatible import type for `a`") - -(module $a - (module (export "m") - (global (export "") i32 (i32.const 0)))) - -;; globals -(module (import "a" "m" (module))) -(module (import "a" "m" (module (export "" (global i32))))) -(assert_unlinkable - (module - (import "a" "m" (module (export "" (global (mut i32))))) - ) - "incompatible import type for `a`") -(assert_unlinkable - (module (import "a" "m" (module (export "" (global f32))))) - "incompatible import type for `a`") -(assert_unlinkable - (module (import "a" "m" (module (export "" (func))))) - "incompatible import type for `a`") -(assert_unlinkable - (module (import "a" "m" (module (export "" (table 1 funcref))))) - "incompatible import type for `a`") -(assert_unlinkable - (module (import "a" "m" (module (export "" (memory 1))))) - "incompatible import type for `a`") -(assert_unlinkable - (module (import "a" "m" (module (export "" (module))))) - "incompatible import type for `a`") -(assert_unlinkable - (module (import "a" "m" (module (export "" (instance))))) - "incompatible import type for `a`") - -;; tables -(module $a - (module (export "m") - (table (export "") 1 funcref) - (table (export "max") 1 10 funcref) - ) -) -(module - (import "a" "m" (module)) -) -(module - (import "a" "m" (module (export "" (table 1 funcref)))) -) -(module - (import "a" "m" (module (export "" (table 0 funcref)))) -) -(module - (import "a" "m" (module (export "max" (table 1 10 funcref)))) -) -(module - (import "a" "m" (module (export "max" (table 0 10 funcref)))) -) -(module - (import "a" "m" (module (export "max" (table 0 11 funcref)))) -) -(module - (import "a" "m" (module (export "max" (table 0 funcref)))) -) -(assert_unlinkable - (module (import "a" "m" (module (export "" (global f32))))) - "incompatible import type for `a`") -(assert_unlinkable - (module (import "a" "m" (module (export "" (func))))) - "incompatible import type for `a`") -(assert_unlinkable - (module (import "a" "m" (module (export "" (table 2 funcref))))) - "incompatible import type for `a`") -(assert_unlinkable - (module (import "a" "m" (module (export "" (table 1 10 funcref))))) - "incompatible import type for `a`") -(assert_unlinkable - (module (import "a" "m" (module (export "max" (table 2 10 funcref))))) - "incompatible import type for `a`") -(assert_unlinkable - (module (import "a" "m" (module (export "max" (table 1 9 funcref))))) - "incompatible import type for `a`") -(assert_unlinkable - (module (import "a" "m" (module (export "" (memory 1))))) - "incompatible import type for `a`") -(assert_unlinkable - (module (import "a" "m" (module (export "" (module))))) - "incompatible import type for `a`") -(assert_unlinkable - (module (import "a" "m" (module (export "" (instance))))) - "incompatible import type for `a`") - -;; memories -(module $a - (module (export "m") - (memory (export "") 1) - (memory (export "max") 1 10) - ) -) -(module - (import "a" "m" (module)) -) -(module - (import "a" "m" (module (export "" (memory 1)))) -) -(module - (import "a" "m" (module (export "" (memory 0)))) -) -(module - (import "a" "m" (module (export "max" (memory 1 10)))) -) -(module - (import "a" "m" (module (export "max" (memory 0 10)))) -) -(module - (import "a" "m" (module (export "max" (memory 0 11)))) -) -(module - (import "a" "m" (module (export "max" (memory 0)))) -) -(assert_unlinkable - (module (import "a" "m" (module (export "" (global f32))))) - "incompatible import type for `a`") -(assert_unlinkable - (module (import "a" "m" (module (export "" (func))))) - "incompatible import type for `a`") -(assert_unlinkable - (module (import "a" "m" (module (export "" (table 1 funcref))))) - "incompatible import type for `a`") -(assert_unlinkable - (module (import "a" "m" (module (export "" (memory 2))))) - "incompatible import type for `a`") -(assert_unlinkable - (module (import "a" "m" (module (export "" (memory 1 10))))) - "incompatible import type for `a`") -(assert_unlinkable - (module (import "a" "m" (module (export "max" (memory 2 10))))) - "incompatible import type for `a`") -(assert_unlinkable - (module (import "a" "m" (module (export "max" (memory 2))))) - "incompatible import type for `a`") -(assert_unlinkable - (module (import "a" "m" (module (export "" (module))))) - "incompatible import type for `a`") -(assert_unlinkable - (module (import "a" "m" (module (export "" (instance))))) - "incompatible import type for `a`") - -;; modules -(module $a - (module (export "m") - ;; export nothing - (module (export "a")) - ;; export one thing - (module (export "b") - (func (export "")) - ) - ;; export a mixture - (module (export "c") - (func (export "a")) - (func (export "b") (result i32) - i32.const 0) - (global (export "c") i32 (i32.const 0)) - ) - ;; import one thing - (module (export "d") - (import "" (func)) - ) - ;; import a mixture - (module (export "e") - (import "a" (func)) - (import "b" (func)) - (import "c" (global i32)) - ) - ) -) -(module - (import "a" "m" (module)) -) -(module - (import "a" "m" (module (export "a" (module)))) -) -(module - (import "a" "m" (module (export "b" (module)))) -) -(module - (import "a" "m" (module (export "b" (module (export "" (func)))))) -) -(module - (import "a" "m" (module (export "c" (module)))) -) -(module - (import "a" "m" (module (export "c" (module - (export "a" (func)) - )))) -) -(module - (import "a" "m" (module (export "c" (module - (export "a" (func)) - (export "b" (func (result i32))) - )))) -) -(module - (import "a" "m" (module (export "c" (module - (export "c" (global i32)) - )))) -) -(module - (import "a" "m" (module (export "c" (module - (export "c" (global i32)) - (export "a" (func)) - )))) -) -(module - (import "a" "m" (module (export "d" (module - (import "" (func)) - (import "a" (func)) - )))) -) -(module - (import "a" "m" (module (export "d" (module (import "" (func)))))) -) -(assert_unlinkable - (module - (import "a" "m" (module (export "d" (module (import "x" (func)))))) - ) - "incompatible import type for `a`") -(assert_unlinkable - (module - (import "a" "m" (module (export "d" (module (import "x" "y" (func)))))) - ) - "incompatible import type for `a`") -(module - (import "a" "m" (module (export "e" (module - (import "a" (func)) - (import "b" (func)) - (import "c" (global i32)) - )))) -) -(assert_unlinkable - (module (import "a" "m" (module (export "" (module (export "a" (func))))))) - "incompatible import type for `a`") -(assert_unlinkable - (module (import "a" "m" (module (export "d" (module))))) - "incompatible import type for `a`") -(assert_unlinkable - (module (import "a" "m" (module (export "d" (module (import "" (module))))))) - "incompatible import type for `a`") -(assert_unlinkable - (module (import "a" "m" (module (export "" (global f32))))) - "incompatible import type for `a`") -(assert_unlinkable - (module (import "a" "m" (module (export "" (func))))) - "incompatible import type for `a`") -(assert_unlinkable - (module (import "a" "m" (module (export "" (table 1 funcref))))) - "incompatible import type for `a`") -(assert_unlinkable - (module (import "a" "m" (module (export "" (memory 2))))) - "incompatible import type for `a`") -(assert_unlinkable - (module (import "a" "m" (module (export "" (module (export "foo" (func))))))) - "incompatible import type for `a`") -(assert_unlinkable - (module (import "a" "m" (module (export "" (instance))))) - "incompatible import type for `a`") - -;; instances -(module $a - ;; export nothing - (module $m1) - (instance (export "a") (instantiate $m1)) - ;; export one thing - (module $m2 - (func (export "")) - ) - (instance (export "b") (instantiate $m2)) - ;; export a mixture - (module $m3 - (func (export "a")) - (func (export "b") (result i32) - i32.const 0) - (global (export "c") i32 (i32.const 0)) - ) - (instance (export "c") (instantiate $m3)) - - (module (export "m") - ;; export one thing - (module $m2 - (func (export "")) - ) - (instance (export "i") (instantiate $m2)) - ) - -) -(module - (import "a" "a" (instance)) -) -(module - (import "a" "b" (instance)) -) -(module - (import "a" "b" (instance (export "" (func)))) -) -(module - (import "a" "c" (instance)) -) -(module - (import "a" "c" (instance (export "a" (func)))) -) -(module - (import "a" "c" (instance (export "b" (func (result i32))))) -) -(module - (import "a" "c" (instance (export "c" (global i32)))) -) -(module - (import "a" "c" (instance - (export "a" (func)) - (export "b" (func (result i32))) - (export "c" (global i32)) - )) -) -(module - (import "a" "c" (instance - (export "c" (global i32)) - (export "a" (func)) - )) -) -(module - (import "a" "m" (module (export "i" (instance)))) -) -(module - (import "a" "m" (module (export "i" (instance (export "" (func)))))) -) -(assert_unlinkable - (module (import "a" "a" (instance (export "" (global f32))))) - "incompatible import type for `a`") -(assert_unlinkable - (module (import "a" "m" (module (export "i" (instance (export "x" (func))))))) - "incompatible import type for `a`") -(assert_unlinkable - (module (import "a" "m" (module (export "" (func))))) - "incompatible import type for `a`") -(assert_unlinkable - (module (import "a" "m" (module (export "" (table 1 funcref))))) - "incompatible import type for `a`") -(assert_unlinkable - (module (import "a" "m" (module (export "" (memory 2))))) - "incompatible import type for `a`") -(assert_unlinkable - (module (import "a" "m" (module (export "" (memory 1 10))))) - "incompatible import type for `a`") -(assert_unlinkable - (module (import "a" "m" (module (export "max" (memory 2 10))))) - "incompatible import type for `a`") -(assert_unlinkable - (module (import "a" "m" (module (export "" (module))))) - "incompatible import type for `a`") diff --git a/tests/misc_testsuite/module-linking/instantiate.wast b/tests/misc_testsuite/module-linking/instantiate.wast deleted file mode 100644 index 6e2e04628e0e..000000000000 --- a/tests/misc_testsuite/module-linking/instantiate.wast +++ /dev/null @@ -1,308 +0,0 @@ -(module - (module) - (instance $a (instantiate 0)) -) - -(module $a - (global (export "global") (mut i32) (i32.const 0)) - - (func (export "reset") - i32.const 0 - global.set 0) - - (func $set (export "inc") - i32.const 1 - global.get 0 - i32.add - global.set 0) - - (func (export "get") (result i32) - global.get 0) - - (func (export "load") (result i32) - i32.const 0 - i32.load) - - (memory (export "memory") 1) - (table (export "table") 1 funcref) - (elem (i32.const 0) $set) -) - -;; Imported functions work -(module - (import "a" "inc" (func $set)) - (module - (import "" (func)) - (start 0)) - (instance $a (instantiate 0 (import "" (func $set)))) -) - -(assert_return (invoke $a "get") (i32.const 1)) - -;; Imported globals work -(module - (import "a" "global" (global $g (mut i32))) - (module - (import "" (global (mut i32))) - (func - i32.const 2 - global.set 0) - (start 0)) - - (instance $a (instantiate 0 (import "" (global $g)))) -) -(assert_return (invoke $a "get") (i32.const 2)) - -;; Imported tables work -(module - (import "a" "table" (table $t 1 funcref)) - (module - (import "" (table 1 funcref)) - (func - i32.const 0 - call_indirect) - (start 0)) - - (instance $a (instantiate 0 (import "" (table $t)))) -) -(assert_return (invoke $a "get") (i32.const 3)) - -;; Imported memories work -(module - (import "a" "memory" (memory $m 1)) - (module - (import "" (memory 1)) - (func - i32.const 0 - i32.const 100 - i32.store) - (start 0)) - - (instance $a (instantiate 0 (import "" (memory $m)))) -) -(assert_return (invoke $a "load") (i32.const 100)) - -;; Imported instances work -(module - (import "a" "inc" (func $set)) - - (module $m1 - (import "" (instance (export "" (func)))) - (alias 0 "" (func)) - (start 0)) - - (module $m2 - (func (export "") (import ""))) - (instance $i (instantiate $m2 (import "" (func $set)))) - (instance (instantiate $m1 (import "" (instance $i)))) -) -(assert_return (invoke $a "get") (i32.const 4)) - -;; Imported modules work -(module - (import "a" "inc" (func $set)) - - (module $m1 - (import "" (module $m (export "" (func $f (result i32))))) - (instance $i (instantiate $m)) - (func $get (export "") (result i32) - call (func $i ""))) - - (module $m2 - (func (export "") (result i32) - i32.const 5)) - (instance $i (instantiate $m1 (import "" (module $m2)))) - (func (export "get") (result i32) - call (func $i "")) -) -(assert_return (invoke "get") (i32.const 5)) - -;; imported modules again -(module - (module $m - (import "" (module $m (export "get" (func (result i32))))) - (instance $i (instantiate $m)) - (alias $i "get" (func $f)) - (export "" (func $f)) - ) - (module $m2 - (func (export "get") (result i32) - i32.const 6)) - (instance $a (instantiate $m (import "" (module $m2)))) - - (func (export "get") (result i32) - call (func $a "")) -) -(assert_return (invoke "get") (i32.const 6)) - -;; all at once -(module - (import "a" "inc" (func $f)) - (import "a" "global" (global $g (mut i32))) - (import "a" "table" (table $t 1 funcref)) - (import "a" "memory" (memory $m 1)) - - (module - (import "m" (memory 1)) - (import "g" (global (mut i32))) - (import "t" (table 1 funcref)) - (import "f" (func)) - (func $start - call 0 - - i32.const 0 - i32.const 4 - i32.store - - i32.const 0 - call_indirect - - global.get 0 - global.set 0) - (start $start)) - - (instance $a - (instantiate 0 - (import "m" (memory $m)) - (import "g" (global $g)) - (import "t" (table $t)) - (import "f" (func $f)) - ) - ) -) - -;; instantiate lots -(module - (import "a" "inc" (func $f)) - (import "a" "global" (global $g (mut i32))) - (import "a" "table" (table $t 1 funcref)) - (import "a" "memory" (memory $m 1)) - - (module $mm (import "" (memory 1))) - (module $mf (import "" (func))) - (module $mt (import "" (table 1 funcref))) - (module $mg (import "" (global (mut i32)))) - - (instance (instantiate $mm (import "" (memory $m)))) - (instance (instantiate $mf (import "" (func $f)))) - (instance (instantiate $mt (import "" (table $t)))) - (instance (instantiate $mg (import "" (global $g)))) -) - -;; instantiate nested -(assert_return (invoke $a "reset")) -(assert_return (invoke $a "get") (i32.const 0)) -(module - (import "a" "inc" (func)) - (module - (import "" (func)) - (module - (import "" (func)) - (module - (import "" (func)) - (module - (import "" (func)) - (start 0) - ) - (instance (instantiate 0 (import "" (func 0)))) - ) - (instance (instantiate 0 (import "" (func 0)))) - ) - (instance (instantiate 0 (import "" (func 0)))) - ) - (instance (instantiate 0 (import "" (func 0)))) -) -(assert_return (invoke $a "get") (i32.const 1)) - -;; module/instance top-level imports work -(module $b - (module (export "m")) - (instance (export "i") (instantiate 0)) -) -(module (import "b" "m" (module))) -(module (import "b" "m" (module (import "" (func))))) -(module (import "b" "i" (instance))) -(assert_unlinkable - (module - (import "b" "i" (instance (export "" (func)))) - ) - "incompatible import type") - -;; ensure we ignore other exported items -(module $b - (module $m - (func (export "f") (result i32) - i32.const 300) - (global (export "g") i32 (i32.const 0xfeed)) - ) - - (instance (export "i") (instantiate 0)) -) -(module - (import "b" "i" (instance $i - (export "g" (global $g i32)) - )) - - (func (export "get") (result i32) - global.get (global $i "g")) -) -(assert_return (invoke "get") (i32.const 0xfeed)) - -;; ensure the right export is used even when subtyping comes into play -(module $b - (module $m - (func (export "f") (result i32) - i32.const 300) - (func (export "g") (param i32) (result i32) - i32.const 100 - local.get 0 - i32.add) - ) - - (instance (export "i") (instantiate 0)) -) -(module - (import "b" "i" (instance $i - ;; notice that this order is swapped - (export "g" (func (param i32) (result i32))) - (export "f" (func (result i32))) - )) - - (func (export "f") (result i32) - call (func $i "f")) - (func (export "g") (param i32) (result i32) - local.get 0 - call (func $i "g")) -) -(assert_return (invoke "f") (i32.const 300)) -(assert_return (invoke "g" (i32.const 3000)) (i32.const 3100)) - -(module $a - (func (export "f"))) - -(module - (import "a" "f" (func)) - - (module $m1 - (import "a" "f" (func))) - (instance (instantiate $m1 (import "a" (instance 0)))) -) - -(module - (import "a" "f" (func)) - - ;; this module provides nothing - (module $m1) - - ;; this module imports a module which it says imports something - (module $m2 - (module $a - (func (export ""))) - (instance $i (instantiate $a)) - (import "m" (module $b (import "" (func)))) - (instance $b (instantiate $b (import "" (func $i ""))))) - - ;; we should be able to instantiate m2 with m1 because m1 doesn't actually - ;; import anything (always safe to remove imports!) - (instance (instantiate $m2 (import "m" (module $m1)))) -)