diff --git a/cranelift/wasm/Cargo.toml b/cranelift/wasm/Cargo.toml index cc5cc3d90e..f9f2b8b4bd 100644 --- a/cranelift/wasm/Cargo.toml +++ b/cranelift/wasm/Cargo.toml @@ -21,7 +21,7 @@ serde = { version = "1.0.94", features = ["derive"], optional = true } thiserror = "1.0.4" [dev-dependencies] -wat = "1.0.7" +wat = "1.0.9" target-lexicon = "0.10" [features] diff --git a/cranelift/wasm/src/environ/dummy.rs b/cranelift/wasm/src/environ/dummy.rs index a36a0bce70..4ebf0bdc29 100644 --- a/cranelift/wasm/src/environ/dummy.rs +++ b/cranelift/wasm/src/environ/dummy.rs @@ -11,8 +11,8 @@ use crate::environ::{ use crate::func_translator::FuncTranslator; use crate::state::ModuleTranslationState; use crate::translation_utils::{ - DefinedFuncIndex, FuncIndex, Global, GlobalIndex, Memory, MemoryIndex, SignatureIndex, Table, - TableIndex, + DefinedFuncIndex, FuncIndex, Global, GlobalIndex, Memory, MemoryIndex, PassiveDataIndex, + PassiveElemIndex, SignatureIndex, Table, TableIndex, }; use core::convert::TryFrom; use cranelift_codegen::cursor::FuncCursor; @@ -605,6 +605,22 @@ impl<'data> ModuleEnvironment<'data> for DummyEnvironment { Ok(()) } + fn declare_passive_element( + &mut self, + _elem_index: PassiveElemIndex, + _segments: Box<[FuncIndex]>, + ) -> WasmResult<()> { + Ok(()) + } + + fn declare_passive_data( + &mut self, + _elem_index: PassiveDataIndex, + _segments: &'data [u8], + ) -> WasmResult<()> { + Ok(()) + } + fn declare_memory(&mut self, memory: Memory) -> WasmResult<()> { self.info.memories.push(Exportable::new(memory)); Ok(()) diff --git a/cranelift/wasm/src/environ/spec.rs b/cranelift/wasm/src/environ/spec.rs index 123a8d0c09..73a02c6709 100644 --- a/cranelift/wasm/src/environ/spec.rs +++ b/cranelift/wasm/src/environ/spec.rs @@ -8,7 +8,8 @@ use crate::state::{FuncTranslationState, ModuleTranslationState}; use crate::translation_utils::{ - FuncIndex, Global, GlobalIndex, Memory, MemoryIndex, SignatureIndex, Table, TableIndex, + FuncIndex, Global, GlobalIndex, Memory, MemoryIndex, PassiveDataIndex, PassiveElemIndex, + SignatureIndex, Table, TableIndex, }; use core::convert::From; use cranelift_codegen::cursor::FuncCursor; @@ -600,6 +601,29 @@ pub trait ModuleEnvironment<'data>: TargetEnvironment { elements: Box<[FuncIndex]>, ) -> WasmResult<()>; + /// Declare a passive element segment. + fn declare_passive_element( + &mut self, + index: PassiveElemIndex, + elements: Box<[FuncIndex]>, + ) -> WasmResult<()>; + + /// Provides the number of passive data segments up front. + /// + /// By default this does nothing, but implementations may use this to + /// pre-allocate memory if desired. + fn reserve_passive_data(&mut self, count: u32) -> WasmResult<()> { + let _ = count; + Ok(()) + } + + /// Declare a passive data segment. + fn declare_passive_data( + &mut self, + data_index: PassiveDataIndex, + data: &'data [u8], + ) -> WasmResult<()>; + /// Provides the contents of a function body. /// /// Note there's no `reserve_function_bodies` function because the number of diff --git a/cranelift/wasm/src/lib.rs b/cranelift/wasm/src/lib.rs index 28e4361126..b98c95b466 100644 --- a/cranelift/wasm/src/lib.rs +++ b/cranelift/wasm/src/lib.rs @@ -68,7 +68,7 @@ pub use crate::state::module_state::ModuleTranslationState; pub use crate::translation_utils::{ get_vmctx_value_label, DefinedFuncIndex, DefinedGlobalIndex, DefinedMemoryIndex, DefinedTableIndex, FuncIndex, Global, GlobalIndex, GlobalInit, Memory, MemoryIndex, - SignatureIndex, Table, TableElementType, TableIndex, + PassiveDataIndex, PassiveElemIndex, SignatureIndex, Table, TableElementType, TableIndex, }; /// Version number of this crate. diff --git a/cranelift/wasm/src/module_translator.rs b/cranelift/wasm/src/module_translator.rs index 257daa1f20..e31e6f09f8 100644 --- a/cranelift/wasm/src/module_translator.rs +++ b/cranelift/wasm/src/module_translator.rs @@ -1,6 +1,6 @@ //! Translation skeleton that traverses the whole WebAssembly module and call helper functions //! to deal with each part of it. -use crate::environ::{ModuleEnvironment, WasmError, WasmResult}; +use crate::environ::{ModuleEnvironment, WasmResult}; use crate::sections_translator::{ parse_code_section, parse_data_section, parse_element_section, parse_export_section, parse_function_section, parse_global_section, parse_import_section, parse_memory_section, @@ -67,11 +67,8 @@ pub fn translate_module<'data>( parse_data_section(data, environ)?; } - SectionContent::DataCount(_) => { - return Err(WasmError::InvalidWebAssembly { - message: "don't know how to handle the data count section yet", - offset: reader.current_position(), - }); + SectionContent::DataCount(count) => { + environ.reserve_passive_data(count)?; } SectionContent::Custom { diff --git a/cranelift/wasm/src/sections_translator.rs b/cranelift/wasm/src/sections_translator.rs index f4c5079a6e..6759a60c3f 100644 --- a/cranelift/wasm/src/sections_translator.rs +++ b/cranelift/wasm/src/sections_translator.rs @@ -11,7 +11,8 @@ use crate::environ::{ModuleEnvironment, WasmError, WasmResult}; use crate::state::ModuleTranslationState; use crate::translation_utils::{ tabletype_to_type, type_to_type, FuncIndex, Global, GlobalIndex, GlobalInit, Memory, - MemoryIndex, SignatureIndex, Table, TableElementType, TableIndex, + MemoryIndex, PassiveDataIndex, PassiveElemIndex, SignatureIndex, Table, TableElementType, + TableIndex, }; use crate::{wasm_unsupported, HashMap}; use core::convert::TryFrom; @@ -19,10 +20,11 @@ use cranelift_codegen::ir::immediates::V128Imm; use cranelift_codegen::ir::{self, AbiParam, Signature}; use cranelift_entity::packed_option::ReservedValue; use cranelift_entity::EntityRef; +use std::boxed::Box; use std::vec::Vec; use wasmparser::{ - self, CodeSectionReader, Data, DataKind, DataSectionReader, Element, ElementItem, ElementKind, - ElementSectionReader, Export, ExportSectionReader, ExternalKind, FuncType, + self, CodeSectionReader, Data, DataKind, DataSectionReader, Element, ElementItem, ElementItems, + ElementKind, ElementSectionReader, Export, ExportSectionReader, ExternalKind, FuncType, FunctionSectionReader, GlobalSectionReader, GlobalType, ImportSectionEntryType, ImportSectionReader, MemorySectionReader, MemoryType, NameSectionReader, Naming, NamingReader, Operator, TableSectionReader, Type, TypeSectionReader, @@ -288,6 +290,19 @@ pub fn parse_start_section(index: u32, environ: &mut dyn ModuleEnvironment) -> W Ok(()) } +fn read_elems(items: &ElementItems) -> WasmResult> { + let items_reader = items.get_items_reader()?; + let mut elems = Vec::with_capacity(usize::try_from(items_reader.get_count()).unwrap()); + for item in items_reader { + let elem = match item? { + ElementItem::Null => FuncIndex::reserved_value(), + ElementItem::Func(index) => FuncIndex::from_u32(index), + }; + elems.push(elem); + } + Ok(elems.into_boxed_slice()) +} + /// Parses the Element section of the wasm module. pub fn parse_element_section<'data>( elements: ElementSectionReader<'data>, @@ -295,7 +310,7 @@ pub fn parse_element_section<'data>( ) -> WasmResult<()> { environ.reserve_table_elements(elements.get_count())?; - for entry in elements { + for (index, entry) in elements.into_iter().enumerate() { let Element { kind, items, ty } = entry?; if ty != Type::AnyFunc { return Err(wasm_unsupported!( @@ -303,41 +318,37 @@ pub fn parse_element_section<'data>( ty )); } - if let ElementKind::Active { - table_index, - init_expr, - } = kind - { - let mut init_expr_reader = init_expr.get_binary_reader(); - let (base, offset) = match init_expr_reader.read_operator()? { - Operator::I32Const { value } => (None, value as u32 as usize), - Operator::GlobalGet { global_index } => { - (Some(GlobalIndex::from_u32(global_index)), 0) - } - ref s => { - return Err(wasm_unsupported!( - "unsupported init expr in element section: {:?}", - s - )); - } - }; - let items_reader = items.get_items_reader()?; - let mut elems = Vec::with_capacity(usize::try_from(items_reader.get_count()).unwrap()); - for item in items_reader { - let elem = match item? { - ElementItem::Null => FuncIndex::reserved_value(), - ElementItem::Func(index) => FuncIndex::from_u32(index), + let segments = read_elems(&items)?; + match kind { + ElementKind::Active { + table_index, + init_expr, + } => { + let mut init_expr_reader = init_expr.get_binary_reader(); + let (base, offset) = match init_expr_reader.read_operator()? { + Operator::I32Const { value } => (None, value as u32 as usize), + Operator::GlobalGet { global_index } => { + (Some(GlobalIndex::from_u32(global_index)), 0) + } + ref s => { + return Err(wasm_unsupported!( + "unsupported init expr in element section: {:?}", + s + )); + } }; - elems.push(elem); + environ.declare_table_elements( + TableIndex::from_u32(table_index), + base, + offset, + segments, + )? } - environ.declare_table_elements( - TableIndex::from_u32(table_index), - base, - offset, - elems.into_boxed_slice(), - )? - } else { - return Err(wasm_unsupported!("unsupported passive elements section",)); + ElementKind::Passive => { + let index = PassiveElemIndex::from_u32(index as u32); + environ.declare_passive_element(index, segments)?; + } + ElementKind::Declared => return Err(wasm_unsupported!("element kind declared")), } } Ok(()) @@ -365,37 +376,37 @@ pub fn parse_data_section<'data>( ) -> WasmResult<()> { environ.reserve_data_initializers(data.get_count())?; - for entry in data { + for (index, entry) in data.into_iter().enumerate() { let Data { kind, data } = entry?; - if let DataKind::Active { - memory_index, - init_expr, - } = kind - { - let mut init_expr_reader = init_expr.get_binary_reader(); - let (base, offset) = match init_expr_reader.read_operator()? { - Operator::I32Const { value } => (None, value as u32 as usize), - Operator::GlobalGet { global_index } => { - (Some(GlobalIndex::from_u32(global_index)), 0) - } - ref s => { - return Err(wasm_unsupported!( - "unsupported init expr in data section: {:?}", - s - )) - } - }; - environ.declare_data_initialization( - MemoryIndex::from_u32(memory_index), - base, - offset, - data, - )?; - } else { - return Err(wasm_unsupported!( - "unsupported passive data section: {:?}", - kind - )); + match kind { + DataKind::Active { + memory_index, + init_expr, + } => { + let mut init_expr_reader = init_expr.get_binary_reader(); + let (base, offset) = match init_expr_reader.read_operator()? { + Operator::I32Const { value } => (None, value as u32 as usize), + Operator::GlobalGet { global_index } => { + (Some(GlobalIndex::from_u32(global_index)), 0) + } + ref s => { + return Err(wasm_unsupported!( + "unsupported init expr in data section: {:?}", + s + )) + } + }; + environ.declare_data_initialization( + MemoryIndex::from_u32(memory_index), + base, + offset, + data, + )?; + } + DataKind::Passive => { + let index = PassiveDataIndex::from_u32(index as u32); + environ.declare_passive_data(index, data)?; + } } } diff --git a/cranelift/wasm/src/translation_utils.rs b/cranelift/wasm/src/translation_utils.rs index cd19ed820f..8a19761a88 100644 --- a/cranelift/wasm/src/translation_utils.rs +++ b/cranelift/wasm/src/translation_utils.rs @@ -57,6 +57,16 @@ entity_impl!(MemoryIndex); pub struct SignatureIndex(u32); entity_impl!(SignatureIndex); +/// Index type of a passive data segment inside the WebAssembly module. +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] +pub struct PassiveDataIndex(u32); +entity_impl!(PassiveDataIndex); + +/// Index type of a passive element segment inside the WebAssembly module. +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] +pub struct PassiveElemIndex(u32); +entity_impl!(PassiveElemIndex); + /// WebAssembly global. #[derive(Debug, Clone, Copy, Hash)] pub struct Global { diff --git a/cranelift/wasmtests/passive-data.wat b/cranelift/wasmtests/passive-data.wat new file mode 100644 index 0000000000..9316cd0f59 --- /dev/null +++ b/cranelift/wasmtests/passive-data.wat @@ -0,0 +1,11 @@ +(module + (data $passive "this is a passive data segment") + + (func (export "init") (param i32 i32 i32) + local.get 0 ;; dst + local.get 1 ;; src + local.get 2 ;; cnt + memory.init $passive) + + (func (export "drop") + data.drop $passive)) diff --git a/cranelift/wasmtests/table-copy.wat b/cranelift/wasmtests/table-copy.wat new file mode 100644 index 0000000000..dd9e1611e6 --- /dev/null +++ b/cranelift/wasmtests/table-copy.wat @@ -0,0 +1,22 @@ +(module $n + (table $t (import "m" "t") 6 funcref) + + (func $i (param i32 i32 i32 i32 i32 i32) (result i32) (local.get 3)) + (func $j (param i32 i32 i32 i32 i32 i32) (result i32) (local.get 4)) + (func $k (param i32 i32 i32 i32 i32 i32) (result i32) (local.get 5)) + + (table $u (export "u") funcref (elem $i $j $k $i $j $k)) + + (func (export "copy_to_t_from_u") (param i32 i32 i32 i32) (result i32) + local.get 0 + local.get 1 + local.get 2 + local.get 3 + table.copy $t $u) + + (func (export "copy_to_u_from_t") (param i32 i32 i32 i32) (result i32) + local.get 0 + local.get 1 + local.get 2 + local.get 3 + table.copy $u $t))