Update to the new wasmparser and port to the new readers API.

The new wasmparser API provides dedicated reader types for each section
type, which significantly simplifies the code.

This also changes WasmError::from_binary_reader_error into a From
trait so that we don't have to do .map_err(from_binary_reader_error)
throughout the code.
This commit is contained in:
Dan Gohman
2018-10-23 16:34:29 -07:00
parent 9e084dbadc
commit 5ea6c57b95
6 changed files with 319 additions and 430 deletions

View File

@@ -10,7 +10,7 @@ readme = "README.md"
keywords = ["webassembly", "wasm"] keywords = ["webassembly", "wasm"]
[dependencies] [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-codegen = { path = "../codegen", version = "0.22.0", default-features = false }
cranelift-entity = { path = "../entity", 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 } cranelift-frontend = { path = "../frontend", version = "0.22.0", default-features = false }

View File

@@ -3,6 +3,7 @@
use cranelift_codegen::cursor::FuncCursor; use cranelift_codegen::cursor::FuncCursor;
use cranelift_codegen::ir::{self, InstBuilder}; use cranelift_codegen::ir::{self, InstBuilder};
use cranelift_codegen::isa::TargetFrontendConfig; use cranelift_codegen::isa::TargetFrontendConfig;
use std::convert::From;
use std::vec::Vec; use std::vec::Vec;
use translation_utils::{ use translation_utils::{
FuncIndex, Global, GlobalIndex, Memory, MemoryIndex, SignatureIndex, Table, TableIndex, FuncIndex, Global, GlobalIndex, Memory, MemoryIndex, SignatureIndex, Table, TableIndex,
@@ -62,9 +63,9 @@ pub enum WasmError {
ImplLimitExceeded, ImplLimitExceeded,
} }
impl WasmError { impl From<BinaryReaderError> for WasmError {
/// Convert from a `BinaryReaderError` to a `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; let BinaryReaderError { message, offset } = e;
WasmError::InvalidWebAssembly { message, offset } WasmError::InvalidWebAssembly { message, offset }
} }

View File

@@ -9,7 +9,7 @@ use cranelift_codegen::entity::EntityRef;
use cranelift_codegen::ir::{self, Ebb, InstBuilder}; use cranelift_codegen::ir::{self, Ebb, InstBuilder};
use cranelift_codegen::timing; use cranelift_codegen::timing;
use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable}; use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable};
use environ::{FuncEnvironment, ReturnMode, WasmError, WasmResult}; use environ::{FuncEnvironment, ReturnMode, WasmResult};
use state::TranslationState; use state::TranslationState;
use wasmparser::{self, BinaryReader}; use wasmparser::{self, BinaryReader};
@@ -135,16 +135,12 @@ fn parse_local_decls(
num_params: usize, num_params: usize,
) -> WasmResult<()> { ) -> WasmResult<()> {
let mut next_local = num_params; let mut next_local = num_params;
let local_count = reader let local_count = reader.read_local_count()?;
.read_local_count()
.map_err(WasmError::from_binary_reader_error)?;
let mut locals_total = 0; let mut locals_total = 0;
for _ in 0..local_count { for _ in 0..local_count {
builder.set_srcloc(cur_srcloc(reader)); builder.set_srcloc(cur_srcloc(reader));
let (count, ty) = reader let (count, ty) = reader.read_local_decl(&mut locals_total)?;
.read_local_decl(&mut locals_total)
.map_err(WasmError::from_binary_reader_error)?;
declare_locals(builder, count, ty, &mut next_local); declare_locals(builder, count, ty, &mut next_local);
} }
@@ -195,9 +191,7 @@ fn parse_function_body<FE: FuncEnvironment + ?Sized>(
// Keep going until the final `End` operator which pops the outermost block. // Keep going until the final `End` operator which pops the outermost block.
while !state.control_stack.is_empty() { while !state.control_stack.is_empty() {
builder.set_srcloc(cur_srcloc(&reader)); builder.set_srcloc(cur_srcloc(&reader));
let op = reader let op = reader.read_operator()?;
.read_operator()
.map_err(WasmError::from_binary_reader_error)?;
translate_operator(op, builder, state, environ)?; translate_operator(op, builder, state, environ)?;
} }

View File

@@ -76,6 +76,7 @@ mod std {
pub use self::alloc::string; pub use self::alloc::string;
pub use self::alloc::vec; pub use self::alloc::vec;
pub use core::convert;
pub use core::fmt; pub use core::fmt;
pub use core::option; pub use core::option;
pub use core::{cmp, i32, str, u32}; pub use core::{cmp, i32, str, u32};

View File

@@ -1,119 +1,143 @@
//! Translation skeleton that traverses the whole WebAssembly module and call helper functions //! Translation skeleton that traverses the whole WebAssembly module and call helper functions
//! to deal with each part of it. //! to deal with each part of it.
use cranelift_codegen::timing; use cranelift_codegen::timing;
use environ::{ModuleEnvironment, WasmError, WasmResult}; use environ::{ModuleEnvironment, WasmResult};
use sections_translator::{ use sections_translator::{
parse_code_section, parse_data_section, parse_element_section, parse_export_section, 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_function_section, parse_global_section, parse_import_section, parse_memory_section,
parse_memory_section, parse_start_section, parse_table_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 /// Translate a sequence of bytes forming a valid Wasm binary into a list of valid Cranelift IR
/// [`Function`](../codegen/ir/function/struct.Function.html). /// [`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>( pub fn translate_module<'data>(
data: &'data [u8], data: &'data [u8],
environ: &mut ModuleEnvironment<'data>, environ: &mut ModuleEnvironment<'data>,
) -> WasmResult<()> { ) -> WasmResult<()> {
let _tt = timing::wasm_translate_module(); let _tt = timing::wasm_translate_module();
let mut parser = Parser::new(data); let mut reader = ModuleReader::new(data)?;
match *parser.read() {
ParserState::BeginWasm { .. } => {} reader.skip_custom_sections()?;
ParserState::Error(e) => { if reader.eof() {
return Err(WasmError::from_binary_reader_error(e)); return Ok(());
} }
ref s => panic!("modules should begin properly: {:?}", s), 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(());
} }
let mut next_input = ParserInput::Default; section = reader.read()?;
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, if let SectionCode::Import = section.code {
.. let imports = section.get_import_section_reader()?;
} => { parse_import_section(imports, environ)?;
parse_import_section(&mut parser, environ)?;
next_input = ParserInput::Default; reader.skip_custom_sections()?;
if reader.eof() {
return Ok(());
} }
ParserState::BeginSection { section = reader.read()?;
code: SectionCode::Function,
..
} => {
parse_function_section(&mut parser, environ)?;
next_input = ParserInput::Default;
} }
ParserState::BeginSection {
code: SectionCode::Table, if let SectionCode::Function = section.code {
.. let functions = section.get_function_section_reader()?;
} => { parse_function_section(functions, environ)?;
parse_table_section(&mut parser, environ)?;
reader.skip_custom_sections()?;
if reader.eof() {
return Ok(());
} }
ParserState::BeginSection { section = reader.read()?;
code: SectionCode::Memory,
..
} => {
parse_memory_section(&mut parser, environ)?;
next_input = ParserInput::Default;
} }
ParserState::BeginSection {
code: SectionCode::Global, if let SectionCode::Table = section.code {
.. let tables = section.get_table_section_reader()?;
} => { parse_table_section(tables, environ)?;
parse_global_section(&mut parser, environ)?;
next_input = ParserInput::Default; reader.skip_custom_sections()?;
if reader.eof() {
return Ok(());
} }
ParserState::BeginSection { section = reader.read()?;
code: SectionCode::Export,
..
} => {
parse_export_section(&mut parser, environ)?;
next_input = ParserInput::Default;
} }
ParserState::BeginSection {
code: SectionCode::Start, if let SectionCode::Memory = section.code {
.. let memories = section.get_memory_section_reader()?;
} => { parse_memory_section(memories, environ)?;
parse_start_section(&mut parser, environ)?;
next_input = ParserInput::Default; reader.skip_custom_sections()?;
if reader.eof() {
return Ok(());
} }
ParserState::BeginSection { section = reader.read()?;
code: SectionCode::Element,
..
} => {
parse_element_section(&mut parser, environ)?;
next_input = ParserInput::Default;
} }
ParserState::BeginSection {
code: SectionCode::Code, if let SectionCode::Global = section.code {
.. let globals = section.get_global_section_reader()?;
} => parse_code_section(&mut parser, environ)?, parse_global_section(globals, environ)?;
ParserState::EndSection => {
next_input = ParserInput::Default; reader.skip_custom_sections()?;
if reader.eof() {
return Ok(());
} }
ParserState::EndWasm => return Ok(()), section = reader.read()?;
ParserState::BeginSection {
code: SectionCode::Data,
..
} => {
parse_data_section(&mut parser, environ)?;
} }
ParserState::BeginSection {
code: SectionCode::Custom { .. }, if let SectionCode::Export = section.code {
.. let exports = section.get_export_section_reader()?;
} => { parse_export_section(exports, environ)?;
// Ignore unknown custom sections.
next_input = ParserInput::SkipSection; reader.skip_custom_sections()?;
if reader.eof() {
return Ok(());
} }
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)), section = reader.read()?;
_ => panic!("wrong content in the preamble"),
};
} }
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(())
} }

