Allow wasm embedders to reject wasm modules with unsupported features. (#345)
Define `WasmError` (and an accompanying `WasmResult`) to represent errors translating WebAssembly functions. Make `translate_call` and related functions return `WasmResult`s so that embedders have the flexibility to reject features they don't support. Move `InvalidInput` out of `CtonError` and into `WasmError`, where it's now named `InvalidWebAssembly`, as it's a WebAssembly-specific error condition. Also extend it to preserve the original error message and bytecode offset.
This commit is contained in:
@@ -105,7 +105,9 @@ fn handle_module(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut dummy_environ = DummyEnvironment::with_flags(fisa.flags.clone());
|
let mut dummy_environ = DummyEnvironment::with_flags(fisa.flags.clone());
|
||||||
translate_module(&data, &mut dummy_environ)?;
|
translate_module(&data, &mut dummy_environ).map_err(
|
||||||
|
|e| e.to_string(),
|
||||||
|
)?;
|
||||||
|
|
||||||
terminal.fg(term::color::GREEN).unwrap();
|
terminal.fg(term::color::GREEN).unwrap();
|
||||||
vprintln!(flag_verbose, "ok");
|
vprintln!(flag_verbose, "ok");
|
||||||
|
|||||||
@@ -7,13 +7,6 @@ use verifier;
|
|||||||
/// When Cretonne fails to compile a function, it will return one of these error codes.
|
/// When Cretonne fails to compile a function, it will return one of these error codes.
|
||||||
#[derive(Fail, Debug, PartialEq, Eq)]
|
#[derive(Fail, Debug, PartialEq, Eq)]
|
||||||
pub enum CtonError {
|
pub enum CtonError {
|
||||||
/// The input is invalid.
|
|
||||||
///
|
|
||||||
/// This error code is used by a WebAssembly translator when it encounters invalid WebAssembly
|
|
||||||
/// code. This should never happen for validated WebAssembly code.
|
|
||||||
#[fail(display = "Invalid input code")]
|
|
||||||
InvalidInput,
|
|
||||||
|
|
||||||
/// An IR verifier error.
|
/// An IR verifier error.
|
||||||
///
|
///
|
||||||
/// This always represents a bug, either in the code that generated IR for Cretonne, or a bug
|
/// This always represents a bug, either in the code that generated IR for Cretonne, or a bug
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ wasmparser = { version = "0.16.1", default-features = false }
|
|||||||
cretonne-codegen = { path = "../codegen", version = "0.8.0", default-features = false }
|
cretonne-codegen = { path = "../codegen", version = "0.8.0", default-features = false }
|
||||||
cretonne-frontend = { path = "../frontend", version = "0.8.0", default-features = false }
|
cretonne-frontend = { path = "../frontend", version = "0.8.0", default-features = false }
|
||||||
hashmap_core = { version = "0.1.4", optional = true }
|
hashmap_core = { version = "0.1.4", optional = true }
|
||||||
|
failure = { version = "0.1.1", default-features = false, features = ["derive"] }
|
||||||
|
failure_derive = { version = "0.1.1", default-features = false }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tempdir = "0.3.5"
|
tempdir = "0.3.5"
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ use cretonne_codegen::ir::types::*;
|
|||||||
use cretonne_codegen::ir::{self, InstBuilder, JumpTableData, MemFlags};
|
use cretonne_codegen::ir::{self, InstBuilder, JumpTableData, MemFlags};
|
||||||
use cretonne_codegen::packed_option::ReservedValue;
|
use cretonne_codegen::packed_option::ReservedValue;
|
||||||
use cretonne_frontend::{FunctionBuilder, Variable};
|
use cretonne_frontend::{FunctionBuilder, Variable};
|
||||||
use environ::{FuncEnvironment, GlobalValue};
|
use environ::{FuncEnvironment, GlobalValue, WasmResult};
|
||||||
use state::{ControlStackFrame, TranslationState};
|
use state::{ControlStackFrame, TranslationState};
|
||||||
use std::collections::{hash_map, HashMap};
|
use std::collections::{hash_map, HashMap};
|
||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
@@ -45,13 +45,13 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||||||
builder: &mut FunctionBuilder<Variable>,
|
builder: &mut FunctionBuilder<Variable>,
|
||||||
state: &mut TranslationState,
|
state: &mut TranslationState,
|
||||||
environ: &mut FE,
|
environ: &mut FE,
|
||||||
) {
|
) -> WasmResult<()> {
|
||||||
if !state.reachable {
|
if !state.reachable {
|
||||||
return translate_unreachable_operator(&op, builder, state);
|
return Ok(translate_unreachable_operator(&op, builder, state));
|
||||||
}
|
}
|
||||||
|
|
||||||
// This big match treats all Wasm code operators.
|
// This big match treats all Wasm code operators.
|
||||||
match op {
|
Ok(match op {
|
||||||
/********************************** Locals ****************************************
|
/********************************** Locals ****************************************
|
||||||
* `get_local` and `set_local` are treated as non-SSA variables and will completely
|
* `get_local` and `set_local` are treated as non-SSA variables and will completely
|
||||||
* disappear in the Cretonne Code
|
* disappear in the Cretonne Code
|
||||||
@@ -362,7 +362,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||||||
function_index as FunctionIndex,
|
function_index as FunctionIndex,
|
||||||
fref,
|
fref,
|
||||||
state.peekn(num_args),
|
state.peekn(num_args),
|
||||||
);
|
)?;
|
||||||
state.popn(num_args);
|
state.popn(num_args);
|
||||||
state.pushn(builder.inst_results(call));
|
state.pushn(builder.inst_results(call));
|
||||||
}
|
}
|
||||||
@@ -378,7 +378,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||||||
sigref,
|
sigref,
|
||||||
callee,
|
callee,
|
||||||
state.peekn(num_args),
|
state.peekn(num_args),
|
||||||
);
|
)?;
|
||||||
state.popn(num_args);
|
state.popn(num_args);
|
||||||
state.pushn(builder.inst_results(call));
|
state.pushn(builder.inst_results(call));
|
||||||
}
|
}
|
||||||
@@ -397,7 +397,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||||||
heap_index,
|
heap_index,
|
||||||
heap,
|
heap,
|
||||||
val,
|
val,
|
||||||
))
|
)?)
|
||||||
}
|
}
|
||||||
Operator::CurrentMemory { reserved } => {
|
Operator::CurrentMemory { reserved } => {
|
||||||
let heap_index = reserved as MemoryIndex;
|
let heap_index = reserved as MemoryIndex;
|
||||||
@@ -406,7 +406,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||||||
builder.cursor(),
|
builder.cursor(),
|
||||||
heap_index,
|
heap_index,
|
||||||
heap,
|
heap,
|
||||||
));
|
)?);
|
||||||
}
|
}
|
||||||
/******************************* Load instructions ***********************************
|
/******************************* Load instructions ***********************************
|
||||||
* Wasm specifies an integer alignment flag but we drop it in Cretonne.
|
* Wasm specifies an integer alignment flag but we drop it in Cretonne.
|
||||||
@@ -857,7 +857,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||||||
Operator::I64AtomicRmw32UCmpxchg { .. } => {
|
Operator::I64AtomicRmw32UCmpxchg { .. } => {
|
||||||
panic!("proposed thread operators not yet supported");
|
panic!("proposed thread operators not yet supported");
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clippy warns us of some fields we are deliberately ignoring
|
// Clippy warns us of some fields we are deliberately ignoring
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use cretonne_codegen::cursor::FuncCursor;
|
|||||||
use cretonne_codegen::ir::types::*;
|
use cretonne_codegen::ir::types::*;
|
||||||
use cretonne_codegen::ir::{self, InstBuilder};
|
use cretonne_codegen::ir::{self, InstBuilder};
|
||||||
use cretonne_codegen::settings;
|
use cretonne_codegen::settings;
|
||||||
use environ::{FuncEnvironment, GlobalValue, ModuleEnvironment};
|
use environ::{FuncEnvironment, GlobalValue, ModuleEnvironment, WasmResult};
|
||||||
use func_translator::FuncTranslator;
|
use func_translator::FuncTranslator;
|
||||||
use std::string::String;
|
use std::string::String;
|
||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
@@ -196,7 +196,7 @@ impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environ
|
|||||||
sig_ref: ir::SigRef,
|
sig_ref: ir::SigRef,
|
||||||
callee: ir::Value,
|
callee: ir::Value,
|
||||||
call_args: &[ir::Value],
|
call_args: &[ir::Value],
|
||||||
) -> ir::Inst {
|
) -> WasmResult<ir::Inst> {
|
||||||
// Pass the current function's vmctx parameter on to the callee.
|
// Pass the current function's vmctx parameter on to the callee.
|
||||||
let vmctx = pos.func
|
let vmctx = pos.func
|
||||||
.special_param(ir::ArgumentPurpose::VMContext)
|
.special_param(ir::ArgumentPurpose::VMContext)
|
||||||
@@ -224,9 +224,11 @@ impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environ
|
|||||||
args.extend(call_args.iter().cloned(), &mut pos.func.dfg.value_lists);
|
args.extend(call_args.iter().cloned(), &mut pos.func.dfg.value_lists);
|
||||||
args.push(vmctx, &mut pos.func.dfg.value_lists);
|
args.push(vmctx, &mut pos.func.dfg.value_lists);
|
||||||
|
|
||||||
pos.ins()
|
Ok(
|
||||||
.CallIndirect(ir::Opcode::CallIndirect, VOID, sig_ref, args)
|
pos.ins()
|
||||||
.0
|
.CallIndirect(ir::Opcode::CallIndirect, VOID, sig_ref, args)
|
||||||
|
.0,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn translate_call(
|
fn translate_call(
|
||||||
@@ -235,7 +237,7 @@ impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environ
|
|||||||
_callee_index: FunctionIndex,
|
_callee_index: FunctionIndex,
|
||||||
callee: ir::FuncRef,
|
callee: ir::FuncRef,
|
||||||
call_args: &[ir::Value],
|
call_args: &[ir::Value],
|
||||||
) -> ir::Inst {
|
) -> WasmResult<ir::Inst> {
|
||||||
// Pass the current function's vmctx parameter on to the callee.
|
// Pass the current function's vmctx parameter on to the callee.
|
||||||
let vmctx = pos.func
|
let vmctx = pos.func
|
||||||
.special_param(ir::ArgumentPurpose::VMContext)
|
.special_param(ir::ArgumentPurpose::VMContext)
|
||||||
@@ -247,7 +249,7 @@ impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environ
|
|||||||
args.extend(call_args.iter().cloned(), &mut pos.func.dfg.value_lists);
|
args.extend(call_args.iter().cloned(), &mut pos.func.dfg.value_lists);
|
||||||
args.push(vmctx, &mut pos.func.dfg.value_lists);
|
args.push(vmctx, &mut pos.func.dfg.value_lists);
|
||||||
|
|
||||||
pos.ins().Call(ir::Opcode::Call, VOID, callee, args).0
|
Ok(pos.ins().Call(ir::Opcode::Call, VOID, callee, args).0)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn translate_grow_memory(
|
fn translate_grow_memory(
|
||||||
@@ -256,8 +258,8 @@ impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environ
|
|||||||
_index: MemoryIndex,
|
_index: MemoryIndex,
|
||||||
_heap: ir::Heap,
|
_heap: ir::Heap,
|
||||||
_val: ir::Value,
|
_val: ir::Value,
|
||||||
) -> ir::Value {
|
) -> WasmResult<ir::Value> {
|
||||||
pos.ins().iconst(I32, -1)
|
Ok(pos.ins().iconst(I32, -1))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn translate_current_memory(
|
fn translate_current_memory(
|
||||||
@@ -265,8 +267,8 @@ impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environ
|
|||||||
mut pos: FuncCursor,
|
mut pos: FuncCursor,
|
||||||
_index: MemoryIndex,
|
_index: MemoryIndex,
|
||||||
_heap: ir::Heap,
|
_heap: ir::Heap,
|
||||||
) -> ir::Value {
|
) -> WasmResult<ir::Value> {
|
||||||
pos.ins().iconst(I32, -1)
|
Ok(pos.ins().iconst(I32, -1))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -385,7 +387,7 @@ impl<'data> ModuleEnvironment<'data> for DummyEnvironment {
|
|||||||
self.info.start_func = Some(func_index);
|
self.info.start_func = Some(func_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn define_function_body(&mut self, body_bytes: &'data [u8]) -> Result<(), String> {
|
fn define_function_body(&mut self, body_bytes: &'data [u8]) -> WasmResult<()> {
|
||||||
let func = {
|
let func = {
|
||||||
let mut func_environ = DummyFuncEnvironment::new(&self.info);
|
let mut func_environ = DummyFuncEnvironment::new(&self.info);
|
||||||
let function_index = self.get_num_func_imports() + self.info.function_bodies.len();
|
let function_index = self.get_num_func_imports() + self.info.function_bodies.len();
|
||||||
@@ -393,9 +395,11 @@ impl<'data> ModuleEnvironment<'data> for DummyEnvironment {
|
|||||||
let sig = func_environ.vmctx_sig(self.get_func_type(function_index));
|
let sig = func_environ.vmctx_sig(self.get_func_type(function_index));
|
||||||
let mut func = ir::Function::with_name_signature(name, sig);
|
let mut func = ir::Function::with_name_signature(name, sig);
|
||||||
let reader = wasmparser::BinaryReader::new(body_bytes);
|
let reader = wasmparser::BinaryReader::new(body_bytes);
|
||||||
self.trans
|
self.trans.translate_from_reader(
|
||||||
.translate_from_reader(reader, &mut func, &mut func_environ)
|
reader,
|
||||||
.map_err(|e| format!("{}", e))?;
|
&mut func,
|
||||||
|
&mut func_environ,
|
||||||
|
)?;
|
||||||
func
|
func
|
||||||
};
|
};
|
||||||
self.func_bytecode_sizes.push(body_bytes.len());
|
self.func_bytecode_sizes.push(body_bytes.len());
|
||||||
|
|||||||
@@ -4,4 +4,4 @@ mod dummy;
|
|||||||
mod spec;
|
mod spec;
|
||||||
|
|
||||||
pub use environ::dummy::DummyEnvironment;
|
pub use environ::dummy::DummyEnvironment;
|
||||||
pub use environ::spec::{FuncEnvironment, GlobalValue, ModuleEnvironment};
|
pub use environ::spec::{FuncEnvironment, GlobalValue, ModuleEnvironment, WasmError, WasmResult};
|
||||||
|
|||||||
@@ -3,10 +3,10 @@
|
|||||||
use cretonne_codegen::cursor::FuncCursor;
|
use cretonne_codegen::cursor::FuncCursor;
|
||||||
use cretonne_codegen::ir::{self, InstBuilder};
|
use cretonne_codegen::ir::{self, InstBuilder};
|
||||||
use cretonne_codegen::settings::Flags;
|
use cretonne_codegen::settings::Flags;
|
||||||
use std::string::String;
|
|
||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
use translation_utils::{FunctionIndex, Global, GlobalIndex, Memory, MemoryIndex, SignatureIndex,
|
use translation_utils::{FunctionIndex, Global, GlobalIndex, Memory, MemoryIndex, SignatureIndex,
|
||||||
Table, TableIndex};
|
Table, TableIndex};
|
||||||
|
use wasmparser::BinaryReaderError;
|
||||||
|
|
||||||
/// The value of a WebAssembly global variable.
|
/// The value of a WebAssembly global variable.
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
@@ -23,6 +23,49 @@ pub enum GlobalValue {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A WebAssembly translation error.
|
||||||
|
///
|
||||||
|
/// When a WebAssembly function can't be translated, one of these error codes will be returned
|
||||||
|
/// to describe the failure.
|
||||||
|
#[derive(Fail, Debug, PartialEq, Eq)]
|
||||||
|
pub enum WasmError {
|
||||||
|
/// The input WebAssembly code is invalid.
|
||||||
|
///
|
||||||
|
/// This error code is used by a WebAssembly translator when it encounters invalid WebAssembly
|
||||||
|
/// code. This should never happen for validated WebAssembly code.
|
||||||
|
#[fail(display = "Invalid input WebAssembly code at offset {}: {}", _1, _0)]
|
||||||
|
InvalidWebAssembly {
|
||||||
|
message: &'static str,
|
||||||
|
offset: usize,
|
||||||
|
},
|
||||||
|
|
||||||
|
/// A feature used by the WebAssembly code is not supported by the embedding environment.
|
||||||
|
///
|
||||||
|
/// Embedding environments may have their own limitations and feature restrictions.
|
||||||
|
#[fail(display = "Unsupported feature: {}", _0)]
|
||||||
|
Unsupported(&'static str),
|
||||||
|
|
||||||
|
/// An implementation limit was exceeded.
|
||||||
|
///
|
||||||
|
/// Cretonne can compile very large and complicated functions, but the [implementation has
|
||||||
|
/// limits][limits] that cause compilation to fail when they are exceeded.
|
||||||
|
///
|
||||||
|
/// [limits]: https://cretonne.readthedocs.io/en/latest/langref.html#implementation-limits
|
||||||
|
#[fail(display = "Implementation limit exceeded")]
|
||||||
|
ImplLimitExceeded,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WasmError {
|
||||||
|
/// Convert from a `BinaryReaderError` to a `WasmError`.
|
||||||
|
pub fn from_binary_reader_error(e: BinaryReaderError) -> Self {
|
||||||
|
let BinaryReaderError { message, offset } = e;
|
||||||
|
WasmError::InvalidWebAssembly { message, offset }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A convenient alias for a `Result` that uses `WasmError` as the error type.
|
||||||
|
pub type WasmResult<T> = Result<T, WasmError>;
|
||||||
|
|
||||||
/// Environment affecting the translation of a single WebAssembly function.
|
/// Environment affecting the translation of a single WebAssembly function.
|
||||||
///
|
///
|
||||||
/// A `FuncEnvironment` trait object is required to translate a WebAssembly function to Cretonne
|
/// A `FuncEnvironment` trait object is required to translate a WebAssembly function to Cretonne
|
||||||
@@ -99,7 +142,7 @@ pub trait FuncEnvironment {
|
|||||||
sig_ref: ir::SigRef,
|
sig_ref: ir::SigRef,
|
||||||
callee: ir::Value,
|
callee: ir::Value,
|
||||||
call_args: &[ir::Value],
|
call_args: &[ir::Value],
|
||||||
) -> ir::Inst;
|
) -> WasmResult<ir::Inst>;
|
||||||
|
|
||||||
/// Translate a `call` WebAssembly instruction at `pos`.
|
/// Translate a `call` WebAssembly instruction at `pos`.
|
||||||
///
|
///
|
||||||
@@ -114,8 +157,8 @@ pub trait FuncEnvironment {
|
|||||||
_callee_index: FunctionIndex,
|
_callee_index: FunctionIndex,
|
||||||
callee: ir::FuncRef,
|
callee: ir::FuncRef,
|
||||||
call_args: &[ir::Value],
|
call_args: &[ir::Value],
|
||||||
) -> ir::Inst {
|
) -> WasmResult<ir::Inst> {
|
||||||
pos.ins().call(callee, call_args)
|
Ok(pos.ins().call(callee, call_args))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Translate a `grow_memory` WebAssembly instruction.
|
/// Translate a `grow_memory` WebAssembly instruction.
|
||||||
@@ -132,7 +175,7 @@ pub trait FuncEnvironment {
|
|||||||
index: MemoryIndex,
|
index: MemoryIndex,
|
||||||
heap: ir::Heap,
|
heap: ir::Heap,
|
||||||
val: ir::Value,
|
val: ir::Value,
|
||||||
) -> ir::Value;
|
) -> WasmResult<ir::Value>;
|
||||||
|
|
||||||
/// Translates a `current_memory` WebAssembly instruction.
|
/// Translates a `current_memory` WebAssembly instruction.
|
||||||
///
|
///
|
||||||
@@ -145,7 +188,7 @@ pub trait FuncEnvironment {
|
|||||||
pos: FuncCursor,
|
pos: FuncCursor,
|
||||||
index: MemoryIndex,
|
index: MemoryIndex,
|
||||||
heap: ir::Heap,
|
heap: ir::Heap,
|
||||||
) -> ir::Value;
|
) -> WasmResult<ir::Value>;
|
||||||
|
|
||||||
/// Emit code at the beginning of every wasm loop.
|
/// Emit code at the beginning of every wasm loop.
|
||||||
///
|
///
|
||||||
@@ -229,5 +272,5 @@ pub trait ModuleEnvironment<'data> {
|
|||||||
fn declare_start_func(&mut self, index: FunctionIndex);
|
fn declare_start_func(&mut self, index: FunctionIndex);
|
||||||
|
|
||||||
/// Provides the contents of a function body.
|
/// Provides the contents of a function body.
|
||||||
fn define_function_body(&mut self, body_bytes: &'data [u8]) -> Result<(), String>;
|
fn define_function_body(&mut self, body_bytes: &'data [u8]) -> WasmResult<()>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,10 +7,9 @@
|
|||||||
use code_translator::translate_operator;
|
use code_translator::translate_operator;
|
||||||
use cretonne_codegen::entity::EntityRef;
|
use cretonne_codegen::entity::EntityRef;
|
||||||
use cretonne_codegen::ir::{self, Ebb, InstBuilder};
|
use cretonne_codegen::ir::{self, Ebb, InstBuilder};
|
||||||
use cretonne_codegen::result::{CtonError, CtonResult};
|
|
||||||
use cretonne_codegen::timing;
|
use cretonne_codegen::timing;
|
||||||
use cretonne_frontend::{FunctionBuilder, FunctionBuilderContext, Variable};
|
use cretonne_frontend::{FunctionBuilder, FunctionBuilderContext, Variable};
|
||||||
use environ::FuncEnvironment;
|
use environ::{FuncEnvironment, WasmError, WasmResult};
|
||||||
use state::TranslationState;
|
use state::TranslationState;
|
||||||
use wasmparser::{self, BinaryReader};
|
use wasmparser::{self, BinaryReader};
|
||||||
|
|
||||||
@@ -56,7 +55,7 @@ impl FuncTranslator {
|
|||||||
code: &[u8],
|
code: &[u8],
|
||||||
func: &mut ir::Function,
|
func: &mut ir::Function,
|
||||||
environ: &mut FE,
|
environ: &mut FE,
|
||||||
) -> CtonResult {
|
) -> WasmResult<()> {
|
||||||
self.translate_from_reader(BinaryReader::new(code), func, environ)
|
self.translate_from_reader(BinaryReader::new(code), func, environ)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,7 +65,7 @@ impl FuncTranslator {
|
|||||||
mut reader: BinaryReader,
|
mut reader: BinaryReader,
|
||||||
func: &mut ir::Function,
|
func: &mut ir::Function,
|
||||||
environ: &mut FE,
|
environ: &mut FE,
|
||||||
) -> CtonResult {
|
) -> WasmResult<()> {
|
||||||
let _tt = timing::wasm_translate_function();
|
let _tt = timing::wasm_translate_function();
|
||||||
dbg!(
|
dbg!(
|
||||||
"translate({} bytes, {}{})",
|
"translate({} bytes, {}{})",
|
||||||
@@ -134,17 +133,17 @@ fn parse_local_decls(
|
|||||||
reader: &mut BinaryReader,
|
reader: &mut BinaryReader,
|
||||||
builder: &mut FunctionBuilder<Variable>,
|
builder: &mut FunctionBuilder<Variable>,
|
||||||
num_params: usize,
|
num_params: usize,
|
||||||
) -> CtonResult {
|
) -> WasmResult<()> {
|
||||||
let mut next_local = num_params;
|
let mut next_local = num_params;
|
||||||
let local_count = reader.read_local_count().map_err(
|
let local_count = reader.read_local_count().map_err(|e| {
|
||||||
|_| CtonError::InvalidInput,
|
WasmError::from_binary_reader_error(e)
|
||||||
)?;
|
})?;
|
||||||
|
|
||||||
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.read_local_decl(&mut locals_total).map_err(|_| {
|
let (count, ty) = reader.read_local_decl(&mut locals_total).map_err(|e| {
|
||||||
CtonError::InvalidInput
|
WasmError::from_binary_reader_error(e)
|
||||||
})?;
|
})?;
|
||||||
declare_locals(builder, count, ty, &mut next_local);
|
declare_locals(builder, count, ty, &mut next_local);
|
||||||
}
|
}
|
||||||
@@ -189,15 +188,17 @@ fn parse_function_body<FE: FuncEnvironment + ?Sized>(
|
|||||||
builder: &mut FunctionBuilder<Variable>,
|
builder: &mut FunctionBuilder<Variable>,
|
||||||
state: &mut TranslationState,
|
state: &mut TranslationState,
|
||||||
environ: &mut FE,
|
environ: &mut FE,
|
||||||
) -> CtonResult {
|
) -> WasmResult<()> {
|
||||||
// The control stack is initialized with a single block representing the whole function.
|
// The control stack is initialized with a single block representing the whole function.
|
||||||
debug_assert_eq!(state.control_stack.len(), 1, "State not initialized");
|
debug_assert_eq!(state.control_stack.len(), 1, "State not initialized");
|
||||||
|
|
||||||
// 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.read_operator().map_err(|_| CtonError::InvalidInput)?;
|
let op = reader.read_operator().map_err(|e| {
|
||||||
translate_operator(op, builder, state, environ);
|
WasmError::from_binary_reader_error(e)
|
||||||
|
})?;
|
||||||
|
translate_operator(op, builder, state, environ)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The final `End` operator left us in the exit block where we need to manually add a return
|
// The final `End` operator left us in the exit block where we need to manually add a return
|
||||||
|
|||||||
@@ -42,6 +42,10 @@ extern crate cretonne_codegen;
|
|||||||
extern crate cretonne_frontend;
|
extern crate cretonne_frontend;
|
||||||
extern crate wasmparser;
|
extern crate wasmparser;
|
||||||
|
|
||||||
|
extern crate failure;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate failure_derive;
|
||||||
|
|
||||||
mod code_translator;
|
mod code_translator;
|
||||||
mod environ;
|
mod environ;
|
||||||
mod func_translator;
|
mod func_translator;
|
||||||
|
|||||||
@@ -1,14 +1,12 @@
|
|||||||
//! 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 cretonne_codegen::timing;
|
use cretonne_codegen::timing;
|
||||||
use environ::ModuleEnvironment;
|
use environ::{ModuleEnvironment, WasmError, WasmResult};
|
||||||
use sections_translator::{parse_data_section, parse_elements_section, parse_export_section,
|
use sections_translator::{parse_data_section, parse_elements_section, parse_export_section,
|
||||||
parse_function_section, parse_function_signatures, parse_global_section,
|
parse_function_section, parse_function_signatures, parse_global_section,
|
||||||
parse_import_section, parse_memory_section, parse_start_section,
|
parse_import_section, parse_memory_section, parse_start_section,
|
||||||
parse_table_section, SectionParsingError};
|
parse_table_section};
|
||||||
use wasmparser::{BinaryReaderError, Parser, ParserInput, ParserState, SectionCode, WasmDecoder};
|
use wasmparser::{Parser, ParserInput, ParserState, SectionCode, WasmDecoder};
|
||||||
|
|
||||||
use std::string::String;
|
|
||||||
|
|
||||||
/// Translate a sequence of bytes forming a valid Wasm binary into a list of valid Cretonne IR
|
/// Translate a sequence of bytes forming a valid Wasm binary into a list of valid Cretonne IR
|
||||||
/// [`Function`](../codegen/ir/function/struct.Function.html).
|
/// [`Function`](../codegen/ir/function/struct.Function.html).
|
||||||
@@ -17,13 +15,13 @@ use std::string::String;
|
|||||||
pub fn translate_module<'data>(
|
pub fn translate_module<'data>(
|
||||||
data: &'data [u8],
|
data: &'data [u8],
|
||||||
environ: &mut ModuleEnvironment<'data>,
|
environ: &mut ModuleEnvironment<'data>,
|
||||||
) -> Result<(), String> {
|
) -> WasmResult<()> {
|
||||||
let _tt = timing::wasm_translate_module();
|
let _tt = timing::wasm_translate_module();
|
||||||
let mut parser = Parser::new(data);
|
let mut parser = Parser::new(data);
|
||||||
match *parser.read() {
|
match *parser.read() {
|
||||||
ParserState::BeginWasm { .. } => {}
|
ParserState::BeginWasm { .. } => {}
|
||||||
ParserState::Error(BinaryReaderError { message, offset }) => {
|
ParserState::Error(e) => {
|
||||||
return Err(format!("at offset {}: {}", offset, message));
|
return Err(WasmError::from_binary_reader_error(e));
|
||||||
}
|
}
|
||||||
ref s => panic!("modules should begin properly: {:?}", s),
|
ref s => panic!("modules should begin properly: {:?}", s),
|
||||||
}
|
}
|
||||||
@@ -31,83 +29,38 @@ pub fn translate_module<'data>(
|
|||||||
loop {
|
loop {
|
||||||
match *parser.read_with_input(next_input) {
|
match *parser.read_with_input(next_input) {
|
||||||
ParserState::BeginSection { code: SectionCode::Type, .. } => {
|
ParserState::BeginSection { code: SectionCode::Type, .. } => {
|
||||||
match parse_function_signatures(&mut parser, environ) {
|
parse_function_signatures(&mut parser, environ)?;
|
||||||
Ok(()) => (),
|
|
||||||
Err(SectionParsingError::WrongSectionContent(s)) => {
|
|
||||||
return Err(format!("wrong content in the type section: {}", s))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
next_input = ParserInput::Default;
|
next_input = ParserInput::Default;
|
||||||
}
|
}
|
||||||
ParserState::BeginSection { code: SectionCode::Import, .. } => {
|
ParserState::BeginSection { code: SectionCode::Import, .. } => {
|
||||||
match parse_import_section(&mut parser, environ) {
|
parse_import_section(&mut parser, environ)?;
|
||||||
Ok(()) => {}
|
|
||||||
Err(SectionParsingError::WrongSectionContent(s)) => {
|
|
||||||
return Err(format!("wrong content in the import section: {}", s))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
next_input = ParserInput::Default;
|
next_input = ParserInput::Default;
|
||||||
}
|
}
|
||||||
ParserState::BeginSection { code: SectionCode::Function, .. } => {
|
ParserState::BeginSection { code: SectionCode::Function, .. } => {
|
||||||
match parse_function_section(&mut parser, environ) {
|
parse_function_section(&mut parser, environ)?;
|
||||||
Ok(()) => {}
|
|
||||||
Err(SectionParsingError::WrongSectionContent(s)) => {
|
|
||||||
return Err(format!("wrong content in the function section: {}", s))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
next_input = ParserInput::Default;
|
next_input = ParserInput::Default;
|
||||||
}
|
}
|
||||||
ParserState::BeginSection { code: SectionCode::Table, .. } => {
|
ParserState::BeginSection { code: SectionCode::Table, .. } => {
|
||||||
match parse_table_section(&mut parser, environ) {
|
parse_table_section(&mut parser, environ)?;
|
||||||
Ok(()) => (),
|
|
||||||
Err(SectionParsingError::WrongSectionContent(s)) => {
|
|
||||||
return Err(format!("wrong content in the table section: {}", s))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ParserState::BeginSection { code: SectionCode::Memory, .. } => {
|
ParserState::BeginSection { code: SectionCode::Memory, .. } => {
|
||||||
match parse_memory_section(&mut parser, environ) {
|
parse_memory_section(&mut parser, environ)?;
|
||||||
Ok(()) => {}
|
|
||||||
Err(SectionParsingError::WrongSectionContent(s)) => {
|
|
||||||
return Err(format!("wrong content in the memory section: {}", s))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
next_input = ParserInput::Default;
|
next_input = ParserInput::Default;
|
||||||
}
|
}
|
||||||
ParserState::BeginSection { code: SectionCode::Global, .. } => {
|
ParserState::BeginSection { code: SectionCode::Global, .. } => {
|
||||||
match parse_global_section(&mut parser, environ) {
|
parse_global_section(&mut parser, environ)?;
|
||||||
Ok(()) => {}
|
|
||||||
Err(SectionParsingError::WrongSectionContent(s)) => {
|
|
||||||
return Err(format!("wrong content in the global section: {}", s))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
next_input = ParserInput::Default;
|
next_input = ParserInput::Default;
|
||||||
}
|
}
|
||||||
ParserState::BeginSection { code: SectionCode::Export, .. } => {
|
ParserState::BeginSection { code: SectionCode::Export, .. } => {
|
||||||
match parse_export_section(&mut parser, environ) {
|
parse_export_section(&mut parser, environ)?;
|
||||||
Ok(()) => {}
|
|
||||||
Err(SectionParsingError::WrongSectionContent(s)) => {
|
|
||||||
return Err(format!("wrong content in the export section: {}", s))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
next_input = ParserInput::Default;
|
next_input = ParserInput::Default;
|
||||||
}
|
}
|
||||||
ParserState::BeginSection { code: SectionCode::Start, .. } => {
|
ParserState::BeginSection { code: SectionCode::Start, .. } => {
|
||||||
match parse_start_section(&mut parser, environ) {
|
parse_start_section(&mut parser, environ)?;
|
||||||
Ok(()) => (),
|
|
||||||
Err(SectionParsingError::WrongSectionContent(s)) => {
|
|
||||||
return Err(format!("wrong content in the start section: {}", s))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
next_input = ParserInput::Default;
|
next_input = ParserInput::Default;
|
||||||
}
|
}
|
||||||
ParserState::BeginSection { code: SectionCode::Element, .. } => {
|
ParserState::BeginSection { code: SectionCode::Element, .. } => {
|
||||||
match parse_elements_section(&mut parser, environ) {
|
parse_elements_section(&mut parser, environ)?;
|
||||||
Ok(()) => (),
|
|
||||||
Err(SectionParsingError::WrongSectionContent(s)) => {
|
|
||||||
return Err(format!("wrong content in the element section: {}", s))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
next_input = ParserInput::Default;
|
next_input = ParserInput::Default;
|
||||||
}
|
}
|
||||||
ParserState::BeginSection { code: SectionCode::Code, .. } => {
|
ParserState::BeginSection { code: SectionCode::Code, .. } => {
|
||||||
@@ -119,18 +72,14 @@ pub fn translate_module<'data>(
|
|||||||
}
|
}
|
||||||
ParserState::EndWasm => return Ok(()),
|
ParserState::EndWasm => return Ok(()),
|
||||||
ParserState::BeginSection { code: SectionCode::Data, .. } => {
|
ParserState::BeginSection { code: SectionCode::Data, .. } => {
|
||||||
match parse_data_section(&mut parser, environ) {
|
parse_data_section(&mut parser, environ)?;
|
||||||
Ok(()) => (),
|
|
||||||
Err(SectionParsingError::WrongSectionContent(s)) => {
|
|
||||||
return Err(format!("wrong content in the data section: {}", s))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ParserState::BeginSection { code: SectionCode::Custom { .. }, .. } => {
|
ParserState::BeginSection { code: SectionCode::Custom { .. }, .. } => {
|
||||||
// Ignore unknown custom sections.
|
// Ignore unknown custom sections.
|
||||||
next_input = ParserInput::SkipSection;
|
next_input = ParserInput::SkipSection;
|
||||||
}
|
}
|
||||||
_ => return Err(String::from("wrong content in the preamble")),
|
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)),
|
||||||
|
_ => panic!("wrong content in the preamble"),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
// At this point we've entered the code section
|
// At this point we've entered the code section
|
||||||
@@ -138,25 +87,21 @@ pub fn translate_module<'data>(
|
|||||||
match *parser.read() {
|
match *parser.read() {
|
||||||
ParserState::BeginFunctionBody { .. } => {}
|
ParserState::BeginFunctionBody { .. } => {}
|
||||||
ParserState::EndSection => break,
|
ParserState::EndSection => break,
|
||||||
_ => return Err(String::from("wrong content in code section")),
|
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 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).map_err(|e| {
|
reader.read_bytes(size).map_err(|e| {
|
||||||
format!("at offset {}: {}", e.offset, e.message)
|
WasmError::from_binary_reader_error(e)
|
||||||
})?,
|
})?,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
loop {
|
loop {
|
||||||
match *parser.read() {
|
match *parser.read() {
|
||||||
ParserState::BeginSection { code: SectionCode::Data, .. } => {
|
ParserState::BeginSection { code: SectionCode::Data, .. } => {
|
||||||
match parse_data_section(&mut parser, environ) {
|
parse_data_section(&mut parser, environ)?;
|
||||||
Ok(()) => (),
|
|
||||||
Err(SectionParsingError::WrongSectionContent(s)) => {
|
|
||||||
return Err(format!("wrong content in the data section: {}", s))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ParserState::EndWasm => break,
|
ParserState::EndWasm => break,
|
||||||
_ => (),
|
_ => (),
|
||||||
|
|||||||
@@ -8,9 +8,8 @@
|
|||||||
//! is handled, according to the semantics of WebAssembly, to only specific expressions that are
|
//! is handled, according to the semantics of WebAssembly, to only specific expressions that are
|
||||||
//! interpreted on the fly.
|
//! interpreted on the fly.
|
||||||
use cretonne_codegen::ir::{self, AbiParam, Signature};
|
use cretonne_codegen::ir::{self, AbiParam, Signature};
|
||||||
use environ::ModuleEnvironment;
|
use environ::{ModuleEnvironment, WasmError, WasmResult};
|
||||||
use std::str::from_utf8;
|
use std::str::from_utf8;
|
||||||
use std::string::String;
|
|
||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
use translation_utils::{type_to_type, FunctionIndex, Global, GlobalIndex, GlobalInit, Memory,
|
use translation_utils::{type_to_type, FunctionIndex, Global, GlobalIndex, GlobalInit, Memory,
|
||||||
MemoryIndex, SignatureIndex, Table, TableElementType, TableIndex};
|
MemoryIndex, SignatureIndex, Table, TableElementType, TableIndex};
|
||||||
@@ -18,15 +17,11 @@ use wasmparser;
|
|||||||
use wasmparser::{ExternalKind, FuncType, ImportSectionEntryType, MemoryType, Operator, Parser,
|
use wasmparser::{ExternalKind, FuncType, ImportSectionEntryType, MemoryType, Operator, Parser,
|
||||||
ParserState, WasmDecoder};
|
ParserState, WasmDecoder};
|
||||||
|
|
||||||
pub enum SectionParsingError {
|
|
||||||
WrongSectionContent(String),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Reads the Type Section of the wasm module and returns the corresponding function signatures.
|
/// Reads the Type Section of the wasm module and returns the corresponding function signatures.
|
||||||
pub fn parse_function_signatures(
|
pub fn parse_function_signatures(
|
||||||
parser: &mut Parser,
|
parser: &mut Parser,
|
||||||
environ: &mut ModuleEnvironment,
|
environ: &mut ModuleEnvironment,
|
||||||
) -> Result<(), SectionParsingError> {
|
) -> WasmResult<()> {
|
||||||
loop {
|
loop {
|
||||||
match *parser.read() {
|
match *parser.read() {
|
||||||
ParserState::EndSection => break,
|
ParserState::EndSection => break,
|
||||||
@@ -50,7 +45,8 @@ pub fn parse_function_signatures(
|
|||||||
}));
|
}));
|
||||||
environ.declare_signature(&sig);
|
environ.declare_signature(&sig);
|
||||||
}
|
}
|
||||||
ref s => return Err(SectionParsingError::WrongSectionContent(format!("{:?}", s))),
|
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)),
|
||||||
|
ref s => panic!("unexpected section content: {:?}", s),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -60,7 +56,7 @@ pub fn parse_function_signatures(
|
|||||||
pub fn parse_import_section<'data>(
|
pub fn parse_import_section<'data>(
|
||||||
parser: &mut Parser<'data>,
|
parser: &mut Parser<'data>,
|
||||||
environ: &mut ModuleEnvironment<'data>,
|
environ: &mut ModuleEnvironment<'data>,
|
||||||
) -> Result<(), SectionParsingError> {
|
) -> WasmResult<()> {
|
||||||
loop {
|
loop {
|
||||||
match *parser.read() {
|
match *parser.read() {
|
||||||
ParserState::ImportSectionEntry {
|
ParserState::ImportSectionEntry {
|
||||||
@@ -110,7 +106,8 @@ pub fn parse_import_section<'data>(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
ParserState::EndSection => break,
|
ParserState::EndSection => break,
|
||||||
ref s => return Err(SectionParsingError::WrongSectionContent(format!("{:?}", s))),
|
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)),
|
||||||
|
ref s => panic!("unexpected section content: {:?}", s),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -120,14 +117,15 @@ pub fn parse_import_section<'data>(
|
|||||||
pub fn parse_function_section(
|
pub fn parse_function_section(
|
||||||
parser: &mut Parser,
|
parser: &mut Parser,
|
||||||
environ: &mut ModuleEnvironment,
|
environ: &mut ModuleEnvironment,
|
||||||
) -> Result<(), SectionParsingError> {
|
) -> WasmResult<()> {
|
||||||
loop {
|
loop {
|
||||||
match *parser.read() {
|
match *parser.read() {
|
||||||
ParserState::FunctionSectionEntry(sigindex) => {
|
ParserState::FunctionSectionEntry(sigindex) => {
|
||||||
environ.declare_func_type(sigindex as SignatureIndex);
|
environ.declare_func_type(sigindex as SignatureIndex);
|
||||||
}
|
}
|
||||||
ParserState::EndSection => break,
|
ParserState::EndSection => break,
|
||||||
ref s => return Err(SectionParsingError::WrongSectionContent(format!("{:?}", s))),
|
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)),
|
||||||
|
ref s => panic!("unexpected section content: {:?}", s),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -137,7 +135,7 @@ pub fn parse_function_section(
|
|||||||
pub fn parse_export_section<'data>(
|
pub fn parse_export_section<'data>(
|
||||||
parser: &mut Parser<'data>,
|
parser: &mut Parser<'data>,
|
||||||
environ: &mut ModuleEnvironment<'data>,
|
environ: &mut ModuleEnvironment<'data>,
|
||||||
) -> Result<(), SectionParsingError> {
|
) -> WasmResult<()> {
|
||||||
loop {
|
loop {
|
||||||
match *parser.read() {
|
match *parser.read() {
|
||||||
ParserState::ExportSectionEntry {
|
ParserState::ExportSectionEntry {
|
||||||
@@ -158,24 +156,23 @@ pub fn parse_export_section<'data>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ParserState::EndSection => break,
|
ParserState::EndSection => break,
|
||||||
ref s => return Err(SectionParsingError::WrongSectionContent(format!("{:?}", s))),
|
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)),
|
||||||
|
ref s => panic!("unexpected section content: {:?}", s),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieves the start function index from the start section
|
/// Retrieves the start function index from the start section
|
||||||
pub fn parse_start_section(
|
pub fn parse_start_section(parser: &mut Parser, environ: &mut ModuleEnvironment) -> WasmResult<()> {
|
||||||
parser: &mut Parser,
|
|
||||||
environ: &mut ModuleEnvironment,
|
|
||||||
) -> Result<(), SectionParsingError> {
|
|
||||||
loop {
|
loop {
|
||||||
match *parser.read() {
|
match *parser.read() {
|
||||||
ParserState::StartSectionEntry(index) => {
|
ParserState::StartSectionEntry(index) => {
|
||||||
environ.declare_start_func(index as FunctionIndex);
|
environ.declare_start_func(index as FunctionIndex);
|
||||||
}
|
}
|
||||||
ParserState::EndSection => break,
|
ParserState::EndSection => break,
|
||||||
ref s => return Err(SectionParsingError::WrongSectionContent(format!("{:?}", s))),
|
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)),
|
||||||
|
ref s => panic!("unexpected section content: {:?}", s),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -185,7 +182,7 @@ pub fn parse_start_section(
|
|||||||
pub fn parse_memory_section(
|
pub fn parse_memory_section(
|
||||||
parser: &mut Parser,
|
parser: &mut Parser,
|
||||||
environ: &mut ModuleEnvironment,
|
environ: &mut ModuleEnvironment,
|
||||||
) -> Result<(), SectionParsingError> {
|
) -> WasmResult<()> {
|
||||||
loop {
|
loop {
|
||||||
match *parser.read() {
|
match *parser.read() {
|
||||||
ParserState::MemorySectionEntry(ref ty) => {
|
ParserState::MemorySectionEntry(ref ty) => {
|
||||||
@@ -196,7 +193,8 @@ pub fn parse_memory_section(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
ParserState::EndSection => break,
|
ParserState::EndSection => break,
|
||||||
ref s => return Err(SectionParsingError::WrongSectionContent(format!("{:?}", s))),
|
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)),
|
||||||
|
ref s => panic!("unexpected section content: {:?}", s),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -206,16 +204,18 @@ pub fn parse_memory_section(
|
|||||||
pub fn parse_global_section(
|
pub fn parse_global_section(
|
||||||
parser: &mut Parser,
|
parser: &mut Parser,
|
||||||
environ: &mut ModuleEnvironment,
|
environ: &mut ModuleEnvironment,
|
||||||
) -> Result<(), SectionParsingError> {
|
) -> WasmResult<()> {
|
||||||
loop {
|
loop {
|
||||||
let (content_type, mutability) = match *parser.read() {
|
let (content_type, mutability) = match *parser.read() {
|
||||||
ParserState::BeginGlobalSectionEntry(ref ty) => (ty.content_type, ty.mutable),
|
ParserState::BeginGlobalSectionEntry(ref ty) => (ty.content_type, ty.mutable),
|
||||||
ParserState::EndSection => break,
|
ParserState::EndSection => break,
|
||||||
ref s => return Err(SectionParsingError::WrongSectionContent(format!("{:?}", s))),
|
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)),
|
||||||
|
ref s => panic!("unexpected section content: {:?}", s),
|
||||||
};
|
};
|
||||||
match *parser.read() {
|
match *parser.read() {
|
||||||
ParserState::BeginInitExpressionBody => (),
|
ParserState::BeginInitExpressionBody => (),
|
||||||
ref s => return Err(SectionParsingError::WrongSectionContent(format!("{:?}", s))),
|
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)),
|
||||||
|
ref s => panic!("unexpected section content: {:?}", s),
|
||||||
}
|
}
|
||||||
let initializer = match *parser.read() {
|
let initializer = match *parser.read() {
|
||||||
ParserState::InitExpressionOperator(Operator::I32Const { value }) => {
|
ParserState::InitExpressionOperator(Operator::I32Const { value }) => {
|
||||||
@@ -233,11 +233,13 @@ pub fn parse_global_section(
|
|||||||
ParserState::InitExpressionOperator(Operator::GetGlobal { global_index }) => {
|
ParserState::InitExpressionOperator(Operator::GetGlobal { global_index }) => {
|
||||||
GlobalInit::GlobalRef(global_index as GlobalIndex)
|
GlobalInit::GlobalRef(global_index as GlobalIndex)
|
||||||
}
|
}
|
||||||
ref s => return Err(SectionParsingError::WrongSectionContent(format!("{:?}", s))),
|
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)),
|
||||||
|
ref s => panic!("unexpected section content: {:?}", s),
|
||||||
};
|
};
|
||||||
match *parser.read() {
|
match *parser.read() {
|
||||||
ParserState::EndInitExpressionBody => (),
|
ParserState::EndInitExpressionBody => (),
|
||||||
ref s => return Err(SectionParsingError::WrongSectionContent(format!("{:?}", s))),
|
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)),
|
||||||
|
ref s => panic!("unexpected section content: {:?}", s),
|
||||||
}
|
}
|
||||||
let global = Global {
|
let global = Global {
|
||||||
ty: type_to_type(&content_type).unwrap(),
|
ty: type_to_type(&content_type).unwrap(),
|
||||||
@@ -247,7 +249,8 @@ pub fn parse_global_section(
|
|||||||
environ.declare_global(global);
|
environ.declare_global(global);
|
||||||
match *parser.read() {
|
match *parser.read() {
|
||||||
ParserState::EndGlobalSectionEntry => (),
|
ParserState::EndGlobalSectionEntry => (),
|
||||||
ref s => return Err(SectionParsingError::WrongSectionContent(format!("{:?}", s))),
|
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)),
|
||||||
|
ref s => panic!("unexpected section content: {:?}", s),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -256,16 +259,18 @@ pub fn parse_global_section(
|
|||||||
pub fn parse_data_section<'data>(
|
pub fn parse_data_section<'data>(
|
||||||
parser: &mut Parser<'data>,
|
parser: &mut Parser<'data>,
|
||||||
environ: &mut ModuleEnvironment<'data>,
|
environ: &mut ModuleEnvironment<'data>,
|
||||||
) -> Result<(), SectionParsingError> {
|
) -> WasmResult<()> {
|
||||||
loop {
|
loop {
|
||||||
let memory_index = match *parser.read() {
|
let memory_index = match *parser.read() {
|
||||||
ParserState::BeginDataSectionEntry(memory_index) => memory_index,
|
ParserState::BeginDataSectionEntry(memory_index) => memory_index,
|
||||||
ParserState::EndSection => break,
|
ParserState::EndSection => break,
|
||||||
ref s => return Err(SectionParsingError::WrongSectionContent(format!("{:?}", s))),
|
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)),
|
||||||
|
ref s => panic!("unexpected section content: {:?}", s),
|
||||||
};
|
};
|
||||||
match *parser.read() {
|
match *parser.read() {
|
||||||
ParserState::BeginInitExpressionBody => (),
|
ParserState::BeginInitExpressionBody => (),
|
||||||
ref s => return Err(SectionParsingError::WrongSectionContent(format!("{:?}", s))),
|
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)),
|
||||||
|
ref s => panic!("unexpected section content: {:?}", s),
|
||||||
};
|
};
|
||||||
let (base, offset) = match *parser.read() {
|
let (base, offset) = match *parser.read() {
|
||||||
ParserState::InitExpressionOperator(Operator::I32Const { value }) => {
|
ParserState::InitExpressionOperator(Operator::I32Const { value }) => {
|
||||||
@@ -278,22 +283,26 @@ pub fn parse_data_section<'data>(
|
|||||||
_ => panic!("should not happen"),
|
_ => panic!("should not happen"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ref s => return Err(SectionParsingError::WrongSectionContent(format!("{:?}", s))),
|
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)),
|
||||||
|
ref s => panic!("unexpected section content: {:?}", s),
|
||||||
};
|
};
|
||||||
match *parser.read() {
|
match *parser.read() {
|
||||||
ParserState::EndInitExpressionBody => (),
|
ParserState::EndInitExpressionBody => (),
|
||||||
ref s => return Err(SectionParsingError::WrongSectionContent(format!("{:?}", s))),
|
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)),
|
||||||
|
ref s => panic!("unexpected section content: {:?}", s),
|
||||||
};
|
};
|
||||||
match *parser.read() {
|
match *parser.read() {
|
||||||
ParserState::BeginDataSectionEntryBody(_) => (),
|
ParserState::BeginDataSectionEntryBody(_) => (),
|
||||||
ref s => return Err(SectionParsingError::WrongSectionContent(format!("{:?}", s))),
|
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)),
|
||||||
|
ref s => panic!("unexpected section content: {:?}", s),
|
||||||
};
|
};
|
||||||
let mut running_offset = offset;
|
let mut running_offset = offset;
|
||||||
loop {
|
loop {
|
||||||
let data = match *parser.read() {
|
let data = match *parser.read() {
|
||||||
ParserState::DataSectionEntryBodyChunk(data) => data,
|
ParserState::DataSectionEntryBodyChunk(data) => data,
|
||||||
ParserState::EndDataSectionEntryBody => break,
|
ParserState::EndDataSectionEntryBody => break,
|
||||||
ref s => return Err(SectionParsingError::WrongSectionContent(format!("{:?}", s))),
|
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)),
|
||||||
|
ref s => panic!("unexpected section content: {:?}", s),
|
||||||
};
|
};
|
||||||
environ.declare_data_initialization(
|
environ.declare_data_initialization(
|
||||||
memory_index as MemoryIndex,
|
memory_index as MemoryIndex,
|
||||||
@@ -305,17 +314,15 @@ pub fn parse_data_section<'data>(
|
|||||||
}
|
}
|
||||||
match *parser.read() {
|
match *parser.read() {
|
||||||
ParserState::EndDataSectionEntry => (),
|
ParserState::EndDataSectionEntry => (),
|
||||||
ref s => return Err(SectionParsingError::WrongSectionContent(format!("{:?}", s))),
|
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)),
|
||||||
|
ref s => panic!("unexpected section content: {:?}", s),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieves the tables from the table section
|
/// Retrieves the tables from the table section
|
||||||
pub fn parse_table_section(
|
pub fn parse_table_section(parser: &mut Parser, environ: &mut ModuleEnvironment) -> WasmResult<()> {
|
||||||
parser: &mut Parser,
|
|
||||||
environ: &mut ModuleEnvironment,
|
|
||||||
) -> Result<(), SectionParsingError> {
|
|
||||||
loop {
|
loop {
|
||||||
match *parser.read() {
|
match *parser.read() {
|
||||||
ParserState::TableSectionEntry(ref table) => {
|
ParserState::TableSectionEntry(ref table) => {
|
||||||
@@ -329,7 +336,8 @@ pub fn parse_table_section(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
ParserState::EndSection => break,
|
ParserState::EndSection => break,
|
||||||
ref s => return Err(SectionParsingError::WrongSectionContent(format!("{:?}", s))),
|
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)),
|
||||||
|
ref s => panic!("unexpected section content: {:?}", s),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -339,16 +347,18 @@ pub fn parse_table_section(
|
|||||||
pub fn parse_elements_section(
|
pub fn parse_elements_section(
|
||||||
parser: &mut Parser,
|
parser: &mut Parser,
|
||||||
environ: &mut ModuleEnvironment,
|
environ: &mut ModuleEnvironment,
|
||||||
) -> Result<(), SectionParsingError> {
|
) -> WasmResult<()> {
|
||||||
loop {
|
loop {
|
||||||
let table_index = match *parser.read() {
|
let table_index = match *parser.read() {
|
||||||
ParserState::BeginElementSectionEntry(table_index) => table_index as TableIndex,
|
ParserState::BeginElementSectionEntry(table_index) => table_index as TableIndex,
|
||||||
ParserState::EndSection => break,
|
ParserState::EndSection => break,
|
||||||
ref s => return Err(SectionParsingError::WrongSectionContent(format!("{:?}", s))),
|
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)),
|
||||||
|
ref s => panic!("unexpected section content: {:?}", s),
|
||||||
};
|
};
|
||||||
match *parser.read() {
|
match *parser.read() {
|
||||||
ParserState::BeginInitExpressionBody => (),
|
ParserState::BeginInitExpressionBody => (),
|
||||||
ref s => return Err(SectionParsingError::WrongSectionContent(format!("{:?}", s))),
|
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)),
|
||||||
|
ref s => panic!("unexpected section content: {:?}", s),
|
||||||
};
|
};
|
||||||
let (base, offset) = match *parser.read() {
|
let (base, offset) = match *parser.read() {
|
||||||
ParserState::InitExpressionOperator(Operator::I32Const { value }) => {
|
ParserState::InitExpressionOperator(Operator::I32Const { value }) => {
|
||||||
@@ -361,11 +371,13 @@ pub fn parse_elements_section(
|
|||||||
_ => panic!("should not happen"),
|
_ => panic!("should not happen"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ref s => return Err(SectionParsingError::WrongSectionContent(format!("{:?}", s))),
|
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)),
|
||||||
|
ref s => panic!("unexpected section content: {:?}", s),
|
||||||
};
|
};
|
||||||
match *parser.read() {
|
match *parser.read() {
|
||||||
ParserState::EndInitExpressionBody => (),
|
ParserState::EndInitExpressionBody => (),
|
||||||
ref s => return Err(SectionParsingError::WrongSectionContent(format!("{:?}", s))),
|
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)),
|
||||||
|
ref s => panic!("unexpected section content: {:?}", s),
|
||||||
};
|
};
|
||||||
match *parser.read() {
|
match *parser.read() {
|
||||||
ParserState::ElementSectionEntryBody(ref elements) => {
|
ParserState::ElementSectionEntryBody(ref elements) => {
|
||||||
@@ -373,11 +385,13 @@ pub fn parse_elements_section(
|
|||||||
elements.iter().map(|&x| x as FunctionIndex).collect();
|
elements.iter().map(|&x| x as FunctionIndex).collect();
|
||||||
environ.declare_table_elements(table_index, base, offset, elems)
|
environ.declare_table_elements(table_index, base, offset, elems)
|
||||||
}
|
}
|
||||||
ref s => return Err(SectionParsingError::WrongSectionContent(format!("{:?}", s))),
|
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)),
|
||||||
|
ref s => panic!("unexpected section content: {:?}", s),
|
||||||
};
|
};
|
||||||
match *parser.read() {
|
match *parser.read() {
|
||||||
ParserState::EndElementSectionEntry => (),
|
ParserState::EndElementSectionEntry => (),
|
||||||
ref s => return Err(SectionParsingError::WrongSectionContent(format!("{:?}", s))),
|
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)),
|
||||||
|
ref s => panic!("unexpected section content: {:?}", s),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
Reference in New Issue
Block a user