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)))) -)