View File

@@ -9,32 +9,32 @@
//! interpreted on the fly. //! interpreted on the fly.
use cranelift_codegen::ir::{self, AbiParam, Signature}; use cranelift_codegen::ir::{self, AbiParam, Signature};
use cranelift_entity::EntityRef; use cranelift_entity::EntityRef;
use environ::{ModuleEnvironment, WasmError, WasmResult}; use environ::{ModuleEnvironment, WasmResult};
use std::str::from_utf8; use std::str::from_utf8;
use std::vec::Vec; use std::vec::Vec;
use translation_utils::{ use translation_utils::{
type_to_type, FuncIndex, Global, GlobalIndex, GlobalInit, Memory, MemoryIndex, SignatureIndex, type_to_type, FuncIndex, Global, GlobalIndex, GlobalInit, Memory, MemoryIndex, SignatureIndex,
Table, TableElementType, TableIndex, Table, TableElementType, TableIndex,
}; };
use wasmparser;
use wasmparser::{ use wasmparser::{
ExternalKind, FuncType, ImportSectionEntryType, MemoryType, Operator, Parser, ParserState, self, CodeSectionReader, Data, DataSectionReader, Element, ElementSectionReader, Export,
WasmDecoder, 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. /// Parses the Type section of the wasm module.
pub fn parse_function_signatures( pub fn parse_type_section(
parser: &mut Parser, types: TypeSectionReader,
environ: &mut ModuleEnvironment, environ: &mut ModuleEnvironment,
) -> WasmResult<()> { ) -> WasmResult<()> {
loop { for entry in types {
match *parser.read() { match entry? {
ParserState::EndSection => break, FuncType {
ParserState::TypeSectionEntry(FuncType {
form: wasmparser::Type::Func, form: wasmparser::Type::Func,
ref params, ref params,
ref returns, ref returns,
}) => { } => {
let mut sig = Signature::new(environ.target_config().default_call_conv); let mut sig = Signature::new(environ.target_config().default_call_conv);
sig.params.extend(params.iter().map(|ty| { sig.params.extend(params.iter().map(|ty| {
let cret_arg: ir::Type = type_to_type(*ty) let cret_arg: ir::Type = type_to_type(*ty)
@@ -48,24 +48,23 @@ pub fn parse_function_signatures(
})); }));
environ.declare_signature(&sig); environ.declare_signature(&sig);
} }
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)), ref s => panic!("unsupported type: {:?}", s),
ref s => panic!("unexpected section content: {:?}", s),
} }
} }
Ok(()) 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>( pub fn parse_import_section<'data>(
parser: &mut Parser<'data>, imports: ImportSectionReader<'data>,
environ: &mut ModuleEnvironment<'data>, environ: &mut ModuleEnvironment<'data>,
) -> WasmResult<()> { ) -> WasmResult<()> {
loop { for entry in imports {
match *parser.read() { match entry? {
ParserState::ImportSectionEntry { Import {
ty: ImportSectionEntryType::Function(sig),
module, module,
field, field,
ty: ImportSectionEntryType::Function(sig),
} => { } => {
// The input has already been validated, so we should be able to // The input has already been validated, so we should be able to
// assume valid UTF-8 and use `from_utf8_unchecked` if performance // assume valid UTF-8 and use `from_utf8_unchecked` if performance
@@ -78,7 +77,7 @@ pub fn parse_import_section<'data>(
field_name, field_name,
); );
} }
ParserState::ImportSectionEntry { Import {
ty: ty:
ImportSectionEntryType::Memory(MemoryType { ImportSectionEntryType::Memory(MemoryType {
limits: ref memlimits, limits: ref memlimits,
@@ -92,7 +91,7 @@ pub fn parse_import_section<'data>(
shared, shared,
}); });
} }
ParserState::ImportSectionEntry { Import {
ty: ImportSectionEntryType::Global(ref ty), ty: ImportSectionEntryType::Global(ref ty),
.. ..
} => { } => {
@@ -102,7 +101,7 @@ pub fn parse_import_section<'data>(
initializer: GlobalInit::Import(), initializer: GlobalInit::Import(),
}); });
} }
ParserState::ImportSectionEntry { Import {
ty: ImportSectionEntryType::Table(ref tab), ty: ImportSectionEntryType::Table(ref tab),
.. ..
} => environ.declare_table(Table { } => environ.declare_table(Table {
@@ -113,333 +112,203 @@ pub fn parse_import_section<'data>(
size: tab.limits.initial as usize, size: tab.limits.initial as usize,
maximum: tab.limits.maximum.map(|x| x 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(()) Ok(())
} }
/// Retrieves the correspondences between functions and signatures from the function section /// Parses the Function section of the wasm module.
pub fn parse_function_section( pub fn parse_function_section(
parser: &mut Parser, functions: FunctionSectionReader,
environ: &mut ModuleEnvironment, environ: &mut ModuleEnvironment,
) -> WasmResult<()> { ) -> WasmResult<()> {
loop { for entry in functions {
match *parser.read() { let sigindex = entry?;
ParserState::FunctionSectionEntry(sigindex) => {
environ.declare_func_type(SignatureIndex::new(sigindex as usize)); 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(()) Ok(())
} }
/// Retrieves the names of the functions from the export section /// Parses the Table section of the wasm module.
pub fn parse_export_section<'data>( pub fn parse_table_section(
parser: &mut Parser<'data>, tables: TableSectionReader,
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, environ: &mut ModuleEnvironment,
) -> WasmResult<()> { ) -> WasmResult<()> {
loop { for entry in tables {
match *parser.read() { let table = entry?;
ParserState::MemorySectionEntry(ref ty) => { environ.declare_table(Table {
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 }) => {
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),
};
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,
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>,
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();
}
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) { ty: match type_to_type(table.element_type) {
Ok(t) => TableElementType::Val(t), Ok(t) => TableElementType::Val(t),
Err(()) => TableElementType::Func(), Err(()) => TableElementType::Func(),
}, },
size: table.limits.initial as usize, size: table.limits.initial as usize,
maximum: table.limits.maximum.map(|x| x 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),
};
} }
Ok(()) Ok(())
} }
/// Retrieves the elements from the element section /// Parses the Memory section of the wasm module.
pub fn parse_element_section( pub fn parse_memory_section(
parser: &mut Parser, memories: MemorySectionReader,
environ: &mut ModuleEnvironment, environ: &mut ModuleEnvironment,
) -> WasmResult<()> { ) -> WasmResult<()> {
loop { for entry in memories {
let table_index = match *parser.read() { let memory = entry?;
ParserState::BeginElementSectionEntry(table_index) => { environ.declare_memory(Memory {
TableIndex::new(table_index as usize) pages_count: memory.limits.initial as usize,
maximum: memory.limits.maximum.map(|x| x as usize),
shared: memory.shared,
});
} }
ParserState::EndSection => break, Ok(())
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)), }
ref s => panic!("unexpected section content: {:?}", s),
}; /// Parses the Global section of the wasm module.
match *parser.read() { pub fn parse_global_section(
ParserState::BeginInitExpressionBody => (), globals: GlobalSectionReader,
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)), environ: &mut ModuleEnvironment,
ref s => panic!("unexpected section content: {:?}", s), ) -> WasmResult<()> {
}; for entry in globals {
let (base, offset) = match *parser.read() { let wasmparser::Global {
ParserState::InitExpressionOperator(Operator::I32Const { value }) => { ty: GlobalType {
(None, value as u32 as usize) 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::InitExpressionOperator(Operator::GetGlobal { global_index }) => { ref s => panic!("unsupported init expr in global section: {:?}", s),
match environ };
let global = Global {
ty: type_to_type(content_type).unwrap(),
mutability: mutable,
initializer,
};
environ.declare_global(global);
}
Ok(())
}
/// Parses the Export section of the wasm module.
pub fn parse_export_section<'data>(
exports: ExportSectionReader<'data>,
environ: &mut ModuleEnvironment<'data>,
) -> WasmResult<()> {
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),
}
}
Ok(())
}
/// 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(())
}
/// Parses the Element section of the wasm module.
pub fn parse_element_section<'data>(
elements: ElementSectionReader<'data>,
environ: &mut ModuleEnvironment,
) -> WasmResult<()> {
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)) .get_global(GlobalIndex::new(global_index as usize))
.initializer .initializer
{ {
GlobalInit::I32Const(value) => (None, value as u32 as usize), GlobalInit::I32Const(value) => (None, value as u32 as usize),
GlobalInit::Import() => (Some(GlobalIndex::new(global_index as usize)), 0), GlobalInit::Import() => (Some(GlobalIndex::new(global_index as usize)), 0),
_ => panic!("should not happen"), _ => 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)
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<FuncIndex> = 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),
};
} }
Ok(()) 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>( pub fn parse_code_section<'data>(
parser: &mut Parser<'data>, code: CodeSectionReader<'data>,
environ: &mut ModuleEnvironment<'data>, environ: &mut ModuleEnvironment<'data>,
) -> WasmResult<()> { ) -> WasmResult<()> {
loop { for body in code {
match *parser.read() { let mut reader = body?.get_binary_reader();
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();
let size = reader.bytes_remaining(); let size = reader.bytes_remaining();
environ.define_function_body( environ.define_function_body(reader.read_bytes(size)?)?;
reader }
.read_bytes(size) Ok(())
.map_err(WasmError::from_binary_reader_error)?, }
)?;
/// 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(()) Ok(())
} }