diff --git a/cranelift/wasm/src/code_translator.rs b/cranelift/wasm/src/code_translator.rs index fcd68e51e5..dedc4dbae5 100644 --- a/cranelift/wasm/src/code_translator.rs +++ b/cranelift/wasm/src/code_translator.rs @@ -77,7 +77,7 @@ use crate::state::{ControlStackFrame, ElseData, FuncTranslationState}; use crate::translation_utils::{ block_with_params, blocktype_params_results, f32_translation, f64_translation, }; -use crate::translation_utils::{FuncIndex, GlobalIndex, MemoryIndex, SignatureIndex, TableIndex}; +use crate::translation_utils::{FuncIndex, GlobalIndex, MemoryIndex, TableIndex, TypeIndex}; use crate::wasm_unsupported; use core::convert::TryInto; use core::{i32, u32}; @@ -587,7 +587,7 @@ pub fn translate_operator( builder.cursor(), TableIndex::from_u32(*table_index), table, - SignatureIndex::from_u32(*index), + TypeIndex::from_u32(*index), sigref, callee, state.peekn(num_args), diff --git a/cranelift/wasm/src/environ/dummy.rs b/cranelift/wasm/src/environ/dummy.rs index 7a064e62d1..d0b59ee6ab 100644 --- a/cranelift/wasm/src/environ/dummy.rs +++ b/cranelift/wasm/src/environ/dummy.rs @@ -12,7 +12,7 @@ use crate::environ::{ use crate::func_translator::FuncTranslator; use crate::translation_utils::{ DataIndex, DefinedFuncIndex, ElemIndex, FuncIndex, Global, GlobalIndex, Memory, MemoryIndex, - SignatureIndex, Table, TableIndex, + Table, TableIndex, TypeIndex, }; use core::convert::TryFrom; use cranelift_codegen::cursor::FuncCursor; @@ -58,7 +58,7 @@ pub struct DummyModuleInfo { config: TargetFrontendConfig, /// Signatures as provided by `declare_signature`. - pub signatures: PrimaryMap, + pub signatures: PrimaryMap, /// Module and field names of imported functions as provided by `declare_func_import`. pub imported_funcs: Vec<(String, String)>, @@ -73,7 +73,7 @@ pub struct DummyModuleInfo { pub imported_memories: Vec<(String, String)>, /// Functions, imported and local. - pub functions: PrimaryMap>, + pub functions: PrimaryMap>, /// Function bodies. pub function_bodies: PrimaryMap, @@ -157,7 +157,7 @@ impl DummyEnvironment { DummyFuncEnvironment::new(&self.info, self.return_mode) } - fn get_func_type(&self, func_index: FuncIndex) -> SignatureIndex { + fn get_func_type(&self, func_index: FuncIndex) -> TypeIndex { self.info.functions[func_index].entity } @@ -190,7 +190,7 @@ impl<'dummy_environment> DummyFuncEnvironment<'dummy_environment> { // Create a signature for `sigidx` amended with a `vmctx` argument after the standard wasm // arguments. - fn vmctx_sig(&self, sigidx: SignatureIndex) -> ir::Signature { + fn vmctx_sig(&self, sigidx: TypeIndex) -> ir::Signature { let mut sig = self.mod_info.signatures[sigidx].clone(); sig.params.push(ir::AbiParam::special( self.pointer_type(), @@ -283,7 +283,7 @@ impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environ fn make_indirect_sig( &mut self, func: &mut ir::Function, - index: SignatureIndex, + index: TypeIndex, ) -> WasmResult { // A real implementation would probably change the calling convention and add `vmctx` and // signature index arguments. @@ -312,7 +312,7 @@ impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environ mut pos: FuncCursor, _table_index: TableIndex, _table: ir::Table, - _sig_index: SignatureIndex, + _sig_index: TypeIndex, sig_ref: ir::SigRef, callee: ir::Value, call_args: &[ir::Value], @@ -572,14 +572,14 @@ impl TargetEnvironment for DummyEnvironment { } impl<'data> ModuleEnvironment<'data> for DummyEnvironment { - fn declare_signature(&mut self, _wasm: WasmFuncType, sig: ir::Signature) -> WasmResult<()> { + fn declare_type_func(&mut self, _wasm: WasmFuncType, sig: ir::Signature) -> WasmResult<()> { self.info.signatures.push(sig); Ok(()) } fn declare_func_import( &mut self, - sig_index: SignatureIndex, + index: TypeIndex, module: &'data str, field: &'data str, ) -> WasmResult<()> { @@ -588,15 +588,15 @@ impl<'data> ModuleEnvironment<'data> for DummyEnvironment { self.info.imported_funcs.len(), "Imported functions must be declared first" ); - self.info.functions.push(Exportable::new(sig_index)); + self.info.functions.push(Exportable::new(index)); self.info .imported_funcs .push((String::from(module), String::from(field))); Ok(()) } - fn declare_func_type(&mut self, sig_index: SignatureIndex) -> WasmResult<()> { - self.info.functions.push(Exportable::new(sig_index)); + fn declare_func_type(&mut self, index: TypeIndex) -> WasmResult<()> { + self.info.functions.push(Exportable::new(index)); Ok(()) } diff --git a/cranelift/wasm/src/environ/spec.rs b/cranelift/wasm/src/environ/spec.rs index b01cd43764..149e55d6dc 100644 --- a/cranelift/wasm/src/environ/spec.rs +++ b/cranelift/wasm/src/environ/spec.rs @@ -8,8 +8,8 @@ use crate::state::FuncTranslationState; use crate::translation_utils::{ - DataIndex, ElemIndex, FuncIndex, Global, GlobalIndex, Memory, MemoryIndex, SignatureIndex, - Table, TableIndex, + DataIndex, ElemIndex, EntityType, FuncIndex, Global, GlobalIndex, Memory, MemoryIndex, Table, + TableIndex, TypeIndex, }; use core::convert::From; use core::convert::TryFrom; @@ -293,7 +293,7 @@ pub trait FuncEnvironment: TargetEnvironment { fn make_indirect_sig( &mut self, func: &mut ir::Function, - index: SignatureIndex, + index: TypeIndex, ) -> WasmResult; /// Set up an external function definition in the preamble of `func` that can be used to @@ -328,7 +328,7 @@ pub trait FuncEnvironment: TargetEnvironment { pos: FuncCursor, table_index: TableIndex, table: ir::Table, - sig_index: SignatureIndex, + sig_index: TypeIndex, sig_ref: ir::SigRef, callee: ir::Value, call_args: &[ir::Value], @@ -630,19 +630,35 @@ pub trait FuncEnvironment: TargetEnvironment { /// [`translate_module`](fn.translate_module.html) function. These methods should not be called /// by the user, they are only for `cranelift-wasm` internal use. pub trait ModuleEnvironment<'data>: TargetEnvironment { - /// Provides the number of signatures up front. By default this does nothing, but + /// Provides the number of types up front. By default this does nothing, but /// implementations can use this to preallocate memory if desired. - fn reserve_signatures(&mut self, _num: u32) -> WasmResult<()> { + fn reserve_types(&mut self, _num: u32) -> WasmResult<()> { Ok(()) } /// Declares a function signature to the environment. - fn declare_signature( + fn declare_type_func( &mut self, wasm_func_type: WasmFuncType, sig: ir::Signature, ) -> WasmResult<()>; + /// Declares a module type signature to the environment. + fn declare_type_module( + &mut self, + imports: &[(&'data str, Option<&'data str>, EntityType)], + exports: &[(&'data str, EntityType)], + ) -> WasmResult<()> { + drop((imports, exports)); + Err(WasmError::Unsupported("module linking".to_string())) + } + + /// Declares an instance type signature to the environment. + fn declare_type_instance(&mut self, exports: &[(&'data str, EntityType)]) -> WasmResult<()> { + drop(exports); + 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<()> { @@ -652,7 +668,7 @@ pub trait ModuleEnvironment<'data>: TargetEnvironment { /// Declares a function import to the environment. fn declare_func_import( &mut self, - sig_index: SignatureIndex, + index: TypeIndex, module: &'data str, field: &'data str, ) -> WasmResult<()>; @@ -681,6 +697,28 @@ pub trait ModuleEnvironment<'data>: TargetEnvironment { field: &'data str, ) -> WasmResult<()>; + /// Declares a module import to the environment. + fn declare_module_import( + &mut self, + ty_index: TypeIndex, + module: &'data str, + field: &'data str, + ) -> WasmResult<()> { + drop((ty_index, module, field)); + 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: &'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(()) @@ -693,7 +731,7 @@ pub trait ModuleEnvironment<'data>: TargetEnvironment { } /// Declares the type (signature) of a local function in the module. - fn declare_func_type(&mut self, sig_index: SignatureIndex) -> WasmResult<()>; + fn declare_func_type(&mut self, index: TypeIndex) -> WasmResult<()>; /// Provides the number of defined tables up front. By default this does nothing, but /// implementations can use this to preallocate memory if desired. diff --git a/cranelift/wasm/src/lib.rs b/cranelift/wasm/src/lib.rs index cbc4a51861..748ccc211c 100644 --- a/cranelift/wasm/src/lib.rs +++ b/cranelift/wasm/src/lib.rs @@ -65,11 +65,7 @@ pub use crate::func_translator::FuncTranslator; pub use crate::module_translator::translate_module; pub use crate::state::func_state::FuncTranslationState; pub use crate::state::module_state::ModuleTranslationState; -pub use crate::translation_utils::{ - get_vmctx_value_label, DataIndex, DefinedFuncIndex, DefinedGlobalIndex, DefinedMemoryIndex, - DefinedTableIndex, ElemIndex, FuncIndex, Global, GlobalIndex, GlobalInit, Memory, MemoryIndex, - SignatureIndex, Table, TableElementType, TableIndex, -}; +pub use crate::translation_utils::*; pub use cranelift_frontend::FunctionBuilder; // Convenience reexport of the wasmparser crate that we're linking against, diff --git a/cranelift/wasm/src/sections_translator.rs b/cranelift/wasm/src/sections_translator.rs index a2bb649557..842839979d 100644 --- a/cranelift/wasm/src/sections_translator.rs +++ b/cranelift/wasm/src/sections_translator.rs @@ -10,8 +10,8 @@ use crate::environ::{ModuleEnvironment, WasmError, WasmResult}; use crate::state::ModuleTranslationState; use crate::translation_utils::{ - tabletype_to_type, type_to_type, DataIndex, ElemIndex, FuncIndex, Global, GlobalIndex, - GlobalInit, Memory, MemoryIndex, SignatureIndex, Table, TableElementType, TableIndex, + tabletype_to_type, type_to_type, DataIndex, ElemIndex, EntityType, FuncIndex, Global, + GlobalIndex, GlobalInit, Memory, MemoryIndex, Table, TableElementType, TableIndex, TypeIndex, }; use crate::wasm_unsupported; use core::convert::TryFrom; @@ -27,18 +27,71 @@ use wasmparser::{ ElementSectionReader, Export, ExportSectionReader, ExternalKind, FunctionSectionReader, GlobalSectionReader, GlobalType, ImportSectionEntryType, ImportSectionReader, MemorySectionReader, MemoryType, NameSectionReader, Naming, Operator, TableSectionReader, - TypeDef, TypeSectionReader, + TableType, TypeDef, TypeSectionReader, }; +fn entity_type( + ty: ImportSectionEntryType, + environ: &mut dyn ModuleEnvironment<'_>, +) -> WasmResult { + Ok(match ty { + ImportSectionEntryType::Function(sig) => EntityType::Function(TypeIndex::from_u32(sig)), + ImportSectionEntryType::Module(sig) => EntityType::Module(TypeIndex::from_u32(sig)), + ImportSectionEntryType::Instance(sig) => EntityType::Instance(TypeIndex::from_u32(sig)), + ImportSectionEntryType::Memory(ty) => EntityType::Memory(memory(ty)), + ImportSectionEntryType::Global(ty) => { + EntityType::Global(global(ty, environ, GlobalInit::Import)?) + } + ImportSectionEntryType::Table(ty) => EntityType::Table(table(ty, environ)?), + }) +} + +fn memory(ty: MemoryType) -> Memory { + match ty { + MemoryType::M32 { limits, shared } => Memory { + minimum: limits.initial, + maximum: limits.maximum, + shared: shared, + }, + // FIXME(#2361) + MemoryType::M64 { .. } => unimplemented!(), + } +} + +fn table(ty: TableType, environ: &mut dyn ModuleEnvironment<'_>) -> WasmResult { + Ok(Table { + wasm_ty: ty.element_type.try_into()?, + ty: match tabletype_to_type(ty.element_type, environ)? { + Some(t) => TableElementType::Val(t), + None => TableElementType::Func, + }, + minimum: ty.limits.initial, + maximum: ty.limits.maximum, + }) +} + +fn global( + ty: GlobalType, + environ: &mut dyn ModuleEnvironment<'_>, + initializer: GlobalInit, +) -> WasmResult { + Ok(Global { + wasm_ty: ty.content_type.try_into()?, + ty: type_to_type(ty.content_type, environ).unwrap(), + mutability: ty.mutable, + initializer, + }) +} + /// Parses the Type section of the wasm module. -pub fn parse_type_section( - types: TypeSectionReader, +pub fn parse_type_section<'a>( + types: TypeSectionReader<'a>, module_translation_state: &mut ModuleTranslationState, - environ: &mut dyn ModuleEnvironment, + environ: &mut dyn ModuleEnvironment<'a>, ) -> WasmResult<()> { let count = types.get_count(); module_translation_state.wasm_types.reserve(count as usize); - environ.reserve_signatures(count)?; + environ.reserve_types(count)?; for entry in types { match entry? { @@ -55,28 +108,31 @@ pub fn parse_type_section( .expect("only numeric types are supported in function signatures"); AbiParam::new(cret_arg) })); - environ.declare_signature(wasm_func_ty.clone().try_into()?, sig)?; + environ.declare_type_func(wasm_func_ty.clone().try_into()?, sig)?; module_translation_state .wasm_types .push((wasm_func_ty.params, wasm_func_ty.returns)); } - - // Not implemented yet for module linking. Push dummy function types - // though to keep the function type index space consistent. We'll - // want an actual implementation here that handles this eventually. - TypeDef::Module(_) | TypeDef::Instance(_) => { - let sig = - Signature::new(ModuleEnvironment::target_config(environ).default_call_conv); - environ.declare_signature( - crate::environ::WasmFuncType { - params: Box::new([]), - returns: Box::new([]), - }, - sig, - )?; - module_translation_state - .wasm_types - .push((Box::new([]), Box::new([]))); + TypeDef::Module(t) => { + let imports = t + .imports + .iter() + .map(|i| Ok((i.module, i.field, entity_type(i.ty, environ)?))) + .collect::>>()?; + let exports = t + .exports + .iter() + .map(|e| Ok((e.name, entity_type(e.ty, environ)?))) + .collect::>>()?; + environ.declare_type_module(&imports, &exports)?; + } + TypeDef::Instance(t) => { + let exports = t + .exports + .iter() + .map(|e| Ok((e.name, entity_type(e.ty, environ)?))) + .collect::>>()?; + environ.declare_type_instance(&exports)?; } } } @@ -94,61 +150,24 @@ pub fn parse_import_section<'data>( let import = entry?; let module_name = import.module; let field_name = import.field.unwrap(); // TODO Handle error when module linking is implemented. - - match import.ty { - ImportSectionEntryType::Function(sig) => { - environ.declare_func_import( - SignatureIndex::from_u32(sig), - module_name, - field_name, - )?; + match entity_type(import.ty, environ)? { + EntityType::Function(idx) => { + environ.declare_func_import(idx, module_name, field_name)?; } - ImportSectionEntryType::Module(_sig) | ImportSectionEntryType::Instance(_sig) => { - unimplemented!("module linking not implemented yet") + EntityType::Module(idx) => { + environ.declare_module_import(idx, module_name, field_name)?; } - ImportSectionEntryType::Memory(MemoryType::M32 { - limits: ref memlimits, - shared, - }) => { - environ.declare_memory_import( - Memory { - minimum: memlimits.initial, - maximum: memlimits.maximum, - shared, - }, - module_name, - field_name, - )?; + EntityType::Instance(idx) => { + environ.declare_instance_import(idx, module_name, field_name)?; } - ImportSectionEntryType::Memory(MemoryType::M64 { .. }) => { - unimplemented!(); + EntityType::Memory(ty) => { + environ.declare_memory_import(ty, module_name, field_name)?; } - ImportSectionEntryType::Global(ref ty) => { - environ.declare_global_import( - Global { - wasm_ty: ty.content_type.try_into()?, - ty: type_to_type(ty.content_type, environ).unwrap(), - mutability: ty.mutable, - initializer: GlobalInit::Import, - }, - module_name, - field_name, - )?; + EntityType::Global(ty) => { + environ.declare_global_import(ty, module_name, field_name)?; } - ImportSectionEntryType::Table(ref tab) => { - environ.declare_table_import( - Table { - wasm_ty: tab.element_type.try_into()?, - ty: match tabletype_to_type(tab.element_type, environ)? { - Some(t) => TableElementType::Val(t), - None => TableElementType::Func, - }, - minimum: tab.limits.initial, - maximum: tab.limits.maximum, - }, - module_name, - field_name, - )?; + EntityType::Table(ty) => { + environ.declare_table_import(ty, module_name, field_name)?; } } } @@ -172,7 +191,7 @@ pub fn parse_function_section( for entry in functions { let sigindex = entry?; - environ.declare_func_type(SignatureIndex::from_u32(sigindex))?; + environ.declare_func_type(TypeIndex::from_u32(sigindex))?; } Ok(()) @@ -186,16 +205,8 @@ pub fn parse_table_section( environ.reserve_tables(tables.get_count())?; for entry in tables { - let table = entry?; - environ.declare_table(Table { - wasm_ty: table.element_type.try_into()?, - ty: match tabletype_to_type(table.element_type, environ)? { - Some(t) => TableElementType::Val(t), - None => TableElementType::Func, - }, - minimum: table.limits.initial, - maximum: table.limits.maximum, - })?; + let ty = table(entry?, environ)?; + environ.declare_table(ty)?; } Ok(()) @@ -209,17 +220,8 @@ pub fn parse_memory_section( environ.reserve_memories(memories.get_count())?; for entry in memories { - let memory = entry?; - match memory { - MemoryType::M32 { limits, shared } => { - environ.declare_memory(Memory { - minimum: limits.initial, - maximum: limits.maximum, - shared: shared, - })?; - } - MemoryType::M64 { .. } => unimplemented!(), - } + let memory = memory(entry?); + environ.declare_memory(memory)?; } Ok(()) @@ -233,13 +235,7 @@ pub fn parse_global_section( environ.reserve_globals(globals.get_count())?; for entry in globals { - let wasmparser::Global { - ty: GlobalType { - content_type, - mutable, - }, - init_expr, - } = entry?; + let wasmparser::Global { ty, init_expr } = entry?; let mut init_expr_reader = init_expr.get_binary_reader(); let initializer = match init_expr_reader.read_operator()? { Operator::I32Const { value } => GlobalInit::I32Const(value), @@ -263,13 +259,8 @@ pub fn parse_global_section( )); } }; - let global = Global { - wasm_ty: content_type.try_into()?, - ty: type_to_type(content_type, environ).unwrap(), - mutability: mutable, - initializer, - }; - environ.declare_global(global)?; + let ty = global(ty, environ, initializer)?; + environ.declare_global(ty)?; } Ok(()) diff --git a/cranelift/wasm/src/state/func_state.rs b/cranelift/wasm/src/state/func_state.rs index 2af264f59e..70d62c7240 100644 --- a/cranelift/wasm/src/state/func_state.rs +++ b/cranelift/wasm/src/state/func_state.rs @@ -7,7 +7,7 @@ //! value and control stacks during the translation of a single function. use crate::environ::{FuncEnvironment, GlobalVariable, WasmResult}; -use crate::translation_utils::{FuncIndex, GlobalIndex, MemoryIndex, SignatureIndex, TableIndex}; +use crate::translation_utils::{FuncIndex, GlobalIndex, MemoryIndex, TableIndex, TypeIndex}; use crate::{HashMap, Occupied, Vacant}; use cranelift_codegen::ir::{self, Block, Inst, Value}; use std::vec::Vec; @@ -236,7 +236,7 @@ pub struct FuncTranslationState { // Map of indirect call signatures that have been created by // `FuncEnvironment::make_indirect_sig()`. // Stores both the signature reference and the number of WebAssembly arguments - signatures: HashMap, + signatures: HashMap, // Imported and local functions that have been created by // `FuncEnvironment::make_direct_func()`. @@ -498,7 +498,7 @@ impl FuncTranslationState { index: u32, environ: &mut FE, ) -> WasmResult<(ir::SigRef, usize)> { - let index = SignatureIndex::from_u32(index); + let index = TypeIndex::from_u32(index); match self.signatures.entry(index) { Occupied(entry) => Ok(*entry.get()), Vacant(entry) => { diff --git a/cranelift/wasm/src/translation_utils.rs b/cranelift/wasm/src/translation_utils.rs index d8bb6c8593..15ad15756e 100644 --- a/cranelift/wasm/src/translation_utils.rs +++ b/cranelift/wasm/src/translation_utils.rs @@ -73,6 +73,65 @@ entity_impl!(DataIndex); pub struct ElemIndex(u32); entity_impl!(ElemIndex); +/// Index type of a type inside the WebAssembly module. +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +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)] +#[cfg_attr(feature = "enable-serde", derive(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)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub struct InstanceIndex(u32); +entity_impl!(InstanceIndex); + +/// An index of an entity. +#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub enum EntityIndex { + /// Function index. + Function(FuncIndex), + /// Table index. + Table(TableIndex), + /// Memory index. + 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 +/// can be exported. +#[allow(missing_docs)] +#[derive(Clone, Debug)] +#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +pub enum EntityType { + /// A global variable with the specified content type + Global(Global), + /// A linear memory with the specified limits + Memory(Memory), + /// A table with the specified element type and limits + Table(Table), + /// A function type where the index points to the type section and records a + /// function signature. + Function(TypeIndex), + /// An instance where the index points to the type section and records a + /// instance's exports. + Instance(TypeIndex), + /// A module where the index points to the type section and records a + /// module's imports and exports. + Module(TypeIndex), +} + /// A WebAssembly global. /// /// Note that we record both the original Wasm type and the Cranelift IR type diff --git a/crates/c-api/src/types.rs b/crates/c-api/src/types.rs index a80083f1e7..b051ce13be 100644 --- a/crates/c-api/src/types.rs +++ b/crates/c-api/src/types.rs @@ -23,14 +23,18 @@ 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 21278a25e7..fefc62c511 100644 --- a/crates/c-api/src/types/extern.rs +++ b/crates/c-api/src/types/extern.rs @@ -1,5 +1,6 @@ use crate::{wasm_functype_t, wasm_globaltype_t, wasm_memorytype_t, wasm_tabletype_t}; -use crate::{CFuncType, CGlobalType, CMemoryType, CTableType}; +use crate::{wasm_instancetype_t, wasm_moduletype_t}; +use crate::{CFuncType, CGlobalType, CInstanceType, CMemoryType, CModuleType, CTableType}; use wasmtime::ExternType; #[repr(C)] @@ -16,6 +17,8 @@ pub(crate) enum CExternType { Global(CGlobalType), Memory(CMemoryType), Table(CTableType), + Instance(CInstanceType), + Module(CModuleType), } pub type wasm_externkind_t = u8; @@ -24,6 +27,8 @@ 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 WASMTIME_EXTERN_MODULE: wasm_externkind_t = 4; +pub const WASMTIME_EXTERN_INSTANCE: wasm_externkind_t = 5; impl wasm_externtype_t { pub(crate) fn new(ty: ExternType) -> wasm_externtype_t { @@ -33,6 +38,8 @@ 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)), }, } } @@ -43,6 +50,8 @@ 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()), } } } @@ -54,6 +63,8 @@ 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(_) => WASMTIME_EXTERN_INSTANCE, + CExternType::Module(_) => WASMTIME_EXTERN_MODULE, } } @@ -110,3 +121,31 @@ 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 wasm_externtype_as_moduletype( + et: &wasm_externtype_t, +) -> Option<&wasm_moduletype_t> { + wasm_externtype_as_moduletype_const(et) +} + +#[no_mangle] +pub extern "C" fn wasm_externtype_as_moduletype_const( + et: &wasm_externtype_t, +) -> Option<&wasm_moduletype_t> { + wasm_moduletype_t::try_from(et) +} + +#[no_mangle] +pub extern "C" fn wasm_externtype_as_instancetype( + et: &wasm_externtype_t, +) -> Option<&wasm_instancetype_t> { + wasm_externtype_as_instancetype_const(et) +} + +#[no_mangle] +pub extern "C" fn wasm_externtype_as_instancetype_const( + et: &wasm_externtype_t, +) -> Option<&wasm_instancetype_t> { + wasm_instancetype_t::try_from(et) +} diff --git a/crates/c-api/src/types/instance.rs b/crates/c-api/src/types/instance.rs new file mode 100644 index 0000000000..83ec12d893 --- /dev/null +++ b/crates/c-api/src/types/instance.rs @@ -0,0 +1,46 @@ +use crate::{wasm_externtype_t, wasm_limits_t, CExternType}; +use once_cell::unsync::OnceCell; +use wasmtime::InstanceType; + +#[repr(transparent)] +#[derive(Clone)] +pub struct wasm_instancetype_t { + ext: wasm_externtype_t, +} + +wasmtime_c_api_macros::declare_ty!(wasm_instancetype_t); + +#[derive(Clone)] +pub(crate) struct CInstanceType { + pub(crate) ty: InstanceType, + limits_cache: OnceCell, +} + +impl wasm_instancetype_t { + pub(crate) fn try_from(e: &wasm_externtype_t) -> Option<&wasm_instancetype_t> { + match &e.which { + CExternType::Instance(_) => Some(unsafe { &*(e as *const _ as *const _) }), + _ => None, + } + } +} + +impl CInstanceType { + pub(crate) fn new(ty: InstanceType) -> CInstanceType { + CInstanceType { + ty, + limits_cache: OnceCell::new(), + } + } +} +#[no_mangle] +pub extern "C" fn wasm_instancetype_as_externtype(ty: &wasm_instancetype_t) -> &wasm_externtype_t { + &ty.ext +} + +#[no_mangle] +pub extern "C" fn wasm_instancetype_as_externtype_const( + ty: &wasm_instancetype_t, +) -> &wasm_externtype_t { + &ty.ext +} diff --git a/crates/c-api/src/types/module.rs b/crates/c-api/src/types/module.rs new file mode 100644 index 0000000000..3ac3b80757 --- /dev/null +++ b/crates/c-api/src/types/module.rs @@ -0,0 +1,47 @@ +use crate::{wasm_externtype_t, wasm_limits_t, CExternType}; +use once_cell::unsync::OnceCell; +use wasmtime::ModuleType; + +#[repr(transparent)] +#[derive(Clone)] +pub struct wasm_moduletype_t { + ext: wasm_externtype_t, +} + +wasmtime_c_api_macros::declare_ty!(wasm_moduletype_t); + +#[derive(Clone)] +pub(crate) struct CModuleType { + pub(crate) ty: ModuleType, + limits_cache: OnceCell, +} + +impl wasm_moduletype_t { + pub(crate) fn try_from(e: &wasm_externtype_t) -> Option<&wasm_moduletype_t> { + match &e.which { + CExternType::Module(_) => Some(unsafe { &*(e as *const _ as *const _) }), + _ => None, + } + } +} + +impl CModuleType { + pub(crate) fn new(ty: ModuleType) -> CModuleType { + CModuleType { + ty, + limits_cache: OnceCell::new(), + } + } +} + +#[no_mangle] +pub extern "C" fn wasm_moduletype_as_externtype(ty: &wasm_moduletype_t) -> &wasm_externtype_t { + &ty.ext +} + +#[no_mangle] +pub extern "C" fn wasm_moduletype_as_externtype_const( + ty: &wasm_moduletype_t, +) -> &wasm_externtype_t { + &ty.ext +} diff --git a/crates/cranelift/src/func_environ.rs b/crates/cranelift/src/func_environ.rs index 1e296015f7..1dffd20869 100644 --- a/crates/cranelift/src/func_environ.rs +++ b/crates/cranelift/src/func_environ.rs @@ -9,7 +9,7 @@ use cranelift_entity::{EntityRef, PrimaryMap}; use cranelift_frontend::FunctionBuilder; use cranelift_wasm::{ self, FuncIndex, GlobalIndex, GlobalVariable, MemoryIndex, SignatureIndex, TableIndex, - TargetEnvironment, WasmError, WasmResult, WasmType, + TargetEnvironment, TypeIndex, WasmError, WasmResult, WasmType, }; use std::convert::TryFrom; use wasmtime_environ::{ @@ -996,8 +996,9 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m fn make_indirect_sig( &mut self, func: &mut ir::Function, - index: SignatureIndex, + index: TypeIndex, ) -> WasmResult { + let index = self.module.types[index].unwrap_function(); Ok(func.import_signature(self.native_signatures[index].clone())) } @@ -1024,11 +1025,12 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m mut pos: FuncCursor<'_>, table_index: TableIndex, table: ir::Table, - sig_index: SignatureIndex, + ty_index: TypeIndex, sig_ref: ir::SigRef, callee: ir::Value, call_args: &[ir::Value], ) -> WasmResult { + let sig_index = self.module.types[ty_index].unwrap_function(); let pointer_type = self.pointer_type(); let table_entry_addr = pos.ins().table_addr(pointer_type, table, callee, 0); diff --git a/crates/environ/src/data_structures.rs b/crates/environ/src/data_structures.rs index 063e254d79..9e1a164675 100644 --- a/crates/environ/src/data_structures.rs +++ b/crates/environ/src/data_structures.rs @@ -24,9 +24,5 @@ pub mod entity { } pub mod wasm { - pub use cranelift_wasm::{ - get_vmctx_value_label, DataIndex, DefinedFuncIndex, DefinedGlobalIndex, DefinedMemoryIndex, - DefinedTableIndex, ElemIndex, FuncIndex, Global, GlobalIndex, GlobalInit, Memory, - MemoryIndex, SignatureIndex, Table, TableElementType, TableIndex, WasmFuncType, WasmType, - }; + pub use cranelift_wasm::*; } diff --git a/crates/environ/src/lib.rs b/crates/environ/src/lib.rs index f5ab4358c5..bbf521d28d 100644 --- a/crates/environ/src/lib.rs +++ b/crates/environ/src/lib.rs @@ -37,10 +37,7 @@ pub use crate::address_map::*; pub use crate::builtin::*; pub use crate::compilation::*; pub use crate::data_structures::*; -// pub use crate::func_environ::BuiltinFunctionIndex; -pub use crate::module::{ - EntityIndex, MemoryPlan, MemoryStyle, Module, TableElements, TablePlan, TableStyle, -}; +pub use crate::module::*; pub use crate::module_environ::*; pub use crate::tunables::Tunables; pub use crate::vmoffsets::{TargetSharedSignatureIndex, VMOffsets, INTERRUPTED}; diff --git a/crates/environ/src/module.rs b/crates/environ/src/module.rs index d2c651578e..06aec670fc 100644 --- a/crates/environ/src/module.rs +++ b/crates/environ/src/module.rs @@ -5,8 +5,8 @@ use crate::WASM_MAX_PAGES; use cranelift_entity::{EntityRef, PrimaryMap}; use cranelift_wasm::{ DataIndex, DefinedFuncIndex, DefinedGlobalIndex, DefinedMemoryIndex, DefinedTableIndex, - ElemIndex, FuncIndex, Global, GlobalIndex, Memory, MemoryIndex, SignatureIndex, Table, - TableIndex, WasmFuncType, + ElemIndex, EntityIndex, EntityType, FuncIndex, Global, GlobalIndex, InstanceIndex, Memory, + MemoryIndex, ModuleIndex, SignatureIndex, Table, TableIndex, TypeIndex, WasmFuncType, }; use indexmap::IndexMap; use more_asserts::assert_ge; @@ -30,19 +30,6 @@ pub struct TableElements { pub elements: Box<[FuncIndex]>, } -/// An index of an entity. -#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] -pub enum EntityIndex { - /// Function index. - Function(FuncIndex), - /// Table index. - Table(TableIndex), - /// Memory index. - Memory(MemoryIndex), - /// Global index. - Global(GlobalIndex), -} - /// Implemenation styles for WebAssembly linear memory. #[derive(Debug, Clone, Hash, Serialize, Deserialize)] pub enum MemoryStyle { @@ -134,6 +121,36 @@ impl TablePlan { } } +/// Different types that can appear in a module +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum ModuleType { + /// A function type, indexed further into the `signatures` table. + Function(SignatureIndex), + /// A module type + Module { + /// The module's imports + imports: Vec<(String, Option, EntityType)>, + /// The module's exports + exports: Vec<(String, EntityType)>, + }, + /// An instance type + Instance { + /// the instance's exports + exports: Vec<(String, EntityType)>, + }, +} + +impl ModuleType { + /// Asserts this is a `ModuleType::Function`, returning the underlying + /// `SignatureIndex`. + pub fn unwrap_function(&self) -> SignatureIndex { + match self { + ModuleType::Function(f) => *f, + _ => panic!("not a function type"), + } + } +} + /// A translated WebAssembly module, excluding the function bodies and /// memory initializers. #[derive(Debug, Clone, Serialize, Deserialize)] @@ -170,6 +187,9 @@ pub struct Module { /// Unprocessed signatures exactly as provided by `declare_signature()`. pub signatures: PrimaryMap, + /// Types declared in the wasm module. + pub types: PrimaryMap, + /// Number of imported functions in the module. pub num_imported_funcs: usize, @@ -193,6 +213,27 @@ pub struct Module { /// WebAssembly global variables. pub globals: PrimaryMap, + + /// WebAssembly instances. + pub instances: PrimaryMap, + + /// WebAssembly modules. + pub modules: PrimaryMap, +} + +/// Different forms an instance can take in a wasm module +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum Instance { + /// This is an imported instance with the specified type + Import(TypeIndex), + /// This is a locally created instance which instantiates the specified + /// module with the given list of entities. + Instantiate { + /// The module that this instance is instantiating. + module: ModuleIndex, + /// The arguments provided to instantiation. + args: Vec, + }, } impl Module { @@ -217,6 +258,9 @@ impl Module { table_plans: PrimaryMap::new(), memory_plans: PrimaryMap::new(), globals: PrimaryMap::new(), + instances: PrimaryMap::new(), + modules: PrimaryMap::new(), + types: PrimaryMap::new(), } } diff --git a/crates/environ/src/module_environ.rs b/crates/environ/src/module_environ.rs index 85ae46ba81..7d4f47d7fd 100644 --- a/crates/environ/src/module_environ.rs +++ b/crates/environ/src/module_environ.rs @@ -1,13 +1,13 @@ -use crate::module::{EntityIndex, MemoryPlan, Module, TableElements, TablePlan}; +use crate::module::{MemoryPlan, Module, ModuleType, TableElements, TablePlan}; use crate::tunables::Tunables; use cranelift_codegen::ir; use cranelift_codegen::ir::{AbiParam, ArgumentPurpose}; use cranelift_codegen::isa::TargetFrontendConfig; use cranelift_entity::PrimaryMap; use cranelift_wasm::{ - self, translate_module, DataIndex, DefinedFuncIndex, ElemIndex, FuncIndex, Global, GlobalIndex, - Memory, MemoryIndex, SignatureIndex, Table, TableIndex, TargetEnvironment, WasmError, - WasmFuncType, WasmResult, + self, translate_module, DataIndex, DefinedFuncIndex, ElemIndex, EntityIndex, EntityType, + FuncIndex, Global, GlobalIndex, Memory, MemoryIndex, SignatureIndex, Table, TableIndex, + TargetEnvironment, TypeIndex, WasmError, WasmFuncType, WasmResult, }; use serde::{Deserialize, Serialize}; use std::collections::HashMap; @@ -201,18 +201,54 @@ impl<'data> TargetEnvironment for ModuleEnvironment<'data> { /// This trait is useful for `translate_module` because it tells how to translate /// environment-dependent wasm instructions. These functions should not be called by the user. impl<'data> cranelift_wasm::ModuleEnvironment<'data> for ModuleEnvironment<'data> { - fn reserve_signatures(&mut self, num: u32) -> WasmResult<()> { + fn reserve_types(&mut self, num: u32) -> WasmResult<()> { let num = usize::try_from(num).unwrap(); - self.result.module.signatures.reserve_exact(num); + self.result.module.types.reserve_exact(num); self.result.native_signatures.reserve_exact(num); Ok(()) } - fn declare_signature(&mut self, wasm: WasmFuncType, sig: ir::Signature) -> WasmResult<()> { + fn declare_type_func(&mut self, wasm: WasmFuncType, sig: ir::Signature) -> WasmResult<()> { let sig = translate_signature(sig, self.pointer_type()); // TODO: Deduplicate signatures. - self.result.module.signatures.push(wasm); self.result.native_signatures.push(sig); + let sig_index = self.result.module.signatures.push(wasm); + self.result + .module + .types + .push(ModuleType::Function(sig_index)); + Ok(()) + } + + fn declare_type_module( + &mut self, + imports: &[(&'data str, Option<&'data str>, EntityType)], + exports: &[(&'data str, EntityType)], + ) -> WasmResult<()> { + let imports = imports + .iter() + .map(|i| (i.0.to_string(), i.1.map(|s| s.to_string()), i.2.clone())) + .collect(); + let exports = exports + .iter() + .map(|e| (e.0.to_string(), e.1.clone())) + .collect(); + self.result + .module + .types + .push(ModuleType::Module { imports, exports }); + 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(); + self.result + .module + .types + .push(ModuleType::Instance { exports }); Ok(()) } @@ -226,7 +262,7 @@ impl<'data> cranelift_wasm::ModuleEnvironment<'data> for ModuleEnvironment<'data fn declare_func_import( &mut self, - sig_index: SignatureIndex, + index: TypeIndex, module: &str, field: &str, ) -> WasmResult<()> { @@ -235,6 +271,7 @@ impl<'data> cranelift_wasm::ModuleEnvironment<'data> for ModuleEnvironment<'data self.result.module.num_imported_funcs, "Imported functions must be declared first" ); + let sig_index = self.result.module.types[index].unwrap_function(); let func_index = self.result.module.functions.push(sig_index); self.result.module.imports.push(( module.to_owned(), @@ -320,7 +357,8 @@ impl<'data> cranelift_wasm::ModuleEnvironment<'data> for ModuleEnvironment<'data Ok(()) } - fn declare_func_type(&mut self, sig_index: SignatureIndex) -> WasmResult<()> { + fn declare_func_type(&mut self, index: TypeIndex) -> WasmResult<()> { + let sig_index = self.result.module.types[index].unwrap_function(); self.result.module.functions.push(sig_index); Ok(()) } diff --git a/crates/fuzzing/src/oracles/dummy.rs b/crates/fuzzing/src/oracles/dummy.rs index e58dc371d3..f05a52e08e 100644 --- a/crates/fuzzing/src/oracles/dummy.rs +++ b/crates/fuzzing/src/oracles/dummy.rs @@ -17,6 +17,10 @@ pub fn dummy_imports<'module>( 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)), + + // FIXME(#2094) + ExternType::Instance(_) => unimplemented!(), + ExternType::Module(_) => unimplemented!(), }) }) .collect() diff --git a/crates/runtime/src/instance.rs b/crates/runtime/src/instance.rs index ccbff3ba39..ad79721760 100644 --- a/crates/runtime/src/instance.rs +++ b/crates/runtime/src/instance.rs @@ -28,10 +28,10 @@ use thiserror::Error; use wasmtime_environ::entity::{packed_option::ReservedValue, BoxedSlice, EntityRef, PrimaryMap}; use wasmtime_environ::wasm::{ DataIndex, DefinedFuncIndex, DefinedGlobalIndex, DefinedMemoryIndex, DefinedTableIndex, - ElemIndex, FuncIndex, GlobalIndex, GlobalInit, MemoryIndex, SignatureIndex, TableElementType, - TableIndex, WasmType, + ElemIndex, EntityIndex, FuncIndex, GlobalIndex, GlobalInit, MemoryIndex, SignatureIndex, + TableElementType, TableIndex, WasmType, }; -use wasmtime_environ::{ir, DataInitializer, EntityIndex, Module, TableElements, VMOffsets}; +use wasmtime_environ::{ir, DataInitializer, Module, TableElements, VMOffsets}; /// A WebAssembly instance. /// @@ -325,6 +325,10 @@ impl Instance { global: self.module.globals[*index], } .into(), + + // FIXME(#2094) + EntityIndex::Instance(_index) => unimplemented!(), + EntityIndex::Module(_index) => unimplemented!(), } } diff --git a/crates/wasmtime/src/instance.rs b/crates/wasmtime/src/instance.rs index 81d7d5a784..e2164153ea 100644 --- a/crates/wasmtime/src/instance.rs +++ b/crates/wasmtime/src/instance.rs @@ -3,7 +3,7 @@ use crate::{Engine, Export, Extern, Func, Global, Memory, Module, Store, Table, use anyhow::{anyhow, bail, Context, Error, Result}; use std::any::Any; use std::mem; -use wasmtime_environ::EntityIndex; +use wasmtime_environ::wasm::EntityIndex; use wasmtime_jit::CompiledModule; use wasmtime_runtime::{ Imports, InstantiationError, StackMapRegistry, VMContext, VMExternRefActivationsTable, @@ -300,6 +300,10 @@ fn with_imports( } functions.push(func.vmimport()); } + + // FIXME(#2094) + EntityIndex::Module(_i) => unimplemented!(), + EntityIndex::Instance(_i) => unimplemented!(), } Ok(()) }; diff --git a/crates/wasmtime/src/linker.rs b/crates/wasmtime/src/linker.rs index 1fb4b62638..7e9d498460 100644 --- a/crates/wasmtime/src/linker.rs +++ b/crates/wasmtime/src/linker.rs @@ -516,6 +516,10 @@ impl Linker { ExternType::Global(f) => ImportKind::Global(f), ExternType::Memory(_) => ImportKind::Memory, ExternType::Table(_) => ImportKind::Table, + + // FIXME(#2094) + ExternType::Module(_) => unimplemented!(), + ExternType::Instance(_) => unimplemented!(), } } diff --git a/crates/wasmtime/src/runtime.rs b/crates/wasmtime/src/runtime.rs index 2697c3db00..79a4bdccab 100644 --- a/crates/wasmtime/src/runtime.rs +++ b/crates/wasmtime/src/runtime.rs @@ -84,7 +84,12 @@ impl Config { profiler: Arc::new(NullProfilerAgent), memory_creator: None, max_wasm_stack: 1 << 20, - features: WasmFeatures::default(), + features: WasmFeatures { + reference_types: true, + bulk_memory: true, + multi_value: true, + ..WasmFeatures::default() + }, } } @@ -655,6 +660,7 @@ 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( "flags", &settings::Flags::new(self.flags.clone()).to_string(), diff --git a/crates/wasmtime/src/trampoline/func.rs b/crates/wasmtime/src/trampoline/func.rs index 04a62db379..0050f73330 100644 --- a/crates/wasmtime/src/trampoline/func.rs +++ b/crates/wasmtime/src/trampoline/func.rs @@ -10,7 +10,7 @@ use std::mem; use std::panic::{self, AssertUnwindSafe}; use wasmtime_environ::entity::PrimaryMap; use wasmtime_environ::isa::TargetIsa; -use wasmtime_environ::{ir, CompiledFunction, EntityIndex, Module}; +use wasmtime_environ::{ir, wasm, CompiledFunction, Module}; use wasmtime_jit::trampoline::ir::{ ExternalName, Function, InstBuilder, MemFlags, StackSlotData, StackSlotKind, }; @@ -227,7 +227,7 @@ pub fn create_handle_with_function( let func_id = module.functions.push(sig_id); module .exports - .insert(String::new(), EntityIndex::Function(func_id)); + .insert(String::new(), wasm::EntityIndex::Function(func_id)); let trampoline = make_trampoline(isa.as_ref(), &mut code_memory, &mut fn_builder_ctx, &sig); finished_functions.push(trampoline); @@ -274,7 +274,7 @@ pub unsafe fn create_handle_with_raw_function( let func_id = module.functions.push(sig_id); module .exports - .insert(String::new(), EntityIndex::Function(func_id)); + .insert(String::new(), wasm::EntityIndex::Function(func_id)); finished_functions.push(func); store.signatures().borrow_mut().register(wft, trampoline); diff --git a/crates/wasmtime/src/trampoline/global.rs b/crates/wasmtime/src/trampoline/global.rs index 901f533592..217d64721c 100644 --- a/crates/wasmtime/src/trampoline/global.rs +++ b/crates/wasmtime/src/trampoline/global.rs @@ -3,7 +3,7 @@ use crate::trampoline::StoreInstanceHandle; use crate::{GlobalType, Mutability, Store, Val}; use anyhow::Result; use wasmtime_environ::entity::PrimaryMap; -use wasmtime_environ::{wasm, EntityIndex, Module}; +use wasmtime_environ::{wasm, Module}; use wasmtime_runtime::VMFunctionImport; pub fn create_global(store: &Store, gt: &GlobalType, val: Val) -> Result { @@ -43,9 +43,11 @@ pub fn create_global(store: &Store, gt: &GlobalType, val: Val) -> Result Result Result { let mut module = Module::new(); @@ -25,7 +25,7 @@ pub fn create_handle_with_table(store: &Store, table: &TableType) -> Result ExternType { + use wasmtime_environ::wasm::EntityType; + match ty { + EntityType::Function(idx) => { + let sig = module.types[*idx].unwrap_function(); + let sig = &module.signatures[sig]; + FuncType::from_wasm_func_type(sig).into() + } + 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 (imports, exports) = match &module.types[*ty] { + wasmtime_environ::ModuleType::Module { imports, exports } => (imports, exports), + _ => unreachable!("not possible in valid wasm modules"), + }; + ModuleType::from_wasmtime(module, imports, exports).into() + } + EntityType::Instance(ty) => { + let exports = match &module.types[*ty] { + wasmtime_environ::ModuleType::Instance { exports } => exports, + _ => unreachable!("not possible in valid wasm modules"), + }; + InstanceType::from_wasmtime(module, exports).into() + } + } } } @@ -213,6 +250,18 @@ 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. @@ -397,34 +446,198 @@ 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(|(module, name, ty)| { + ImportType { + module, + // FIXME(#2094) should thread through the `Option` + name: name.as_ref().unwrap(), + 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( + module: &wasmtime_environ::Module, + imports: &[(String, Option, wasmtime_environ::wasm::EntityType)], + exports: &[(String, wasmtime_environ::wasm::EntityType)], + ) -> ModuleType { + ModuleType { + exports: exports + .iter() + .map(|(name, ty)| (name.to_string(), ExternType::from_wasmtime(module, ty))) + .collect(), + imports: imports + .iter() + .map(|(m, name, ty)| { + ( + m.to_string(), + name.as_ref().map(|n| n.to_string()), + ExternType::from_wasmtime(module, 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( + module: &wasmtime_environ::Module, + exports: &[(String, wasmtime_environ::wasm::EntityType)], + ) -> InstanceType { + InstanceType { + exports: exports + .iter() + .map(|(name, ty)| (name.to_string(), ExternType::from_wasmtime(module, ty))) + .collect(), + } + } +} + // Entity Types -#[derive(Clone, Hash, Eq, PartialEq)] +#[derive(Clone)] pub(crate) enum EntityType<'module> { Function(&'module wasm::WasmFuncType), Table(&'module wasm::Table), Memory(&'module wasm::Memory), Global(&'module wasm::Global), + Module { + imports: &'module [(String, Option, wasmtime_environ::wasm::EntityType)], + exports: &'module [(String, wasmtime_environ::wasm::EntityType)], + module: &'module wasmtime_environ::Module, + }, + Instance { + exports: &'module [(String, wasmtime_environ::wasm::EntityType)], + module: &'module wasmtime_environ::Module, + }, } impl<'module> EntityType<'module> { /// Translate from a `EntityIndex` into an `ExternType`. pub(crate) fn new( - entity_index: &EntityIndex, + entity_index: &wasm::EntityIndex, module: &'module wasmtime_environ::Module, ) -> EntityType<'module> { match entity_index { - EntityIndex::Function(func_index) => { + wasm::EntityIndex::Function(func_index) => { let sig = module.wasm_func_type(*func_index); EntityType::Function(&sig) } - EntityIndex::Table(table_index) => { + wasm::EntityIndex::Table(table_index) => { EntityType::Table(&module.table_plans[*table_index].table) } - EntityIndex::Memory(memory_index) => { + wasm::EntityIndex::Memory(memory_index) => { EntityType::Memory(&module.memory_plans[*memory_index].memory) } - EntityIndex::Global(global_index) => EntityType::Global(&module.globals[*global_index]), + wasm::EntityIndex::Global(global_index) => { + EntityType::Global(&module.globals[*global_index]) + } + wasm::EntityIndex::Module(idx) => { + let (imports, exports) = match &module.types[module.modules[*idx]] { + wasmtime_environ::ModuleType::Module { imports, exports } => (imports, exports), + _ => unreachable!("valid modules should never hit this"), + }; + EntityType::Module { + imports, + exports, + module, + } + } + wasm::EntityIndex::Instance(idx) => { + // Get the type, either a pointer to an instance for an import + // or a module for an instantiation. + let ty = match module.instances[*idx] { + wasmtime_environ::Instance::Import(ty) => ty, + wasmtime_environ::Instance::Instantiate { module: idx, .. } => { + module.modules[idx] + } + }; + // Get the exports of whatever our type specifies, ignoring + // imports in the module case since we're instantiating the + // module. + let exports = match &module.types[ty] { + wasmtime_environ::ModuleType::Instance { exports } => exports, + wasmtime_environ::ModuleType::Module { exports, .. } => exports, + _ => unreachable!("valid modules should never hit this"), + }; + EntityType::Instance { exports, module } + } } } @@ -435,6 +648,14 @@ impl<'module> EntityType<'module> { EntityType::Table(table) => TableType::from_wasmtime_table(table).into(), EntityType::Memory(memory) => MemoryType::from_wasmtime_memory(memory).into(), EntityType::Global(global) => GlobalType::from_wasmtime_global(global).into(), + EntityType::Instance { exports, module } => { + InstanceType::from_wasmtime(module, exports).into() + } + EntityType::Module { + imports, + exports, + module, + } => ModuleType::from_wasmtime(module, imports, exports).into(), } } } @@ -447,7 +668,7 @@ impl<'module> EntityType<'module> { /// [`Module::imports`](crate::Module::imports) API. Each [`ImportType`] /// describes an import into the wasm module with the module/name that it's /// imported from as well as the type of item that's being imported. -#[derive(Clone, Hash, Eq, PartialEq)] +#[derive(Clone)] pub struct ImportType<'module> { /// The module of the import. module: &'module str, @@ -456,7 +677,13 @@ pub struct ImportType<'module> { name: &'module str, /// The type of the import. - ty: EntityType<'module>, + ty: EntityOrExtern<'module>, +} + +#[derive(Clone)] +enum EntityOrExtern<'a> { + Entity(EntityType<'a>), + Extern(&'a ExternType), } impl<'module> ImportType<'module> { @@ -467,7 +694,11 @@ impl<'module> ImportType<'module> { name: &'module str, ty: EntityType<'module>, ) -> ImportType<'module> { - ImportType { module, name, ty } + ImportType { + module, + name, + ty: EntityOrExtern::Entity(ty), + } } /// Returns the module name that this import is expected to come from. @@ -483,7 +714,10 @@ impl<'module> ImportType<'module> { /// Returns the expected type of this import. pub fn ty(&self) -> ExternType { - self.ty.extern_type() + match &self.ty { + EntityOrExtern::Entity(e) => e.extern_type(), + EntityOrExtern::Extern(e) => (*e).clone(), + } } } @@ -505,20 +739,23 @@ impl<'module> fmt::Debug for ImportType<'module> { /// [`Module::exports`](crate::Module::exports) accessor and describes what /// names are exported from a wasm module and the type of the item that is /// exported. -#[derive(Clone, Hash, Eq, PartialEq)] +#[derive(Clone)] pub struct ExportType<'module> { /// The name of the export. name: &'module str, /// The type of the export. - ty: EntityType<'module>, + ty: EntityOrExtern<'module>, } impl<'module> ExportType<'module> { /// Creates a new export which is exported with the given `name` and has the /// given `ty`. pub(crate) fn new(name: &'module str, ty: EntityType<'module>) -> ExportType<'module> { - ExportType { name, ty } + ExportType { + name, + ty: EntityOrExtern::Entity(ty), + } } /// Returns the name by which this export is known. @@ -528,7 +765,10 @@ impl<'module> ExportType<'module> { /// Returns the type of this export. pub fn ty(&self) -> ExternType { - self.ty.extern_type() + match &self.ty { + EntityOrExtern::Entity(e) => e.extern_type(), + EntityOrExtern::Extern(e) => (*e).clone(), + } } } diff --git a/tests/all/module_linking.rs b/tests/all/module_linking.rs index 61949c576d..30a4b27088 100644 --- a/tests/all/module_linking.rs +++ b/tests/all/module_linking.rs @@ -44,3 +44,11 @@ fn compile() -> Result<()> { 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(()) +}