diff --git a/lib/wasm/Cargo.toml b/lib/wasm/Cargo.toml index 1a09c44e5e..e674945ac2 100644 --- a/lib/wasm/Cargo.toml +++ b/lib/wasm/Cargo.toml @@ -10,7 +10,7 @@ readme = "README.md" keywords = ["webassembly", "wasm"] [dependencies] -wasmparser = { version = "0.19.1", default-features = false } +wasmparser = { version = "0.21.4", default-features = false } cranelift-codegen = { path = "../codegen", version = "0.22.0", default-features = false } cranelift-entity = { path = "../entity", version = "0.22.0", default-features = false } cranelift-frontend = { path = "../frontend", version = "0.22.0", default-features = false } diff --git a/lib/wasm/src/environ/spec.rs b/lib/wasm/src/environ/spec.rs index 7f48ef99d2..d5518e037a 100644 --- a/lib/wasm/src/environ/spec.rs +++ b/lib/wasm/src/environ/spec.rs @@ -3,6 +3,7 @@ use cranelift_codegen::cursor::FuncCursor; use cranelift_codegen::ir::{self, InstBuilder}; use cranelift_codegen::isa::TargetFrontendConfig; +use std::convert::From; use std::vec::Vec; use translation_utils::{ FuncIndex, Global, GlobalIndex, Memory, MemoryIndex, SignatureIndex, Table, TableIndex, @@ -62,9 +63,9 @@ pub enum WasmError { ImplLimitExceeded, } -impl WasmError { +impl From for WasmError { /// Convert from a `BinaryReaderError` to a `WasmError`. - pub fn from_binary_reader_error(e: BinaryReaderError) -> Self { + fn from(e: BinaryReaderError) -> Self { let BinaryReaderError { message, offset } = e; WasmError::InvalidWebAssembly { message, offset } } diff --git a/lib/wasm/src/func_translator.rs b/lib/wasm/src/func_translator.rs index 5b7a116454..4b9e5fe7ca 100644 --- a/lib/wasm/src/func_translator.rs +++ b/lib/wasm/src/func_translator.rs @@ -9,7 +9,7 @@ use cranelift_codegen::entity::EntityRef; use cranelift_codegen::ir::{self, Ebb, InstBuilder}; use cranelift_codegen::timing; use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable}; -use environ::{FuncEnvironment, ReturnMode, WasmError, WasmResult}; +use environ::{FuncEnvironment, ReturnMode, WasmResult}; use state::TranslationState; use wasmparser::{self, BinaryReader}; @@ -135,16 +135,12 @@ fn parse_local_decls( num_params: usize, ) -> WasmResult<()> { let mut next_local = num_params; - let local_count = reader - .read_local_count() - .map_err(WasmError::from_binary_reader_error)?; + let local_count = reader.read_local_count()?; let mut locals_total = 0; for _ in 0..local_count { builder.set_srcloc(cur_srcloc(reader)); - let (count, ty) = reader - .read_local_decl(&mut locals_total) - .map_err(WasmError::from_binary_reader_error)?; + let (count, ty) = reader.read_local_decl(&mut locals_total)?; declare_locals(builder, count, ty, &mut next_local); } @@ -195,9 +191,7 @@ fn parse_function_body( // Keep going until the final `End` operator which pops the outermost block. while !state.control_stack.is_empty() { builder.set_srcloc(cur_srcloc(&reader)); - let op = reader - .read_operator() - .map_err(WasmError::from_binary_reader_error)?; + let op = reader.read_operator()?; translate_operator(op, builder, state, environ)?; } diff --git a/lib/wasm/src/lib.rs b/lib/wasm/src/lib.rs index 76da0113ac..b119d2df8f 100644 --- a/lib/wasm/src/lib.rs +++ b/lib/wasm/src/lib.rs @@ -76,6 +76,7 @@ mod std { pub use self::alloc::string; pub use self::alloc::vec; + pub use core::convert; pub use core::fmt; pub use core::option; pub use core::{cmp, i32, str, u32}; diff --git a/lib/wasm/src/module_translator.rs b/lib/wasm/src/module_translator.rs index 6b7c854f27..7a7ce91b9b 100644 --- a/lib/wasm/src/module_translator.rs +++ b/lib/wasm/src/module_translator.rs @@ -1,119 +1,143 @@ //! Translation skeleton that traverses the whole WebAssembly module and call helper functions //! to deal with each part of it. use cranelift_codegen::timing; -use environ::{ModuleEnvironment, WasmError, WasmResult}; +use environ::{ModuleEnvironment, WasmResult}; use sections_translator::{ parse_code_section, parse_data_section, parse_element_section, parse_export_section, - parse_function_section, parse_function_signatures, parse_global_section, parse_import_section, - parse_memory_section, parse_start_section, parse_table_section, + parse_function_section, parse_global_section, parse_import_section, parse_memory_section, + parse_start_section, parse_table_section, parse_type_section, }; -use wasmparser::{Parser, ParserInput, ParserState, SectionCode, WasmDecoder}; +use wasmparser::{ModuleReader, SectionCode}; /// Translate a sequence of bytes forming a valid Wasm binary into a list of valid Cranelift IR /// [`Function`](../codegen/ir/function/struct.Function.html). -/// Returns the functions and also the mappings for imported functions and signature between the -/// indexes in the wasm module and the indexes inside each functions. pub fn translate_module<'data>( data: &'data [u8], environ: &mut ModuleEnvironment<'data>, ) -> WasmResult<()> { let _tt = timing::wasm_translate_module(); - let mut parser = Parser::new(data); - match *parser.read() { - ParserState::BeginWasm { .. } => {} - ParserState::Error(e) => { - return Err(WasmError::from_binary_reader_error(e)); + let mut reader = ModuleReader::new(data)?; + + reader.skip_custom_sections()?; + if reader.eof() { + return Ok(()); + } + let mut section = reader.read()?; + + if let SectionCode::Type = section.code { + let types = section.get_type_section_reader()?; + parse_type_section(types, environ)?; + + reader.skip_custom_sections()?; + if reader.eof() { + return Ok(()); } - ref s => panic!("modules should begin properly: {:?}", s), + section = reader.read()?; } - let mut next_input = ParserInput::Default; - loop { - match *parser.read_with_input(next_input) { - ParserState::BeginSection { - code: SectionCode::Type, - .. - } => { - parse_function_signatures(&mut parser, environ)?; - next_input = ParserInput::Default; - } - ParserState::BeginSection { - code: SectionCode::Import, - .. - } => { - parse_import_section(&mut parser, environ)?; - next_input = ParserInput::Default; - } - ParserState::BeginSection { - code: SectionCode::Function, - .. - } => { - parse_function_section(&mut parser, environ)?; - next_input = ParserInput::Default; - } - ParserState::BeginSection { - code: SectionCode::Table, - .. - } => { - parse_table_section(&mut parser, environ)?; - } - ParserState::BeginSection { - code: SectionCode::Memory, - .. - } => { - parse_memory_section(&mut parser, environ)?; - next_input = ParserInput::Default; - } - ParserState::BeginSection { - code: SectionCode::Global, - .. - } => { - parse_global_section(&mut parser, environ)?; - next_input = ParserInput::Default; - } - ParserState::BeginSection { - code: SectionCode::Export, - .. - } => { - parse_export_section(&mut parser, environ)?; - next_input = ParserInput::Default; - } - ParserState::BeginSection { - code: SectionCode::Start, - .. - } => { - parse_start_section(&mut parser, environ)?; - next_input = ParserInput::Default; - } - ParserState::BeginSection { - code: SectionCode::Element, - .. - } => { - parse_element_section(&mut parser, environ)?; - next_input = ParserInput::Default; - } - ParserState::BeginSection { - code: SectionCode::Code, - .. - } => parse_code_section(&mut parser, environ)?, - ParserState::EndSection => { - next_input = ParserInput::Default; - } - ParserState::EndWasm => return Ok(()), - ParserState::BeginSection { - code: SectionCode::Data, - .. - } => { - parse_data_section(&mut parser, environ)?; - } - ParserState::BeginSection { - code: SectionCode::Custom { .. }, - .. - } => { - // Ignore unknown custom sections. - next_input = ParserInput::SkipSection; - } - ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)), - _ => panic!("wrong content in the preamble"), - }; + + if let SectionCode::Import = section.code { + let imports = section.get_import_section_reader()?; + parse_import_section(imports, environ)?; + + reader.skip_custom_sections()?; + if reader.eof() { + return Ok(()); + } + section = reader.read()?; } + + if let SectionCode::Function = section.code { + let functions = section.get_function_section_reader()?; + parse_function_section(functions, environ)?; + + reader.skip_custom_sections()?; + if reader.eof() { + return Ok(()); + } + section = reader.read()?; + } + + if let SectionCode::Table = section.code { + let tables = section.get_table_section_reader()?; + parse_table_section(tables, environ)?; + + reader.skip_custom_sections()?; + if reader.eof() { + return Ok(()); + } + section = reader.read()?; + } + + if let SectionCode::Memory = section.code { + let memories = section.get_memory_section_reader()?; + parse_memory_section(memories, environ)?; + + reader.skip_custom_sections()?; + if reader.eof() { + return Ok(()); + } + section = reader.read()?; + } + + if let SectionCode::Global = section.code { + let globals = section.get_global_section_reader()?; + parse_global_section(globals, environ)?; + + reader.skip_custom_sections()?; + if reader.eof() { + return Ok(()); + } + section = reader.read()?; + } + + if let SectionCode::Export = section.code { + let exports = section.get_export_section_reader()?; + parse_export_section(exports, environ)?; + + reader.skip_custom_sections()?; + if reader.eof() { + return Ok(()); + } + section = reader.read()?; + } + + if let SectionCode::Start = section.code { + let start = section.get_start_section_content()?; + parse_start_section(start, environ)?; + + reader.skip_custom_sections()?; + if reader.eof() { + return Ok(()); + } + section = reader.read()?; + } + + if let SectionCode::Element = section.code { + let elements = section.get_element_section_reader()?; + parse_element_section(elements, environ)?; + + reader.skip_custom_sections()?; + if reader.eof() { + return Ok(()); + } + section = reader.read()?; + } + + if let SectionCode::Code = section.code { + let code = section.get_code_section_reader()?; + parse_code_section(code, environ)?; + + reader.skip_custom_sections()?; + if reader.eof() { + return Ok(()); + } + section = reader.read()?; + } + + if let SectionCode::Data = section.code { + let data = section.get_data_section_reader()?; + parse_data_section(data, environ)?; + } + + Ok(()) } diff --git a/lib/wasm/src/sections_translator.rs b/lib/wasm/src/sections_translator.rs index 3865a9c026..e8468d9d4c 100644 --- a/lib/wasm/src/sections_translator.rs +++ b/lib/wasm/src/sections_translator.rs @@ -9,32 +9,32 @@ //! interpreted on the fly. use cranelift_codegen::ir::{self, AbiParam, Signature}; use cranelift_entity::EntityRef; -use environ::{ModuleEnvironment, WasmError, WasmResult}; +use environ::{ModuleEnvironment, WasmResult}; use std::str::from_utf8; use std::vec::Vec; use translation_utils::{ type_to_type, FuncIndex, Global, GlobalIndex, GlobalInit, Memory, MemoryIndex, SignatureIndex, Table, TableElementType, TableIndex, }; -use wasmparser; use wasmparser::{ - ExternalKind, FuncType, ImportSectionEntryType, MemoryType, Operator, Parser, ParserState, - WasmDecoder, + self, CodeSectionReader, Data, DataSectionReader, Element, ElementSectionReader, Export, + ExportSectionReader, ExternalKind, FuncType, FunctionSectionReader, GlobalSectionReader, + GlobalType, Import, ImportSectionEntryType, ImportSectionReader, MemorySectionReader, + MemoryType, Operator, TableSectionReader, TypeSectionReader, }; -/// Reads the Type Section of the wasm module and returns the corresponding function signatures. -pub fn parse_function_signatures( - parser: &mut Parser, +/// Parses the Type section of the wasm module. +pub fn parse_type_section( + types: TypeSectionReader, environ: &mut ModuleEnvironment, ) -> WasmResult<()> { - loop { - match *parser.read() { - ParserState::EndSection => break, - ParserState::TypeSectionEntry(FuncType { + for entry in types { + match entry? { + FuncType { form: wasmparser::Type::Func, ref params, ref returns, - }) => { + } => { let mut sig = Signature::new(environ.target_config().default_call_conv); sig.params.extend(params.iter().map(|ty| { let cret_arg: ir::Type = type_to_type(*ty) @@ -48,24 +48,23 @@ pub fn parse_function_signatures( })); environ.declare_signature(&sig); } - ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)), - ref s => panic!("unexpected section content: {:?}", s), + ref s => panic!("unsupported type: {:?}", s), } } Ok(()) } -/// Retrieves the imports from the imports section of the binary. +/// Parses the Import section of the wasm module. pub fn parse_import_section<'data>( - parser: &mut Parser<'data>, + imports: ImportSectionReader<'data>, environ: &mut ModuleEnvironment<'data>, ) -> WasmResult<()> { - loop { - match *parser.read() { - ParserState::ImportSectionEntry { - ty: ImportSectionEntryType::Function(sig), + for entry in imports { + match entry? { + Import { module, field, + ty: ImportSectionEntryType::Function(sig), } => { // The input has already been validated, so we should be able to // assume valid UTF-8 and use `from_utf8_unchecked` if performance @@ -78,7 +77,7 @@ pub fn parse_import_section<'data>( field_name, ); } - ParserState::ImportSectionEntry { + Import { ty: ImportSectionEntryType::Memory(MemoryType { limits: ref memlimits, @@ -92,7 +91,7 @@ pub fn parse_import_section<'data>( shared, }); } - ParserState::ImportSectionEntry { + Import { ty: ImportSectionEntryType::Global(ref ty), .. } => { @@ -102,7 +101,7 @@ pub fn parse_import_section<'data>( initializer: GlobalInit::Import(), }); } - ParserState::ImportSectionEntry { + Import { ty: ImportSectionEntryType::Table(ref tab), .. } => environ.declare_table(Table { @@ -113,333 +112,203 @@ pub fn parse_import_section<'data>( size: tab.limits.initial as usize, maximum: tab.limits.maximum.map(|x| x as usize), }), - ParserState::EndSection => break, - ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)), - ref s => panic!("unexpected section content: {:?}", s), - }; - } - Ok(()) -} - -/// Retrieves the correspondences between functions and signatures from the function section -pub fn parse_function_section( - parser: &mut Parser, - environ: &mut ModuleEnvironment, -) -> WasmResult<()> { - loop { - match *parser.read() { - ParserState::FunctionSectionEntry(sigindex) => { - environ.declare_func_type(SignatureIndex::new(sigindex as usize)); - } - ParserState::EndSection => break, - ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)), - ref s => panic!("unexpected section content: {:?}", s), - }; - } - Ok(()) -} - -/// Retrieves the names of the functions from the export section -pub fn parse_export_section<'data>( - parser: &mut Parser<'data>, - environ: &mut ModuleEnvironment<'data>, -) -> WasmResult<()> { - loop { - match *parser.read() { - ParserState::ExportSectionEntry { - field, - ref kind, - index, - } => { - // The input has already been validated, so we should be able to - // assume valid UTF-8 and use `from_utf8_unchecked` if performance - // becomes a concern here. - let name = from_utf8(field).unwrap(); - let index = index as usize; - match *kind { - ExternalKind::Function => { - environ.declare_func_export(FuncIndex::new(index), name) - } - ExternalKind::Table => { - environ.declare_table_export(TableIndex::new(index), name) - } - ExternalKind::Memory => { - environ.declare_memory_export(MemoryIndex::new(index), name) - } - ExternalKind::Global => { - environ.declare_global_export(GlobalIndex::new(index), name) - } - } - } - ParserState::EndSection => break, - ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)), - ref s => panic!("unexpected section content: {:?}", s), - }; - } - Ok(()) -} - -/// Retrieves the start function index from the start section -pub fn parse_start_section(parser: &mut Parser, environ: &mut ModuleEnvironment) -> WasmResult<()> { - loop { - match *parser.read() { - ParserState::StartSectionEntry(index) => { - environ.declare_start_func(FuncIndex::new(index as usize)); - } - ParserState::EndSection => break, - ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)), - ref s => panic!("unexpected section content: {:?}", s), - }; - } - Ok(()) -} - -/// Retrieves the size and maximum fields of memories from the memory section -pub fn parse_memory_section( - parser: &mut Parser, - environ: &mut ModuleEnvironment, -) -> WasmResult<()> { - loop { - match *parser.read() { - ParserState::MemorySectionEntry(ref ty) => { - environ.declare_memory(Memory { - pages_count: ty.limits.initial as usize, - maximum: ty.limits.maximum.map(|x| x as usize), - shared: ty.shared, - }); - } - ParserState::EndSection => break, - ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)), - ref s => panic!("unexpected section content: {:?}", s), - }; - } - Ok(()) -} - -/// Retrieves the size and maximum fields of memories from the memory section -pub fn parse_global_section( - parser: &mut Parser, - environ: &mut ModuleEnvironment, -) -> WasmResult<()> { - loop { - let (content_type, mutability) = match *parser.read() { - ParserState::BeginGlobalSectionEntry(ref ty) => (ty.content_type, ty.mutable), - ParserState::EndSection => break, - ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)), - ref s => panic!("unexpected section content: {:?}", s), - }; - match *parser.read() { - ParserState::BeginInitExpressionBody => (), - ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)), - ref s => panic!("unexpected section content: {:?}", s), } - let initializer = match *parser.read() { - ParserState::InitExpressionOperator(Operator::I32Const { value }) => { - GlobalInit::I32Const(value) - } - ParserState::InitExpressionOperator(Operator::I64Const { value }) => { - GlobalInit::I64Const(value) - } - ParserState::InitExpressionOperator(Operator::F32Const { value }) => { - GlobalInit::F32Const(value.bits()) - } - ParserState::InitExpressionOperator(Operator::F64Const { value }) => { - GlobalInit::F64Const(value.bits()) - } - ParserState::InitExpressionOperator(Operator::GetGlobal { global_index }) => { + } + Ok(()) +} + +/// Parses the Function section of the wasm module. +pub fn parse_function_section( + functions: FunctionSectionReader, + environ: &mut ModuleEnvironment, +) -> WasmResult<()> { + for entry in functions { + let sigindex = entry?; + environ.declare_func_type(SignatureIndex::new(sigindex as usize)); + } + Ok(()) +} + +/// Parses the Table section of the wasm module. +pub fn parse_table_section( + tables: TableSectionReader, + environ: &mut ModuleEnvironment, +) -> WasmResult<()> { + for entry in tables { + let table = entry?; + environ.declare_table(Table { + ty: match type_to_type(table.element_type) { + Ok(t) => TableElementType::Val(t), + Err(()) => TableElementType::Func(), + }, + size: table.limits.initial as usize, + maximum: table.limits.maximum.map(|x| x as usize), + }); + } + Ok(()) +} + +/// Parses the Memory section of the wasm module. +pub fn parse_memory_section( + memories: MemorySectionReader, + environ: &mut ModuleEnvironment, +) -> WasmResult<()> { + for entry in memories { + let memory = entry?; + environ.declare_memory(Memory { + pages_count: memory.limits.initial as usize, + maximum: memory.limits.maximum.map(|x| x as usize), + shared: memory.shared, + }); + } + Ok(()) +} + +/// Parses the Global section of the wasm module. +pub fn parse_global_section( + globals: GlobalSectionReader, + environ: &mut ModuleEnvironment, +) -> WasmResult<()> { + for entry in globals { + let wasmparser::Global { + ty: GlobalType { + content_type, + mutable, + }, + 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), + Operator::I64Const { value } => GlobalInit::I64Const(value), + Operator::F32Const { value } => GlobalInit::F32Const(value.bits()), + Operator::F64Const { value } => GlobalInit::F64Const(value.bits()), + Operator::GetGlobal { global_index } => { GlobalInit::GlobalRef(GlobalIndex::new(global_index as usize)) } - ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)), - ref s => panic!("unexpected section content: {:?}", s), + ref s => panic!("unsupported init expr in global section: {:?}", s), }; - match *parser.read() { - ParserState::EndInitExpressionBody => (), - ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)), - ref s => panic!("unexpected section content: {:?}", s), - } let global = Global { ty: type_to_type(content_type).unwrap(), - mutability, + mutability: mutable, initializer, }; environ.declare_global(global); - match *parser.read() { - ParserState::EndGlobalSectionEntry => (), - ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)), - ref s => panic!("unexpected section content: {:?}", s), - } } Ok(()) } -pub fn parse_data_section<'data>( - parser: &mut Parser<'data>, +/// Parses the Export section of the wasm module. +pub fn parse_export_section<'data>( + exports: ExportSectionReader<'data>, environ: &mut ModuleEnvironment<'data>, ) -> WasmResult<()> { - loop { - let memory_index = match *parser.read() { - ParserState::BeginDataSectionEntry(memory_index) => memory_index, - ParserState::EndSection => break, - ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)), - ref s => panic!("unexpected section content: {:?}", s), - }; - match *parser.read() { - ParserState::BeginInitExpressionBody => (), - ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)), - ref s => panic!("unexpected section content: {:?}", s), - }; - let (base, offset) = match *parser.read() { - ParserState::InitExpressionOperator(Operator::I32Const { value }) => { - (None, value as u32 as usize) - } - ParserState::InitExpressionOperator(Operator::GetGlobal { global_index }) => { - match environ - .get_global(GlobalIndex::new(global_index as usize)) - .initializer - { - GlobalInit::I32Const(value) => (None, value as u32 as usize), - GlobalInit::Import() => (Some(GlobalIndex::new(global_index as usize)), 0), - _ => panic!("should not happen"), - } - } - ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)), - ref s => panic!("unexpected section content: {:?}", s), - }; - match *parser.read() { - ParserState::EndInitExpressionBody => (), - ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)), - ref s => panic!("unexpected section content: {:?}", s), - }; - match *parser.read() { - ParserState::BeginDataSectionEntryBody(_) => (), - ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)), - ref s => panic!("unexpected section content: {:?}", s), - }; - let mut running_offset = offset; - loop { - let data = match *parser.read() { - ParserState::DataSectionEntryBodyChunk(data) => data, - ParserState::EndDataSectionEntryBody => break, - ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)), - ref s => panic!("unexpected section content: {:?}", s), - }; - environ.declare_data_initialization( - MemoryIndex::new(memory_index as usize), - base, - running_offset, - data, - ); - running_offset += data.len(); + for entry in exports { + let Export { + field, + ref kind, + index, + } = entry?; + + // The input has already been validated, so we should be able to + // assume valid UTF-8 and use `from_utf8_unchecked` if performance + // becomes a concern here. + let name = from_utf8(field).unwrap(); + let index = index as usize; + match *kind { + ExternalKind::Function => environ.declare_func_export(FuncIndex::new(index), name), + ExternalKind::Table => environ.declare_table_export(TableIndex::new(index), name), + ExternalKind::Memory => environ.declare_memory_export(MemoryIndex::new(index), name), + ExternalKind::Global => environ.declare_global_export(GlobalIndex::new(index), name), } - match *parser.read() { - ParserState::EndDataSectionEntry => (), - ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)), - ref s => panic!("unexpected section content: {:?}", s), - }; } Ok(()) } -/// Retrieves the tables from the table section -pub fn parse_table_section(parser: &mut Parser, environ: &mut ModuleEnvironment) -> WasmResult<()> { - loop { - match *parser.read() { - ParserState::TableSectionEntry(ref table) => environ.declare_table(Table { - ty: match type_to_type(table.element_type) { - Ok(t) => TableElementType::Val(t), - Err(()) => TableElementType::Func(), - }, - size: table.limits.initial as usize, - maximum: table.limits.maximum.map(|x| x as usize), - }), - ParserState::EndSection => break, - ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)), - ref s => panic!("unexpected section content: {:?}", s), - }; - } +/// Parses the Start section of the wasm module. +pub fn parse_start_section(index: u32, environ: &mut ModuleEnvironment) -> WasmResult<()> { + environ.declare_start_func(FuncIndex::new(index as usize)); Ok(()) } -/// Retrieves the elements from the element section -pub fn parse_element_section( - parser: &mut Parser, +/// Parses the Element section of the wasm module. +pub fn parse_element_section<'data>( + elements: ElementSectionReader<'data>, environ: &mut ModuleEnvironment, ) -> WasmResult<()> { - loop { - let table_index = match *parser.read() { - ParserState::BeginElementSectionEntry(table_index) => { - TableIndex::new(table_index as usize) - } - ParserState::EndSection => break, - ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)), - ref s => panic!("unexpected section content: {:?}", s), - }; - match *parser.read() { - ParserState::BeginInitExpressionBody => (), - ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)), - ref s => panic!("unexpected section content: {:?}", s), - }; - let (base, offset) = match *parser.read() { - ParserState::InitExpressionOperator(Operator::I32Const { value }) => { - (None, value as u32 as usize) - } - ParserState::InitExpressionOperator(Operator::GetGlobal { global_index }) => { - match environ - .get_global(GlobalIndex::new(global_index as usize)) - .initializer - { - GlobalInit::I32Const(value) => (None, value as u32 as usize), - GlobalInit::Import() => (Some(GlobalIndex::new(global_index as usize)), 0), - _ => panic!("should not happen"), - } - } - ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)), - ref s => panic!("unexpected section content: {:?}", s), - }; - match *parser.read() { - ParserState::EndInitExpressionBody => (), - ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)), - ref s => panic!("unexpected section content: {:?}", s), - }; - match *parser.read() { - ParserState::ElementSectionEntryBody(ref elements) => { - let elems: Vec = elements - .iter() - .map(|&x| FuncIndex::new(x as usize)) - .collect(); - environ.declare_table_elements(table_index, base, offset, elems) - } - ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)), - ref s => panic!("unexpected section content: {:?}", s), - }; - match *parser.read() { - ParserState::EndElementSectionEntry => (), - ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)), - ref s => panic!("unexpected section content: {:?}", s), + for entry in elements { + let Element { + table_index, + init_expr, + items, + } = entry?; + 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::GetGlobal { global_index } => match environ + .get_global(GlobalIndex::new(global_index as usize)) + .initializer + { + GlobalInit::I32Const(value) => (None, value as u32 as usize), + GlobalInit::Import() => (Some(GlobalIndex::new(global_index as usize)), 0), + _ => panic!("should not happen"), + }, + ref s => panic!("unsupported init expr in element section: {:?}", s), }; + let items_reader = items.get_items_reader()?; + let mut elems = Vec::new(); + for item in items_reader { + let x = item?; + elems.push(FuncIndex::new(x as usize)); + } + environ.declare_table_elements(TableIndex::new(table_index as usize), base, offset, elems) } Ok(()) } -/// Parses every function body in the code section and defines the corresponding function. +/// Parses the Code section of the wasm module. pub fn parse_code_section<'data>( - parser: &mut Parser<'data>, + code: CodeSectionReader<'data>, environ: &mut ModuleEnvironment<'data>, ) -> WasmResult<()> { - loop { - match *parser.read() { - ParserState::BeginFunctionBody { .. } => {} - ParserState::EndSection => break, - ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)), - ref s => panic!("wrong content in code section: {:?}", s), - } - let mut reader = parser.create_binary_reader(); + for body in code { + let mut reader = body?.get_binary_reader(); let size = reader.bytes_remaining(); - environ.define_function_body( - reader - .read_bytes(size) - .map_err(WasmError::from_binary_reader_error)?, - )?; + environ.define_function_body(reader.read_bytes(size)?)?; + } + Ok(()) +} + +/// Parses the Data section of the wasm module. +pub fn parse_data_section<'data>( + data: DataSectionReader<'data>, + environ: &mut ModuleEnvironment<'data>, +) -> WasmResult<()> { + for entry in data { + let Data { + memory_index, + init_expr, + data, + } = entry?; + 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::GetGlobal { global_index } => match environ + .get_global(GlobalIndex::new(global_index as usize)) + .initializer + { + GlobalInit::I32Const(value) => (None, value as u32 as usize), + GlobalInit::Import() => (Some(GlobalIndex::new(global_index as usize)), 0), + _ => panic!("should not happen"), + }, + ref s => panic!("unsupported init expr in data section: {:?}", s), + }; + environ.declare_data_initialization( + MemoryIndex::new(memory_index as usize), + base, + offset, + data, + ); } Ok(()) }