WIP
This commit is contained in:
parent
4b7c3c0c94
commit
48e4704b5f
|
@ -7,6 +7,8 @@ pub const DEFAULT_MEMORY_INDEX: u32 = 0;
|
||||||
/// Index of default table.
|
/// Index of default table.
|
||||||
pub const DEFAULT_TABLE_INDEX: u32 = 0;
|
pub const DEFAULT_TABLE_INDEX: u32 = 0;
|
||||||
|
|
||||||
|
// TODO: Move BlockFrame under validation.
|
||||||
|
|
||||||
/// Control stack frame.
|
/// Control stack frame.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct BlockFrame {
|
pub struct BlockFrame {
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
use std::rc::{Rc, Weak};
|
use std::rc::{Rc, Weak};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::collections::HashMap;
|
use parity_wasm::elements::Local;
|
||||||
use parity_wasm::elements::{Local, Instructions};
|
|
||||||
use {Trap, TrapKind, Signature};
|
use {Trap, TrapKind, Signature};
|
||||||
use host::Externals;
|
use host::Externals;
|
||||||
use runner::{check_function_args, Interpreter};
|
use runner::{check_function_args, Interpreter};
|
||||||
use value::RuntimeValue;
|
use value::RuntimeValue;
|
||||||
use module::ModuleInstance;
|
use module::ModuleInstance;
|
||||||
|
use isa;
|
||||||
|
|
||||||
/// Reference to a function (See [`FuncInstance`] for details).
|
/// Reference to a function (See [`FuncInstance`] for details).
|
||||||
///
|
///
|
||||||
|
@ -158,6 +158,5 @@ impl FuncInstance {
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct FuncBody {
|
pub struct FuncBody {
|
||||||
pub locals: Vec<Local>,
|
pub locals: Vec<Local>,
|
||||||
pub instructions: Instructions,
|
pub code: isa::Instructions,
|
||||||
pub labels: HashMap<usize, usize>,
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,241 +0,0 @@
|
||||||
/// Enumeration of instruction set used by wasmi.
|
|
||||||
///
|
|
||||||
/// The instruction set is mostly derived from Wasm. However,
|
|
||||||
/// there is a substantial difference.
|
|
||||||
///
|
|
||||||
/// # Structured Stack Machine vs Traditional One
|
|
||||||
///
|
|
||||||
/// Wasm is a structured stack machine. Wasm encodes control flow in structures
|
|
||||||
/// similar to that commonly found in a programming languages
|
|
||||||
/// such as if, while. That contrasts to a traditional stack machine which
|
|
||||||
/// encodes all control flow with goto-like instructions.
|
|
||||||
///
|
|
||||||
/// Structured stack machine code aligns well with goals of Wasm,
|
|
||||||
/// namely providing fast validation of Wasm code and compilation to native code.
|
|
||||||
///
|
|
||||||
/// Unfortunately, the downside of structured stack machine code is
|
|
||||||
/// that it is less convenient to interpret. For example, let's look at
|
|
||||||
/// the following example in hypothetical structured stack machine:
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// loop
|
|
||||||
/// ...
|
|
||||||
/// if_true_jump_to_end
|
|
||||||
/// ...
|
|
||||||
/// end
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// To execute `if_true_jump_to_end` , the interpreter needs to skip all instructions
|
|
||||||
/// until it reaches the *matching* `end`. That's quite inefficient compared
|
|
||||||
/// to a plain goto to the specific position.
|
|
||||||
///
|
|
||||||
/// # Differences from Wasm
|
|
||||||
///
|
|
||||||
/// - There is no `nop` instruction.
|
|
||||||
/// - All control flow strucutres are flattened to plain gotos.
|
|
||||||
/// - Implicit returns via reaching function scope `End` are replaced with an explicit `return` instruction.
|
|
||||||
/// - Locals live on the value stack now.
|
|
||||||
enum Instruction {
|
|
||||||
/// Keep the specified amount of operands and then
|
|
||||||
/// drop the rest.
|
|
||||||
DropKeep {
|
|
||||||
drop: u32,
|
|
||||||
keep: u32,
|
|
||||||
},
|
|
||||||
|
|
||||||
/// Push a local variable or an argument from the specified depth.
|
|
||||||
GetLocal {
|
|
||||||
depth: u32
|
|
||||||
},
|
|
||||||
|
|
||||||
/// Pop a value and put it in at the specified depth.
|
|
||||||
SetLocal {
|
|
||||||
depth: u32
|
|
||||||
},
|
|
||||||
|
|
||||||
/// Copy a value to the specified depth.
|
|
||||||
TeeLocal(u32),
|
|
||||||
|
|
||||||
/// Similar to the Wasm ones, but instead of a label depth
|
|
||||||
/// they specify direct PC.
|
|
||||||
Br(u32),
|
|
||||||
BrIf(u32),
|
|
||||||
BrTable(Box<[u32]>, u32),
|
|
||||||
|
|
||||||
Unreachable,
|
|
||||||
Return,
|
|
||||||
|
|
||||||
Call(u32),
|
|
||||||
CallIndirect(u32, u8),
|
|
||||||
|
|
||||||
Drop,
|
|
||||||
Select,
|
|
||||||
|
|
||||||
GetGlobal(u32),
|
|
||||||
SetGlobal(u32),
|
|
||||||
|
|
||||||
// All store/load instructions operate with 'memory immediates'
|
|
||||||
// which represented here as (flag, offset) tuple
|
|
||||||
I32Load(u32, u32),
|
|
||||||
I64Load(u32, u32),
|
|
||||||
F32Load(u32, u32),
|
|
||||||
F64Load(u32, u32),
|
|
||||||
I32Load8S(u32, u32),
|
|
||||||
I32Load8U(u32, u32),
|
|
||||||
I32Load16S(u32, u32),
|
|
||||||
I32Load16U(u32, u32),
|
|
||||||
I64Load8S(u32, u32),
|
|
||||||
I64Load8U(u32, u32),
|
|
||||||
I64Load16S(u32, u32),
|
|
||||||
I64Load16U(u32, u32),
|
|
||||||
I64Load32S(u32, u32),
|
|
||||||
I64Load32U(u32, u32),
|
|
||||||
I32Store(u32, u32),
|
|
||||||
I64Store(u32, u32),
|
|
||||||
F32Store(u32, u32),
|
|
||||||
F64Store(u32, u32),
|
|
||||||
I32Store8(u32, u32),
|
|
||||||
I32Store16(u32, u32),
|
|
||||||
I64Store8(u32, u32),
|
|
||||||
I64Store16(u32, u32),
|
|
||||||
I64Store32(u32, u32),
|
|
||||||
|
|
||||||
CurrentMemory(u8),
|
|
||||||
GrowMemory(u8),
|
|
||||||
|
|
||||||
I32Const(i32),
|
|
||||||
I64Const(i64),
|
|
||||||
F32Const(u32),
|
|
||||||
F64Const(u64),
|
|
||||||
|
|
||||||
I32Eqz,
|
|
||||||
I32Eq,
|
|
||||||
I32Ne,
|
|
||||||
I32LtS,
|
|
||||||
I32LtU,
|
|
||||||
I32GtS,
|
|
||||||
I32GtU,
|
|
||||||
I32LeS,
|
|
||||||
I32LeU,
|
|
||||||
I32GeS,
|
|
||||||
I32GeU,
|
|
||||||
|
|
||||||
I64Eqz,
|
|
||||||
I64Eq,
|
|
||||||
I64Ne,
|
|
||||||
I64LtS,
|
|
||||||
I64LtU,
|
|
||||||
I64GtS,
|
|
||||||
I64GtU,
|
|
||||||
I64LeS,
|
|
||||||
I64LeU,
|
|
||||||
I64GeS,
|
|
||||||
I64GeU,
|
|
||||||
|
|
||||||
F32Eq,
|
|
||||||
F32Ne,
|
|
||||||
F32Lt,
|
|
||||||
F32Gt,
|
|
||||||
F32Le,
|
|
||||||
F32Ge,
|
|
||||||
|
|
||||||
F64Eq,
|
|
||||||
F64Ne,
|
|
||||||
F64Lt,
|
|
||||||
F64Gt,
|
|
||||||
F64Le,
|
|
||||||
F64Ge,
|
|
||||||
|
|
||||||
I32Clz,
|
|
||||||
I32Ctz,
|
|
||||||
I32Popcnt,
|
|
||||||
I32Add,
|
|
||||||
I32Sub,
|
|
||||||
I32Mul,
|
|
||||||
I32DivS,
|
|
||||||
I32DivU,
|
|
||||||
I32RemS,
|
|
||||||
I32RemU,
|
|
||||||
I32And,
|
|
||||||
I32Or,
|
|
||||||
I32Xor,
|
|
||||||
I32Shl,
|
|
||||||
I32ShrS,
|
|
||||||
I32ShrU,
|
|
||||||
I32Rotl,
|
|
||||||
I32Rotr,
|
|
||||||
|
|
||||||
I64Clz,
|
|
||||||
I64Ctz,
|
|
||||||
I64Popcnt,
|
|
||||||
I64Add,
|
|
||||||
I64Sub,
|
|
||||||
I64Mul,
|
|
||||||
I64DivS,
|
|
||||||
I64DivU,
|
|
||||||
I64RemS,
|
|
||||||
I64RemU,
|
|
||||||
I64And,
|
|
||||||
I64Or,
|
|
||||||
I64Xor,
|
|
||||||
I64Shl,
|
|
||||||
I64ShrS,
|
|
||||||
I64ShrU,
|
|
||||||
I64Rotl,
|
|
||||||
I64Rotr,
|
|
||||||
F32Abs,
|
|
||||||
F32Neg,
|
|
||||||
F32Ceil,
|
|
||||||
F32Floor,
|
|
||||||
F32Trunc,
|
|
||||||
F32Nearest,
|
|
||||||
F32Sqrt,
|
|
||||||
F32Add,
|
|
||||||
F32Sub,
|
|
||||||
F32Mul,
|
|
||||||
F32Div,
|
|
||||||
F32Min,
|
|
||||||
F32Max,
|
|
||||||
F32Copysign,
|
|
||||||
F64Abs,
|
|
||||||
F64Neg,
|
|
||||||
F64Ceil,
|
|
||||||
F64Floor,
|
|
||||||
F64Trunc,
|
|
||||||
F64Nearest,
|
|
||||||
F64Sqrt,
|
|
||||||
F64Add,
|
|
||||||
F64Sub,
|
|
||||||
F64Mul,
|
|
||||||
F64Div,
|
|
||||||
F64Min,
|
|
||||||
F64Max,
|
|
||||||
F64Copysign,
|
|
||||||
|
|
||||||
I32WrapI64,
|
|
||||||
I32TruncSF32,
|
|
||||||
I32TruncUF32,
|
|
||||||
I32TruncSF64,
|
|
||||||
I32TruncUF64,
|
|
||||||
I64ExtendSI32,
|
|
||||||
I64ExtendUI32,
|
|
||||||
I64TruncSF32,
|
|
||||||
I64TruncUF32,
|
|
||||||
I64TruncSF64,
|
|
||||||
I64TruncUF64,
|
|
||||||
F32ConvertSI32,
|
|
||||||
F32ConvertUI32,
|
|
||||||
F32ConvertSI64,
|
|
||||||
F32ConvertUI64,
|
|
||||||
F32DemoteF64,
|
|
||||||
F64ConvertSI32,
|
|
||||||
F64ConvertUI32,
|
|
||||||
F64ConvertSI64,
|
|
||||||
F64ConvertUI64,
|
|
||||||
F64PromoteF32,
|
|
||||||
|
|
||||||
I32ReinterpretF32,
|
|
||||||
I64ReinterpretF64,
|
|
||||||
F32ReinterpretI32,
|
|
||||||
F64ReinterpretI64,
|
|
||||||
}
|
|
|
@ -0,0 +1,256 @@
|
||||||
|
//! An instruction set used by wasmi.
|
||||||
|
//!
|
||||||
|
//! The instruction set is mostly derived from Wasm. However,
|
||||||
|
//! there is a substantial difference.
|
||||||
|
//!
|
||||||
|
//! # Structured Stack Machine vs Traditional One
|
||||||
|
//!
|
||||||
|
//! Wasm is a structured stack machine. Wasm encodes control flow in structures
|
||||||
|
//! similar to that commonly found in a programming languages
|
||||||
|
//! such as if, while. That contrasts to a traditional stack machine which
|
||||||
|
//! encodes all control flow with goto-like instructions.
|
||||||
|
//!
|
||||||
|
//! Structured stack machine code aligns well with goals of Wasm,
|
||||||
|
//! namely providing fast validation of Wasm code and compilation to native code.
|
||||||
|
//!
|
||||||
|
//! Unfortunately, the downside of structured stack machine code is
|
||||||
|
//! that it is less convenient to interpret. For example, let's look at
|
||||||
|
//! the following example in hypothetical structured stack machine:
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//! loop
|
||||||
|
//! ...
|
||||||
|
//! if_true_jump_to_end
|
||||||
|
//! ...
|
||||||
|
//! end
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! To execute `if_true_jump_to_end` , the interpreter needs to skip all instructions
|
||||||
|
//! until it reaches the *matching* `end`. That's quite inefficient compared
|
||||||
|
//! to a plain goto to the specific position.
|
||||||
|
//!
|
||||||
|
//! # Differences from Wasm
|
||||||
|
//!
|
||||||
|
//! - There is no `nop` instruction.
|
||||||
|
//! - All control flow strucutres are flattened to plain gotos.
|
||||||
|
//! - Implicit returns via reaching function scope `End` are replaced with an explicit `return` instruction.
|
||||||
|
//! - Locals live on the value stack now.
|
||||||
|
//! - Load/store instructions doesn't take `align` parameter.
|
||||||
|
//! - *.const store value in straight encoding.
|
||||||
|
//! - Reserved immediates are ignored for `call_indirect`, `current_memory`, `grow_memory`.
|
||||||
|
//!
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Target {
|
||||||
|
pub dst_pc: u32,
|
||||||
|
pub drop: u32,
|
||||||
|
pub keep: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused)] // TODO: Remove
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum Instruction {
|
||||||
|
/// Push a local variable or an argument from the specified depth.
|
||||||
|
GetLocal {
|
||||||
|
depth: u32
|
||||||
|
},
|
||||||
|
|
||||||
|
/// Pop a value and put it in at the specified depth.
|
||||||
|
SetLocal {
|
||||||
|
depth: u32
|
||||||
|
},
|
||||||
|
|
||||||
|
/// Copy a value to the specified depth.
|
||||||
|
TeeLocal { depth: u32 },
|
||||||
|
|
||||||
|
/// Similar to the Wasm ones, but instead of a label depth
|
||||||
|
/// they specify direct PC.
|
||||||
|
Br(Target),
|
||||||
|
BrIfEqz(Target),
|
||||||
|
BrIfNez(Target),
|
||||||
|
|
||||||
|
/// Last one is the default.
|
||||||
|
///
|
||||||
|
/// Can be less than zero.
|
||||||
|
BrTable(Box<[Target]>),
|
||||||
|
|
||||||
|
Unreachable,
|
||||||
|
Return,
|
||||||
|
|
||||||
|
Call(u32),
|
||||||
|
CallIndirect(u32),
|
||||||
|
|
||||||
|
Drop,
|
||||||
|
Select,
|
||||||
|
|
||||||
|
GetGlobal(u32),
|
||||||
|
SetGlobal(u32),
|
||||||
|
|
||||||
|
I32Load(u32),
|
||||||
|
I64Load(u32),
|
||||||
|
F32Load(u32),
|
||||||
|
F64Load(u32),
|
||||||
|
I32Load8S(u32),
|
||||||
|
I32Load8U(u32),
|
||||||
|
I32Load16S(u32),
|
||||||
|
I32Load16U(u32),
|
||||||
|
I64Load8S(u32),
|
||||||
|
I64Load8U(u32),
|
||||||
|
I64Load16S(u32),
|
||||||
|
I64Load16U(u32),
|
||||||
|
I64Load32S(u32),
|
||||||
|
I64Load32U(u32),
|
||||||
|
I32Store(u32),
|
||||||
|
I64Store(u32),
|
||||||
|
F32Store(u32),
|
||||||
|
F64Store(u32),
|
||||||
|
I32Store8(u32),
|
||||||
|
I32Store16(u32),
|
||||||
|
I64Store8(u32),
|
||||||
|
I64Store16(u32),
|
||||||
|
I64Store32(u32),
|
||||||
|
|
||||||
|
CurrentMemory,
|
||||||
|
GrowMemory,
|
||||||
|
|
||||||
|
I32Const(i32),
|
||||||
|
I64Const(i64),
|
||||||
|
F32Const(u32),
|
||||||
|
F64Const(u64),
|
||||||
|
|
||||||
|
I32Eqz,
|
||||||
|
I32Eq,
|
||||||
|
I32Ne,
|
||||||
|
I32LtS,
|
||||||
|
I32LtU,
|
||||||
|
I32GtS,
|
||||||
|
I32GtU,
|
||||||
|
I32LeS,
|
||||||
|
I32LeU,
|
||||||
|
I32GeS,
|
||||||
|
I32GeU,
|
||||||
|
|
||||||
|
I64Eqz,
|
||||||
|
I64Eq,
|
||||||
|
I64Ne,
|
||||||
|
I64LtS,
|
||||||
|
I64LtU,
|
||||||
|
I64GtS,
|
||||||
|
I64GtU,
|
||||||
|
I64LeS,
|
||||||
|
I64LeU,
|
||||||
|
I64GeS,
|
||||||
|
I64GeU,
|
||||||
|
|
||||||
|
F32Eq,
|
||||||
|
F32Ne,
|
||||||
|
F32Lt,
|
||||||
|
F32Gt,
|
||||||
|
F32Le,
|
||||||
|
F32Ge,
|
||||||
|
|
||||||
|
F64Eq,
|
||||||
|
F64Ne,
|
||||||
|
F64Lt,
|
||||||
|
F64Gt,
|
||||||
|
F64Le,
|
||||||
|
F64Ge,
|
||||||
|
|
||||||
|
I32Clz,
|
||||||
|
I32Ctz,
|
||||||
|
I32Popcnt,
|
||||||
|
I32Add,
|
||||||
|
I32Sub,
|
||||||
|
I32Mul,
|
||||||
|
I32DivS,
|
||||||
|
I32DivU,
|
||||||
|
I32RemS,
|
||||||
|
I32RemU,
|
||||||
|
I32And,
|
||||||
|
I32Or,
|
||||||
|
I32Xor,
|
||||||
|
I32Shl,
|
||||||
|
I32ShrS,
|
||||||
|
I32ShrU,
|
||||||
|
I32Rotl,
|
||||||
|
I32Rotr,
|
||||||
|
|
||||||
|
I64Clz,
|
||||||
|
I64Ctz,
|
||||||
|
I64Popcnt,
|
||||||
|
I64Add,
|
||||||
|
I64Sub,
|
||||||
|
I64Mul,
|
||||||
|
I64DivS,
|
||||||
|
I64DivU,
|
||||||
|
I64RemS,
|
||||||
|
I64RemU,
|
||||||
|
I64And,
|
||||||
|
I64Or,
|
||||||
|
I64Xor,
|
||||||
|
I64Shl,
|
||||||
|
I64ShrS,
|
||||||
|
I64ShrU,
|
||||||
|
I64Rotl,
|
||||||
|
I64Rotr,
|
||||||
|
F32Abs,
|
||||||
|
F32Neg,
|
||||||
|
F32Ceil,
|
||||||
|
F32Floor,
|
||||||
|
F32Trunc,
|
||||||
|
F32Nearest,
|
||||||
|
F32Sqrt,
|
||||||
|
F32Add,
|
||||||
|
F32Sub,
|
||||||
|
F32Mul,
|
||||||
|
F32Div,
|
||||||
|
F32Min,
|
||||||
|
F32Max,
|
||||||
|
F32Copysign,
|
||||||
|
F64Abs,
|
||||||
|
F64Neg,
|
||||||
|
F64Ceil,
|
||||||
|
F64Floor,
|
||||||
|
F64Trunc,
|
||||||
|
F64Nearest,
|
||||||
|
F64Sqrt,
|
||||||
|
F64Add,
|
||||||
|
F64Sub,
|
||||||
|
F64Mul,
|
||||||
|
F64Div,
|
||||||
|
F64Min,
|
||||||
|
F64Max,
|
||||||
|
F64Copysign,
|
||||||
|
|
||||||
|
I32WrapI64,
|
||||||
|
I32TruncSF32,
|
||||||
|
I32TruncUF32,
|
||||||
|
I32TruncSF64,
|
||||||
|
I32TruncUF64,
|
||||||
|
I64ExtendSI32,
|
||||||
|
I64ExtendUI32,
|
||||||
|
I64TruncSF32,
|
||||||
|
I64TruncUF32,
|
||||||
|
I64TruncSF64,
|
||||||
|
I64TruncUF64,
|
||||||
|
F32ConvertSI32,
|
||||||
|
F32ConvertUI32,
|
||||||
|
F32ConvertSI64,
|
||||||
|
F32ConvertUI64,
|
||||||
|
F32DemoteF64,
|
||||||
|
F64ConvertSI32,
|
||||||
|
F64ConvertUI32,
|
||||||
|
F64ConvertSI64,
|
||||||
|
F64ConvertUI64,
|
||||||
|
F64PromoteF32,
|
||||||
|
|
||||||
|
I32ReinterpretF32,
|
||||||
|
I64ReinterpretF64,
|
||||||
|
F32ReinterpretI32,
|
||||||
|
F64ReinterpretI64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Instructions {
|
||||||
|
pub code: Vec<Instruction>,
|
||||||
|
}
|
12
src/lib.rs
12
src/lib.rs
|
@ -356,7 +356,7 @@ mod imports;
|
||||||
mod global;
|
mod global;
|
||||||
mod func;
|
mod func;
|
||||||
mod types;
|
mod types;
|
||||||
mod instructions;
|
mod isa;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
@ -379,7 +379,7 @@ pub mod memory_units {
|
||||||
|
|
||||||
/// Deserialized module prepared for instantiation.
|
/// Deserialized module prepared for instantiation.
|
||||||
pub struct Module {
|
pub struct Module {
|
||||||
labels: HashMap<usize, HashMap<usize, usize>>,
|
code_map: Vec<isa::Instructions>,
|
||||||
module: parity_wasm::elements::Module,
|
module: parity_wasm::elements::Module,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -419,12 +419,12 @@ impl Module {
|
||||||
pub fn from_parity_wasm_module(module: parity_wasm::elements::Module) -> Result<Module, Error> {
|
pub fn from_parity_wasm_module(module: parity_wasm::elements::Module) -> Result<Module, Error> {
|
||||||
use validation::{validate_module, ValidatedModule};
|
use validation::{validate_module, ValidatedModule};
|
||||||
let ValidatedModule {
|
let ValidatedModule {
|
||||||
labels,
|
code_map,
|
||||||
module,
|
module,
|
||||||
} = validate_module(module)?;
|
} = validate_module(module)?;
|
||||||
|
|
||||||
Ok(Module {
|
Ok(Module {
|
||||||
labels,
|
code_map,
|
||||||
module,
|
module,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -525,7 +525,7 @@ impl Module {
|
||||||
&self.module
|
&self.module
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn labels(&self) -> &HashMap<usize, HashMap<usize, usize>> {
|
pub(crate) fn code(&self) -> &Vec<isa::Instructions> {
|
||||||
&self.labels
|
&self.code_map
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ use std::rc::Rc;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use parity_wasm::elements::{External, InitExpr, Internal, Instruction, ResizableLimits, Type};
|
use parity_wasm::elements::{External, InitExpr, Internal, Opcode, ResizableLimits, Type};
|
||||||
use {Module, Error, Signature, MemoryInstance, RuntimeValue, TableInstance};
|
use {Module, Error, Signature, MemoryInstance, RuntimeValue, TableInstance};
|
||||||
use imports::ImportResolver;
|
use imports::ImportResolver;
|
||||||
use global::{GlobalInstance, GlobalRef};
|
use global::{GlobalInstance, GlobalRef};
|
||||||
|
@ -291,7 +291,7 @@ impl ModuleInstance {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let labels = loaded_module.labels();
|
let code = loaded_module.code();
|
||||||
{
|
{
|
||||||
let funcs = module.function_section().map(|fs| fs.entries()).unwrap_or(
|
let funcs = module.function_section().map(|fs| fs.entries()).unwrap_or(
|
||||||
&[],
|
&[],
|
||||||
|
@ -308,13 +308,12 @@ impl ModuleInstance {
|
||||||
let signature = instance.signature_by_index(ty.type_ref()).expect(
|
let signature = instance.signature_by_index(ty.type_ref()).expect(
|
||||||
"Due to validation type should exists",
|
"Due to validation type should exists",
|
||||||
);
|
);
|
||||||
let labels = labels.get(&index).expect(
|
let code = code.get(index).expect(
|
||||||
"At func validation time labels are collected; Collected labels are added by index; qed",
|
"At func validation time labels are collected; Collected labels are added by index; qed",
|
||||||
).clone();
|
).clone();
|
||||||
let func_body = FuncBody {
|
let func_body = FuncBody {
|
||||||
locals: body.locals().to_vec(),
|
locals: body.locals().to_vec(),
|
||||||
instructions: body.code().clone(),
|
code: code,
|
||||||
labels: labels,
|
|
||||||
};
|
};
|
||||||
let func_instance =
|
let func_instance =
|
||||||
FuncInstance::alloc_internal(Rc::downgrade(&instance.0), signature, func_body);
|
FuncInstance::alloc_internal(Rc::downgrade(&instance.0), signature, func_body);
|
||||||
|
@ -709,11 +708,11 @@ fn eval_init_expr(init_expr: &InitExpr, module: &ModuleInstance) -> RuntimeValue
|
||||||
"Due to validation `code`.len() should be 2"
|
"Due to validation `code`.len() should be 2"
|
||||||
);
|
);
|
||||||
match code[0] {
|
match code[0] {
|
||||||
Instruction::I32Const(v) => v.into(),
|
Opcode::I32Const(v) => v.into(),
|
||||||
Instruction::I64Const(v) => v.into(),
|
Opcode::I64Const(v) => v.into(),
|
||||||
Instruction::F32Const(v) => RuntimeValue::decode_f32(v),
|
Opcode::F32Const(v) => RuntimeValue::decode_f32(v),
|
||||||
Instruction::F64Const(v) => RuntimeValue::decode_f64(v),
|
Opcode::F64Const(v) => RuntimeValue::decode_f64(v),
|
||||||
Instruction::GetGlobal(idx) => {
|
Opcode::GetGlobal(idx) => {
|
||||||
let global = module.global_by_index(idx).expect(
|
let global = module.global_by_index(idx).expect(
|
||||||
"Due to validation global should exists in module",
|
"Due to validation global should exists in module",
|
||||||
);
|
);
|
||||||
|
|
360
src/runner.rs
360
src/runner.rs
|
@ -4,7 +4,7 @@ use std::{u32, usize};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::iter::repeat;
|
use std::iter::repeat;
|
||||||
use std::collections::{HashMap, VecDeque};
|
use std::collections::{HashMap, VecDeque};
|
||||||
use parity_wasm::elements::{Instruction, BlockType, Local};
|
use parity_wasm::elements::{Opcode, BlockType, Local};
|
||||||
use {Error, Trap, TrapKind, Signature};
|
use {Error, Trap, TrapKind, Signature};
|
||||||
use module::ModuleRef;
|
use module::ModuleRef;
|
||||||
use func::{FuncRef, FuncInstance, FuncInstanceInternal};
|
use func::{FuncRef, FuncInstance, FuncInstanceInternal};
|
||||||
|
@ -84,10 +84,10 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
if !function_context.is_initialized() {
|
if !function_context.is_initialized() {
|
||||||
let return_type = function_context.return_type;
|
let return_type = function_context.return_type;
|
||||||
function_context.initialize(&function_body.locals);
|
function_context.initialize(&function_body.locals);
|
||||||
function_context.push_frame(&function_body.labels, BlockFrameType::Function, return_type).map_err(Trap::new)?;
|
function_context.push_frame(BlockFrameType::Function, return_type).map_err(Trap::new)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let function_return = self.do_run_function(&mut function_context, function_body.instructions.elements(), &function_body.labels).map_err(Trap::new)?;
|
let function_return = self.do_run_function(&mut function_context, function_body.opcodes.elements(), &function_body.labels).map_err(Trap::new)?;
|
||||||
|
|
||||||
match function_return {
|
match function_return {
|
||||||
RunResult::Return(return_value) => {
|
RunResult::Return(return_value) => {
|
||||||
|
@ -127,7 +127,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_run_function(&mut self, function_context: &mut FunctionContext, function_body: &[Instruction], function_labels: &HashMap<usize, usize>) -> Result<RunResult, TrapKind> {
|
fn do_run_function(&mut self, function_context: &mut FunctionContext, function_body: &[Opcode]) -> Result<RunResult, TrapKind> {
|
||||||
loop {
|
loop {
|
||||||
let instruction = &function_body[function_context.position];
|
let instruction = &function_body[function_context.position];
|
||||||
|
|
||||||
|
@ -169,197 +169,197 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_instruction(&mut self, context: &mut FunctionContext, labels: &HashMap<usize, usize>, instruction: &Instruction) -> Result<InstructionOutcome, TrapKind> {
|
fn run_instruction(&mut self, context: &mut FunctionContext, labels: &HashMap<usize, usize>, opcode: &Opcode) -> Result<InstructionOutcome, TrapKind> {
|
||||||
match instruction {
|
match opcode {
|
||||||
&Instruction::Unreachable => self.run_unreachable(context),
|
&Opcode::Unreachable => self.run_unreachable(context),
|
||||||
&Instruction::Nop => self.run_nop(context),
|
&Opcode::Nop => self.run_nop(context),
|
||||||
&Instruction::Block(block_type) => self.run_block(context, labels, block_type),
|
&Opcode::Block(block_type) => self.run_block(context, labels, block_type),
|
||||||
&Instruction::Loop(block_type) => self.run_loop(context, labels, block_type),
|
&Opcode::Loop(block_type) => self.run_loop(context, labels, block_type),
|
||||||
&Instruction::If(block_type) => self.run_if(context, labels, block_type),
|
&Opcode::If(block_type) => self.run_if(context, labels, block_type),
|
||||||
&Instruction::Else => self.run_else(context, labels),
|
&Opcode::Else => self.run_else(context, labels),
|
||||||
&Instruction::End => self.run_end(context),
|
&Opcode::End => self.run_end(context),
|
||||||
&Instruction::Br(idx) => self.run_br(context, idx),
|
&Opcode::Br(idx) => self.run_br(context, idx),
|
||||||
&Instruction::BrIf(idx) => self.run_br_if(context, idx),
|
&Opcode::BrIf(idx) => self.run_br_if(context, idx),
|
||||||
&Instruction::BrTable(ref table, default) => self.run_br_table(context, table, default),
|
&Opcode::BrTable(ref table, default) => self.run_br_table(context, table, default),
|
||||||
&Instruction::Return => self.run_return(context),
|
&Opcode::Return => self.run_return(context),
|
||||||
|
|
||||||
&Instruction::Call(index) => self.run_call(context, index),
|
&Opcode::Call(index) => self.run_call(context, index),
|
||||||
&Instruction::CallIndirect(index, _reserved) => self.run_call_indirect(context, index),
|
&Opcode::CallIndirect(index, _reserved) => self.run_call_indirect(context, index),
|
||||||
|
|
||||||
&Instruction::Drop => self.run_drop(context),
|
&Opcode::Drop => self.run_drop(context),
|
||||||
&Instruction::Select => self.run_select(context),
|
&Opcode::Select => self.run_select(context),
|
||||||
|
|
||||||
&Instruction::GetLocal(index) => self.run_get_local(context, index),
|
&Opcode::GetLocal(index) => self.run_get_local(context, index),
|
||||||
&Instruction::SetLocal(index) => self.run_set_local(context, index),
|
&Opcode::SetLocal(index) => self.run_set_local(context, index),
|
||||||
&Instruction::TeeLocal(index) => self.run_tee_local(context, index),
|
&Opcode::TeeLocal(index) => self.run_tee_local(context, index),
|
||||||
&Instruction::GetGlobal(index) => self.run_get_global(context, index),
|
&Opcode::GetGlobal(index) => self.run_get_global(context, index),
|
||||||
&Instruction::SetGlobal(index) => self.run_set_global(context, index),
|
&Opcode::SetGlobal(index) => self.run_set_global(context, index),
|
||||||
|
|
||||||
&Instruction::I32Load(align, offset) => self.run_load::<i32>(context, align, offset),
|
&Opcode::I32Load(align, offset) => self.run_load::<i32>(context, align, offset),
|
||||||
&Instruction::I64Load(align, offset) => self.run_load::<i64>(context, align, offset),
|
&Opcode::I64Load(align, offset) => self.run_load::<i64>(context, align, offset),
|
||||||
&Instruction::F32Load(align, offset) => self.run_load::<F32>(context, align, offset),
|
&Opcode::F32Load(align, offset) => self.run_load::<F32>(context, align, offset),
|
||||||
&Instruction::F64Load(align, offset) => self.run_load::<F64>(context, align, offset),
|
&Opcode::F64Load(align, offset) => self.run_load::<F64>(context, align, offset),
|
||||||
&Instruction::I32Load8S(align, offset) => self.run_load_extend::<i8, i32>(context, align, offset),
|
&Opcode::I32Load8S(align, offset) => self.run_load_extend::<i8, i32>(context, align, offset),
|
||||||
&Instruction::I32Load8U(align, offset) => self.run_load_extend::<u8, i32>(context, align, offset),
|
&Opcode::I32Load8U(align, offset) => self.run_load_extend::<u8, i32>(context, align, offset),
|
||||||
&Instruction::I32Load16S(align, offset) => self.run_load_extend::<i16, i32>(context, align, offset),
|
&Opcode::I32Load16S(align, offset) => self.run_load_extend::<i16, i32>(context, align, offset),
|
||||||
&Instruction::I32Load16U(align, offset) => self.run_load_extend::<u16, i32>(context, align, offset),
|
&Opcode::I32Load16U(align, offset) => self.run_load_extend::<u16, i32>(context, align, offset),
|
||||||
&Instruction::I64Load8S(align, offset) => self.run_load_extend::<i8, i64>(context, align, offset),
|
&Opcode::I64Load8S(align, offset) => self.run_load_extend::<i8, i64>(context, align, offset),
|
||||||
&Instruction::I64Load8U(align, offset) => self.run_load_extend::<u8, i64>(context, align, offset),
|
&Opcode::I64Load8U(align, offset) => self.run_load_extend::<u8, i64>(context, align, offset),
|
||||||
&Instruction::I64Load16S(align, offset) => self.run_load_extend::<i16, i64>(context, align, offset),
|
&Opcode::I64Load16S(align, offset) => self.run_load_extend::<i16, i64>(context, align, offset),
|
||||||
&Instruction::I64Load16U(align, offset) => self.run_load_extend::<u16, i64>(context, align, offset),
|
&Opcode::I64Load16U(align, offset) => self.run_load_extend::<u16, i64>(context, align, offset),
|
||||||
&Instruction::I64Load32S(align, offset) => self.run_load_extend::<i32, i64>(context, align, offset),
|
&Opcode::I64Load32S(align, offset) => self.run_load_extend::<i32, i64>(context, align, offset),
|
||||||
&Instruction::I64Load32U(align, offset) => self.run_load_extend::<u32, i64>(context, align, offset),
|
&Opcode::I64Load32U(align, offset) => self.run_load_extend::<u32, i64>(context, align, offset),
|
||||||
|
|
||||||
&Instruction::I32Store(align, offset) => self.run_store::<i32>(context, align, offset),
|
&Opcode::I32Store(align, offset) => self.run_store::<i32>(context, align, offset),
|
||||||
&Instruction::I64Store(align, offset) => self.run_store::<i64>(context, align, offset),
|
&Opcode::I64Store(align, offset) => self.run_store::<i64>(context, align, offset),
|
||||||
&Instruction::F32Store(align, offset) => self.run_store::<F32>(context, align, offset),
|
&Opcode::F32Store(align, offset) => self.run_store::<F32>(context, align, offset),
|
||||||
&Instruction::F64Store(align, offset) => self.run_store::<F64>(context, align, offset),
|
&Opcode::F64Store(align, offset) => self.run_store::<F64>(context, align, offset),
|
||||||
&Instruction::I32Store8(align, offset) => self.run_store_wrap::<i32, i8>(context, align, offset),
|
&Opcode::I32Store8(align, offset) => self.run_store_wrap::<i32, i8>(context, align, offset),
|
||||||
&Instruction::I32Store16(align, offset) => self.run_store_wrap::<i32, i16>(context, align, offset),
|
&Opcode::I32Store16(align, offset) => self.run_store_wrap::<i32, i16>(context, align, offset),
|
||||||
&Instruction::I64Store8(align, offset) => self.run_store_wrap::<i64, i8>(context, align, offset),
|
&Opcode::I64Store8(align, offset) => self.run_store_wrap::<i64, i8>(context, align, offset),
|
||||||
&Instruction::I64Store16(align, offset) => self.run_store_wrap::<i64, i16>(context, align, offset),
|
&Opcode::I64Store16(align, offset) => self.run_store_wrap::<i64, i16>(context, align, offset),
|
||||||
&Instruction::I64Store32(align, offset) => self.run_store_wrap::<i64, i32>(context, align, offset),
|
&Opcode::I64Store32(align, offset) => self.run_store_wrap::<i64, i32>(context, align, offset),
|
||||||
|
|
||||||
&Instruction::CurrentMemory(_) => self.run_current_memory(context),
|
&Opcode::CurrentMemory(_) => self.run_current_memory(context),
|
||||||
&Instruction::GrowMemory(_) => self.run_grow_memory(context),
|
&Opcode::GrowMemory(_) => self.run_grow_memory(context),
|
||||||
|
|
||||||
&Instruction::I32Const(val) => self.run_const(context, val.into()),
|
&Opcode::I32Const(val) => self.run_const(context, val.into()),
|
||||||
&Instruction::I64Const(val) => self.run_const(context, val.into()),
|
&Opcode::I64Const(val) => self.run_const(context, val.into()),
|
||||||
&Instruction::F32Const(val) => self.run_const(context, RuntimeValue::decode_f32(val)),
|
&Opcode::F32Const(val) => self.run_const(context, RuntimeValue::decode_f32(val)),
|
||||||
&Instruction::F64Const(val) => self.run_const(context, RuntimeValue::decode_f64(val)),
|
&Opcode::F64Const(val) => self.run_const(context, RuntimeValue::decode_f64(val)),
|
||||||
|
|
||||||
&Instruction::I32Eqz => self.run_eqz::<i32>(context),
|
&Opcode::I32Eqz => self.run_eqz::<i32>(context),
|
||||||
&Instruction::I32Eq => self.run_eq::<i32>(context),
|
&Opcode::I32Eq => self.run_eq::<i32>(context),
|
||||||
&Instruction::I32Ne => self.run_ne::<i32>(context),
|
&Opcode::I32Ne => self.run_ne::<i32>(context),
|
||||||
&Instruction::I32LtS => self.run_lt::<i32>(context),
|
&Opcode::I32LtS => self.run_lt::<i32>(context),
|
||||||
&Instruction::I32LtU => self.run_lt::<u32>(context),
|
&Opcode::I32LtU => self.run_lt::<u32>(context),
|
||||||
&Instruction::I32GtS => self.run_gt::<i32>(context),
|
&Opcode::I32GtS => self.run_gt::<i32>(context),
|
||||||
&Instruction::I32GtU => self.run_gt::<u32>(context),
|
&Opcode::I32GtU => self.run_gt::<u32>(context),
|
||||||
&Instruction::I32LeS => self.run_lte::<i32>(context),
|
&Opcode::I32LeS => self.run_lte::<i32>(context),
|
||||||
&Instruction::I32LeU => self.run_lte::<u32>(context),
|
&Opcode::I32LeU => self.run_lte::<u32>(context),
|
||||||
&Instruction::I32GeS => self.run_gte::<i32>(context),
|
&Opcode::I32GeS => self.run_gte::<i32>(context),
|
||||||
&Instruction::I32GeU => self.run_gte::<u32>(context),
|
&Opcode::I32GeU => self.run_gte::<u32>(context),
|
||||||
|
|
||||||
&Instruction::I64Eqz => self.run_eqz::<i64>(context),
|
&Opcode::I64Eqz => self.run_eqz::<i64>(context),
|
||||||
&Instruction::I64Eq => self.run_eq::<i64>(context),
|
&Opcode::I64Eq => self.run_eq::<i64>(context),
|
||||||
&Instruction::I64Ne => self.run_ne::<i64>(context),
|
&Opcode::I64Ne => self.run_ne::<i64>(context),
|
||||||
&Instruction::I64LtS => self.run_lt::<i64>(context),
|
&Opcode::I64LtS => self.run_lt::<i64>(context),
|
||||||
&Instruction::I64LtU => self.run_lt::<u64>(context),
|
&Opcode::I64LtU => self.run_lt::<u64>(context),
|
||||||
&Instruction::I64GtS => self.run_gt::<i64>(context),
|
&Opcode::I64GtS => self.run_gt::<i64>(context),
|
||||||
&Instruction::I64GtU => self.run_gt::<u64>(context),
|
&Opcode::I64GtU => self.run_gt::<u64>(context),
|
||||||
&Instruction::I64LeS => self.run_lte::<i64>(context),
|
&Opcode::I64LeS => self.run_lte::<i64>(context),
|
||||||
&Instruction::I64LeU => self.run_lte::<u64>(context),
|
&Opcode::I64LeU => self.run_lte::<u64>(context),
|
||||||
&Instruction::I64GeS => self.run_gte::<i64>(context),
|
&Opcode::I64GeS => self.run_gte::<i64>(context),
|
||||||
&Instruction::I64GeU => self.run_gte::<u64>(context),
|
&Opcode::I64GeU => self.run_gte::<u64>(context),
|
||||||
|
|
||||||
&Instruction::F32Eq => self.run_eq::<F32>(context),
|
&Opcode::F32Eq => self.run_eq::<F32>(context),
|
||||||
&Instruction::F32Ne => self.run_ne::<F32>(context),
|
&Opcode::F32Ne => self.run_ne::<F32>(context),
|
||||||
&Instruction::F32Lt => self.run_lt::<F32>(context),
|
&Opcode::F32Lt => self.run_lt::<F32>(context),
|
||||||
&Instruction::F32Gt => self.run_gt::<F32>(context),
|
&Opcode::F32Gt => self.run_gt::<F32>(context),
|
||||||
&Instruction::F32Le => self.run_lte::<F32>(context),
|
&Opcode::F32Le => self.run_lte::<F32>(context),
|
||||||
&Instruction::F32Ge => self.run_gte::<F32>(context),
|
&Opcode::F32Ge => self.run_gte::<F32>(context),
|
||||||
|
|
||||||
&Instruction::F64Eq => self.run_eq::<F64>(context),
|
&Opcode::F64Eq => self.run_eq::<F64>(context),
|
||||||
&Instruction::F64Ne => self.run_ne::<F64>(context),
|
&Opcode::F64Ne => self.run_ne::<F64>(context),
|
||||||
&Instruction::F64Lt => self.run_lt::<F64>(context),
|
&Opcode::F64Lt => self.run_lt::<F64>(context),
|
||||||
&Instruction::F64Gt => self.run_gt::<F64>(context),
|
&Opcode::F64Gt => self.run_gt::<F64>(context),
|
||||||
&Instruction::F64Le => self.run_lte::<F64>(context),
|
&Opcode::F64Le => self.run_lte::<F64>(context),
|
||||||
&Instruction::F64Ge => self.run_gte::<F64>(context),
|
&Opcode::F64Ge => self.run_gte::<F64>(context),
|
||||||
|
|
||||||
&Instruction::I32Clz => self.run_clz::<i32>(context),
|
&Opcode::I32Clz => self.run_clz::<i32>(context),
|
||||||
&Instruction::I32Ctz => self.run_ctz::<i32>(context),
|
&Opcode::I32Ctz => self.run_ctz::<i32>(context),
|
||||||
&Instruction::I32Popcnt => self.run_popcnt::<i32>(context),
|
&Opcode::I32Popcnt => self.run_popcnt::<i32>(context),
|
||||||
&Instruction::I32Add => self.run_add::<i32>(context),
|
&Opcode::I32Add => self.run_add::<i32>(context),
|
||||||
&Instruction::I32Sub => self.run_sub::<i32>(context),
|
&Opcode::I32Sub => self.run_sub::<i32>(context),
|
||||||
&Instruction::I32Mul => self.run_mul::<i32>(context),
|
&Opcode::I32Mul => self.run_mul::<i32>(context),
|
||||||
&Instruction::I32DivS => self.run_div::<i32, i32>(context),
|
&Opcode::I32DivS => self.run_div::<i32, i32>(context),
|
||||||
&Instruction::I32DivU => self.run_div::<i32, u32>(context),
|
&Opcode::I32DivU => self.run_div::<i32, u32>(context),
|
||||||
&Instruction::I32RemS => self.run_rem::<i32, i32>(context),
|
&Opcode::I32RemS => self.run_rem::<i32, i32>(context),
|
||||||
&Instruction::I32RemU => self.run_rem::<i32, u32>(context),
|
&Opcode::I32RemU => self.run_rem::<i32, u32>(context),
|
||||||
&Instruction::I32And => self.run_and::<i32>(context),
|
&Opcode::I32And => self.run_and::<i32>(context),
|
||||||
&Instruction::I32Or => self.run_or::<i32>(context),
|
&Opcode::I32Or => self.run_or::<i32>(context),
|
||||||
&Instruction::I32Xor => self.run_xor::<i32>(context),
|
&Opcode::I32Xor => self.run_xor::<i32>(context),
|
||||||
&Instruction::I32Shl => self.run_shl::<i32>(context, 0x1F),
|
&Opcode::I32Shl => self.run_shl::<i32>(context, 0x1F),
|
||||||
&Instruction::I32ShrS => self.run_shr::<i32, i32>(context, 0x1F),
|
&Opcode::I32ShrS => self.run_shr::<i32, i32>(context, 0x1F),
|
||||||
&Instruction::I32ShrU => self.run_shr::<i32, u32>(context, 0x1F),
|
&Opcode::I32ShrU => self.run_shr::<i32, u32>(context, 0x1F),
|
||||||
&Instruction::I32Rotl => self.run_rotl::<i32>(context),
|
&Opcode::I32Rotl => self.run_rotl::<i32>(context),
|
||||||
&Instruction::I32Rotr => self.run_rotr::<i32>(context),
|
&Opcode::I32Rotr => self.run_rotr::<i32>(context),
|
||||||
|
|
||||||
&Instruction::I64Clz => self.run_clz::<i64>(context),
|
&Opcode::I64Clz => self.run_clz::<i64>(context),
|
||||||
&Instruction::I64Ctz => self.run_ctz::<i64>(context),
|
&Opcode::I64Ctz => self.run_ctz::<i64>(context),
|
||||||
&Instruction::I64Popcnt => self.run_popcnt::<i64>(context),
|
&Opcode::I64Popcnt => self.run_popcnt::<i64>(context),
|
||||||
&Instruction::I64Add => self.run_add::<i64>(context),
|
&Opcode::I64Add => self.run_add::<i64>(context),
|
||||||
&Instruction::I64Sub => self.run_sub::<i64>(context),
|
&Opcode::I64Sub => self.run_sub::<i64>(context),
|
||||||
&Instruction::I64Mul => self.run_mul::<i64>(context),
|
&Opcode::I64Mul => self.run_mul::<i64>(context),
|
||||||
&Instruction::I64DivS => self.run_div::<i64, i64>(context),
|
&Opcode::I64DivS => self.run_div::<i64, i64>(context),
|
||||||
&Instruction::I64DivU => self.run_div::<i64, u64>(context),
|
&Opcode::I64DivU => self.run_div::<i64, u64>(context),
|
||||||
&Instruction::I64RemS => self.run_rem::<i64, i64>(context),
|
&Opcode::I64RemS => self.run_rem::<i64, i64>(context),
|
||||||
&Instruction::I64RemU => self.run_rem::<i64, u64>(context),
|
&Opcode::I64RemU => self.run_rem::<i64, u64>(context),
|
||||||
&Instruction::I64And => self.run_and::<i64>(context),
|
&Opcode::I64And => self.run_and::<i64>(context),
|
||||||
&Instruction::I64Or => self.run_or::<i64>(context),
|
&Opcode::I64Or => self.run_or::<i64>(context),
|
||||||
&Instruction::I64Xor => self.run_xor::<i64>(context),
|
&Opcode::I64Xor => self.run_xor::<i64>(context),
|
||||||
&Instruction::I64Shl => self.run_shl::<i64>(context, 0x3F),
|
&Opcode::I64Shl => self.run_shl::<i64>(context, 0x3F),
|
||||||
&Instruction::I64ShrS => self.run_shr::<i64, i64>(context, 0x3F),
|
&Opcode::I64ShrS => self.run_shr::<i64, i64>(context, 0x3F),
|
||||||
&Instruction::I64ShrU => self.run_shr::<i64, u64>(context, 0x3F),
|
&Opcode::I64ShrU => self.run_shr::<i64, u64>(context, 0x3F),
|
||||||
&Instruction::I64Rotl => self.run_rotl::<i64>(context),
|
&Opcode::I64Rotl => self.run_rotl::<i64>(context),
|
||||||
&Instruction::I64Rotr => self.run_rotr::<i64>(context),
|
&Opcode::I64Rotr => self.run_rotr::<i64>(context),
|
||||||
|
|
||||||
&Instruction::F32Abs => self.run_abs::<F32>(context),
|
&Opcode::F32Abs => self.run_abs::<F32>(context),
|
||||||
&Instruction::F32Neg => self.run_neg::<F32>(context),
|
&Opcode::F32Neg => self.run_neg::<F32>(context),
|
||||||
&Instruction::F32Ceil => self.run_ceil::<F32>(context),
|
&Opcode::F32Ceil => self.run_ceil::<F32>(context),
|
||||||
&Instruction::F32Floor => self.run_floor::<F32>(context),
|
&Opcode::F32Floor => self.run_floor::<F32>(context),
|
||||||
&Instruction::F32Trunc => self.run_trunc::<F32>(context),
|
&Opcode::F32Trunc => self.run_trunc::<F32>(context),
|
||||||
&Instruction::F32Nearest => self.run_nearest::<F32>(context),
|
&Opcode::F32Nearest => self.run_nearest::<F32>(context),
|
||||||
&Instruction::F32Sqrt => self.run_sqrt::<F32>(context),
|
&Opcode::F32Sqrt => self.run_sqrt::<F32>(context),
|
||||||
&Instruction::F32Add => self.run_add::<F32>(context),
|
&Opcode::F32Add => self.run_add::<F32>(context),
|
||||||
&Instruction::F32Sub => self.run_sub::<F32>(context),
|
&Opcode::F32Sub => self.run_sub::<F32>(context),
|
||||||
&Instruction::F32Mul => self.run_mul::<F32>(context),
|
&Opcode::F32Mul => self.run_mul::<F32>(context),
|
||||||
&Instruction::F32Div => self.run_div::<F32, F32>(context),
|
&Opcode::F32Div => self.run_div::<F32, F32>(context),
|
||||||
&Instruction::F32Min => self.run_min::<F32>(context),
|
&Opcode::F32Min => self.run_min::<F32>(context),
|
||||||
&Instruction::F32Max => self.run_max::<F32>(context),
|
&Opcode::F32Max => self.run_max::<F32>(context),
|
||||||
&Instruction::F32Copysign => self.run_copysign::<F32>(context),
|
&Opcode::F32Copysign => self.run_copysign::<F32>(context),
|
||||||
|
|
||||||
&Instruction::F64Abs => self.run_abs::<F64>(context),
|
&Opcode::F64Abs => self.run_abs::<F64>(context),
|
||||||
&Instruction::F64Neg => self.run_neg::<F64>(context),
|
&Opcode::F64Neg => self.run_neg::<F64>(context),
|
||||||
&Instruction::F64Ceil => self.run_ceil::<F64>(context),
|
&Opcode::F64Ceil => self.run_ceil::<F64>(context),
|
||||||
&Instruction::F64Floor => self.run_floor::<F64>(context),
|
&Opcode::F64Floor => self.run_floor::<F64>(context),
|
||||||
&Instruction::F64Trunc => self.run_trunc::<F64>(context),
|
&Opcode::F64Trunc => self.run_trunc::<F64>(context),
|
||||||
&Instruction::F64Nearest => self.run_nearest::<F64>(context),
|
&Opcode::F64Nearest => self.run_nearest::<F64>(context),
|
||||||
&Instruction::F64Sqrt => self.run_sqrt::<F64>(context),
|
&Opcode::F64Sqrt => self.run_sqrt::<F64>(context),
|
||||||
&Instruction::F64Add => self.run_add::<F64>(context),
|
&Opcode::F64Add => self.run_add::<F64>(context),
|
||||||
&Instruction::F64Sub => self.run_sub::<F64>(context),
|
&Opcode::F64Sub => self.run_sub::<F64>(context),
|
||||||
&Instruction::F64Mul => self.run_mul::<F64>(context),
|
&Opcode::F64Mul => self.run_mul::<F64>(context),
|
||||||
&Instruction::F64Div => self.run_div::<F64, F64>(context),
|
&Opcode::F64Div => self.run_div::<F64, F64>(context),
|
||||||
&Instruction::F64Min => self.run_min::<F64>(context),
|
&Opcode::F64Min => self.run_min::<F64>(context),
|
||||||
&Instruction::F64Max => self.run_max::<F64>(context),
|
&Opcode::F64Max => self.run_max::<F64>(context),
|
||||||
&Instruction::F64Copysign => self.run_copysign::<F64>(context),
|
&Opcode::F64Copysign => self.run_copysign::<F64>(context),
|
||||||
|
|
||||||
&Instruction::I32WrapI64 => self.run_wrap::<i64, i32>(context),
|
&Opcode::I32WrapI64 => self.run_wrap::<i64, i32>(context),
|
||||||
&Instruction::I32TruncSF32 => self.run_trunc_to_int::<F32, i32, i32>(context),
|
&Opcode::I32TruncSF32 => self.run_trunc_to_int::<F32, i32, i32>(context),
|
||||||
&Instruction::I32TruncUF32 => self.run_trunc_to_int::<F32, u32, i32>(context),
|
&Opcode::I32TruncUF32 => self.run_trunc_to_int::<F32, u32, i32>(context),
|
||||||
&Instruction::I32TruncSF64 => self.run_trunc_to_int::<F64, i32, i32>(context),
|
&Opcode::I32TruncSF64 => self.run_trunc_to_int::<F64, i32, i32>(context),
|
||||||
&Instruction::I32TruncUF64 => self.run_trunc_to_int::<F64, u32, i32>(context),
|
&Opcode::I32TruncUF64 => self.run_trunc_to_int::<F64, u32, i32>(context),
|
||||||
&Instruction::I64ExtendSI32 => self.run_extend::<i32, i64, i64>(context),
|
&Opcode::I64ExtendSI32 => self.run_extend::<i32, i64, i64>(context),
|
||||||
&Instruction::I64ExtendUI32 => self.run_extend::<u32, u64, i64>(context),
|
&Opcode::I64ExtendUI32 => self.run_extend::<u32, u64, i64>(context),
|
||||||
&Instruction::I64TruncSF32 => self.run_trunc_to_int::<F32, i64, i64>(context),
|
&Opcode::I64TruncSF32 => self.run_trunc_to_int::<F32, i64, i64>(context),
|
||||||
&Instruction::I64TruncUF32 => self.run_trunc_to_int::<F32, u64, i64>(context),
|
&Opcode::I64TruncUF32 => self.run_trunc_to_int::<F32, u64, i64>(context),
|
||||||
&Instruction::I64TruncSF64 => self.run_trunc_to_int::<F64, i64, i64>(context),
|
&Opcode::I64TruncSF64 => self.run_trunc_to_int::<F64, i64, i64>(context),
|
||||||
&Instruction::I64TruncUF64 => self.run_trunc_to_int::<F64, u64, i64>(context),
|
&Opcode::I64TruncUF64 => self.run_trunc_to_int::<F64, u64, i64>(context),
|
||||||
&Instruction::F32ConvertSI32 => self.run_extend::<i32, F32, F32>(context),
|
&Opcode::F32ConvertSI32 => self.run_extend::<i32, F32, F32>(context),
|
||||||
&Instruction::F32ConvertUI32 => self.run_extend::<u32, F32, F32>(context),
|
&Opcode::F32ConvertUI32 => self.run_extend::<u32, F32, F32>(context),
|
||||||
&Instruction::F32ConvertSI64 => self.run_wrap::<i64, F32>(context),
|
&Opcode::F32ConvertSI64 => self.run_wrap::<i64, F32>(context),
|
||||||
&Instruction::F32ConvertUI64 => self.run_wrap::<u64, F32>(context),
|
&Opcode::F32ConvertUI64 => self.run_wrap::<u64, F32>(context),
|
||||||
&Instruction::F32DemoteF64 => self.run_wrap::<F64, F32>(context),
|
&Opcode::F32DemoteF64 => self.run_wrap::<F64, F32>(context),
|
||||||
&Instruction::F64ConvertSI32 => self.run_extend::<i32, F64, F64>(context),
|
&Opcode::F64ConvertSI32 => self.run_extend::<i32, F64, F64>(context),
|
||||||
&Instruction::F64ConvertUI32 => self.run_extend::<u32, F64, F64>(context),
|
&Opcode::F64ConvertUI32 => self.run_extend::<u32, F64, F64>(context),
|
||||||
&Instruction::F64ConvertSI64 => self.run_extend::<i64, F64, F64>(context),
|
&Opcode::F64ConvertSI64 => self.run_extend::<i64, F64, F64>(context),
|
||||||
&Instruction::F64ConvertUI64 => self.run_extend::<u64, F64, F64>(context),
|
&Opcode::F64ConvertUI64 => self.run_extend::<u64, F64, F64>(context),
|
||||||
&Instruction::F64PromoteF32 => self.run_extend::<F32, F64, F64>(context),
|
&Opcode::F64PromoteF32 => self.run_extend::<F32, F64, F64>(context),
|
||||||
|
|
||||||
&Instruction::I32ReinterpretF32 => self.run_reinterpret::<F32, i32>(context),
|
&Opcode::I32ReinterpretF32 => self.run_reinterpret::<F32, i32>(context),
|
||||||
&Instruction::I64ReinterpretF64 => self.run_reinterpret::<F64, i64>(context),
|
&Opcode::I64ReinterpretF64 => self.run_reinterpret::<F64, i64>(context),
|
||||||
&Instruction::F32ReinterpretI32 => self.run_reinterpret::<i32, F32>(context),
|
&Opcode::F32ReinterpretI32 => self.run_reinterpret::<i32, F32>(context),
|
||||||
&Instruction::F64ReinterpretI64 => self.run_reinterpret::<i64, F64>(context),
|
&Opcode::F64ReinterpretI64 => self.run_reinterpret::<i64, F64>(context),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -400,7 +400,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
||||||
Ok(InstructionOutcome::RunNextInstruction)
|
Ok(InstructionOutcome::RunNextInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_else(&mut self, context: &mut FunctionContext, labels: &HashMap<usize, usize>) -> Result<InstructionOutcome, TrapKind> {
|
fn run_else(&mut self, context: &mut FunctionContext) -> Result<InstructionOutcome, TrapKind> {
|
||||||
let end_pos = labels[&context.position];
|
let end_pos = labels[&context.position];
|
||||||
context.pop_frame(false)?;
|
context.pop_frame(false)?;
|
||||||
context.position = end_pos;
|
context.position = end_pos;
|
||||||
|
@ -1144,7 +1144,7 @@ impl FunctionContext {
|
||||||
&self.frame_stack
|
&self.frame_stack
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_frame(&mut self, labels: &HashMap<usize, usize>, frame_type: BlockFrameType, block_type: BlockType) -> Result<(), TrapKind> {
|
pub fn push_frame(&mut self, frame_type: BlockFrameType, block_type: BlockType) -> Result<(), TrapKind> {
|
||||||
let begin_position = self.position;
|
let begin_position = self.position;
|
||||||
let branch_position = match frame_type {
|
let branch_position = match frame_type {
|
||||||
BlockFrameType::Function => usize::MAX,
|
BlockFrameType::Function => usize::MAX,
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -9,6 +9,7 @@ use common::stack;
|
||||||
use self::context::ModuleContextBuilder;
|
use self::context::ModuleContextBuilder;
|
||||||
use self::func::Validator;
|
use self::func::Validator;
|
||||||
use memory_units::Pages;
|
use memory_units::Pages;
|
||||||
|
use isa;
|
||||||
|
|
||||||
mod context;
|
mod context;
|
||||||
mod func;
|
mod func;
|
||||||
|
@ -40,7 +41,7 @@ impl From<stack::Error> for Error {
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ValidatedModule {
|
pub struct ValidatedModule {
|
||||||
pub labels: HashMap<usize, HashMap<usize, usize>>,
|
pub code_map: Vec<isa::Instructions>,
|
||||||
pub module: Module,
|
pub module: Module,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,7 +168,7 @@ pub fn deny_floating_point(module: &Module) -> Result<(), Error> {
|
||||||
pub fn validate_module(module: Module) -> Result<ValidatedModule, Error> {
|
pub fn validate_module(module: Module) -> Result<ValidatedModule, Error> {
|
||||||
let mut context_builder = ModuleContextBuilder::new();
|
let mut context_builder = ModuleContextBuilder::new();
|
||||||
let mut imported_globals = Vec::new();
|
let mut imported_globals = Vec::new();
|
||||||
let mut labels = HashMap::new();
|
let mut code_map = Vec::new();
|
||||||
|
|
||||||
// Copy types from module as is.
|
// Copy types from module as is.
|
||||||
context_builder.set_types(
|
context_builder.set_types(
|
||||||
|
@ -257,12 +258,12 @@ pub fn validate_module(module: Module) -> Result<ValidatedModule, Error> {
|
||||||
index
|
index
|
||||||
)),
|
)),
|
||||||
)?;
|
)?;
|
||||||
let func_labels = Validator::validate_function(&context, function, function_body)
|
let code = Validator::validate_function(&context, function, function_body)
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
let Error(ref msg) = e;
|
let Error(ref msg) = e;
|
||||||
Error(format!("Function #{} validation error: {}", index, msg))
|
Error(format!("Function #{} validation error: {}", index, msg))
|
||||||
})?;
|
})?;
|
||||||
labels.insert(index, func_labels);
|
code_map.push(code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -374,7 +375,7 @@ pub fn validate_module(module: Module) -> Result<ValidatedModule, Error> {
|
||||||
|
|
||||||
Ok(ValidatedModule {
|
Ok(ValidatedModule {
|
||||||
module,
|
module,
|
||||||
labels
|
code_map,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,21 @@ impl<'a> Locals<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns total count of all declared locals and paramaterers.
|
||||||
|
///
|
||||||
|
/// Returns `Err` if count overflows 32-bit value.
|
||||||
|
pub fn count(&self) -> Result<u32, Error> {
|
||||||
|
let mut acc = self.params.len() as u32;
|
||||||
|
for locals_group in self.local_groups {
|
||||||
|
acc = acc
|
||||||
|
.checked_add(locals_group.count())
|
||||||
|
.ok_or_else(||
|
||||||
|
Error(String::from("Locals range no in 32-bit range"))
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
Ok(acc)
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the type of a local variable (either a declared local or a param).
|
/// Returns the type of a local variable (either a declared local or a param).
|
||||||
///
|
///
|
||||||
/// Returns `Err` in the case of overflow or when idx falls out of range.
|
/// Returns `Err` in the case of overflow or when idx falls out of range.
|
||||||
|
|
Loading…
Reference in New Issue