WIP
This commit is contained in:
parent
1702372696
commit
5653e2809f
|
@ -7,6 +7,8 @@ pub const DEFAULT_MEMORY_INDEX: u32 = 0;
|
|||
/// Index of default table.
|
||||
pub const DEFAULT_TABLE_INDEX: u32 = 0;
|
||||
|
||||
// TODO: Move BlockFrame under validation.
|
||||
|
||||
/// Control stack frame.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct BlockFrame {
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
use std::rc::{Rc, Weak};
|
||||
use std::fmt;
|
||||
use std::collections::HashMap;
|
||||
use parity_wasm::elements::{Local, Opcodes};
|
||||
use parity_wasm::elements::Local;
|
||||
use {Trap, TrapKind, Signature};
|
||||
use host::Externals;
|
||||
use runner::{check_function_args, Interpreter};
|
||||
use value::RuntimeValue;
|
||||
use module::ModuleInstance;
|
||||
use isa;
|
||||
|
||||
/// Reference to a function (See [`FuncInstance`] for details).
|
||||
///
|
||||
|
@ -158,6 +158,5 @@ impl FuncInstance {
|
|||
#[derive(Clone, Debug)]
|
||||
pub struct FuncBody {
|
||||
pub locals: Vec<Local>,
|
||||
pub opcodes: Opcodes,
|
||||
pub labels: HashMap<usize, usize>,
|
||||
pub code: isa::Instructions,
|
||||
}
|
||||
|
|
|
@ -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 func;
|
||||
mod types;
|
||||
mod instructions;
|
||||
mod isa;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
@ -379,7 +379,7 @@ pub mod memory_units {
|
|||
|
||||
/// Deserialized module prepared for instantiation.
|
||||
pub struct Module {
|
||||
labels: HashMap<usize, HashMap<usize, usize>>,
|
||||
code_map: Vec<isa::Instructions>,
|
||||
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> {
|
||||
use validation::{validate_module, ValidatedModule};
|
||||
let ValidatedModule {
|
||||
labels,
|
||||
code_map,
|
||||
module,
|
||||
} = validate_module(module)?;
|
||||
|
||||
Ok(Module {
|
||||
labels,
|
||||
code_map,
|
||||
module,
|
||||
})
|
||||
}
|
||||
|
@ -525,7 +525,7 @@ impl Module {
|
|||
&self.module
|
||||
}
|
||||
|
||||
pub(crate) fn labels(&self) -> &HashMap<usize, HashMap<usize, usize>> {
|
||||
&self.labels
|
||||
pub(crate) fn code(&self) -> &Vec<isa::Instructions> {
|
||||
&self.code_map
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
&[],
|
||||
|
@ -308,13 +308,12 @@ impl ModuleInstance {
|
|||
let signature = instance.signature_by_index(ty.type_ref()).expect(
|
||||
"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",
|
||||
).clone();
|
||||
let func_body = FuncBody {
|
||||
locals: body.locals().to_vec(),
|
||||
opcodes: body.code().clone(),
|
||||
labels: labels,
|
||||
code: code,
|
||||
};
|
||||
let func_instance =
|
||||
FuncInstance::alloc_internal(Rc::downgrade(&instance.0), signature, func_body);
|
||||
|
|
|
@ -84,7 +84,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
|||
if !function_context.is_initialized() {
|
||||
let return_type = function_context.return_type;
|
||||
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.opcodes.elements(), &function_body.labels).map_err(Trap::new)?;
|
||||
|
@ -127,7 +127,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
|||
}
|
||||
}
|
||||
|
||||
fn do_run_function(&mut self, function_context: &mut FunctionContext, function_body: &[Opcode], 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 {
|
||||
let instruction = &function_body[function_context.position];
|
||||
|
||||
|
@ -400,7 +400,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
|
|||
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];
|
||||
context.pop_frame(false)?;
|
||||
context.position = end_pos;
|
||||
|
@ -1144,7 +1144,7 @@ impl FunctionContext {
|
|||
&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 branch_position = match frame_type {
|
||||
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::func::Validator;
|
||||
use memory_units::Pages;
|
||||
use isa;
|
||||
|
||||
mod context;
|
||||
mod func;
|
||||
|
@ -40,7 +41,7 @@ impl From<stack::Error> for Error {
|
|||
|
||||
#[derive(Clone)]
|
||||
pub struct ValidatedModule {
|
||||
pub labels: HashMap<usize, HashMap<usize, usize>>,
|
||||
pub code_map: Vec<isa::Instructions>,
|
||||
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> {
|
||||
let mut context_builder = ModuleContextBuilder::new();
|
||||
let mut imported_globals = Vec::new();
|
||||
let mut labels = HashMap::new();
|
||||
let mut code_map = Vec::new();
|
||||
|
||||
// Copy types from module as is.
|
||||
context_builder.set_types(
|
||||
|
@ -257,12 +258,12 @@ pub fn validate_module(module: Module) -> Result<ValidatedModule, Error> {
|
|||
index
|
||||
)),
|
||||
)?;
|
||||
let func_labels = Validator::validate_function(&context, function, function_body)
|
||||
let code = Validator::validate_function(&context, function, function_body)
|
||||
.map_err(|e| {
|
||||
let Error(ref msg) = e;
|
||||
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 {
|
||||
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 `Err` in the case of overflow or when idx falls out of range.
|
||||
|
|
Loading…
Reference in New Issue