Rename/Split Validator into Reader

This commit is contained in:
Sergey Pepyakin 2018-06-18 19:47:45 +03:00
parent 29002153ec
commit 6506705310
2 changed files with 40 additions and 24 deletions

View File

@ -150,20 +150,19 @@ impl PartialEq<StackValueType> for ValueType {
} }
} }
/// Function validator.
pub struct Validator;
/// Instruction outcome. /// Instruction outcome.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
enum InstructionOutcome { enum Outcome {
/// Continue with next instruction. /// Continue with next instruction.
ValidateNextInstruction, NextInstruction,
/// Unreachable instruction reached. /// Unreachable instruction reached.
Unreachable, Unreachable,
} }
impl Validator { pub struct FunctionReader;
pub fn validate_function(
impl FunctionReader {
pub fn read_function(
module: &ModuleContext, module: &ModuleContext,
func: &Func, func: &Func,
body: &FuncBody, body: &FuncBody,
@ -190,14 +189,14 @@ impl Validator {
&context.value_stack, &context.value_stack,
&mut context.frame_stack, &mut context.frame_stack,
)?; )?;
Validator::validate_function_block(&mut context, body.code().elements())?; FunctionReader::read_function_body(&mut context, body.code().elements())?;
assert!(context.frame_stack.is_empty()); assert!(context.frame_stack.is_empty());
Ok(context.into_code()) Ok(context.into_code())
} }
fn validate_function_block(context: &mut FunctionValidationContext, body: &[Opcode]) -> Result<(), Error> { fn read_function_body(context: &mut FunctionValidationContext, body: &[Opcode]) -> Result<(), Error> {
let body_len = body.len(); let body_len = body.len();
if body_len == 0 { if body_len == 0 {
return Err(Error("Non-empty function body expected".into())); return Err(Error("Non-empty function body expected".into()));
@ -206,13 +205,13 @@ impl Validator {
loop { loop {
let opcode = &body[context.position]; let opcode = &body[context.position];
let outcome = Validator::validate_instruction(context, opcode) let outcome = FunctionReader::read_instruction(context, opcode)
.map_err(|err| Error(format!("At instruction {:?}(@{}): {}", opcode, context.position, err)))?; .map_err(|err| Error(format!("At instruction {:?}(@{}): {}", opcode, context.position, err)))?;
println!("opcode: {:?}, outcome={:?}", opcode, outcome); println!("opcode: {:?}, outcome={:?}", opcode, outcome);
match outcome { match outcome {
InstructionOutcome::ValidateNextInstruction => (), Outcome::NextInstruction => (),
InstructionOutcome::Unreachable => make_top_frame_polymorphic( Outcome::Unreachable => make_top_frame_polymorphic(
&mut context.value_stack, &mut context.value_stack,
&mut context.frame_stack &mut context.frame_stack
), ),
@ -225,7 +224,7 @@ impl Validator {
} }
} }
fn validate_instruction(context: &mut FunctionValidationContext, opcode: &Opcode) -> Result<InstructionOutcome, Error> { fn read_instruction(context: &mut FunctionValidationContext, opcode: &Opcode) -> Result<Outcome, Error> {
use self::Opcode::*; use self::Opcode::*;
match *opcode { match *opcode {
// Nop instruction doesn't do anything. It is safe to just skip it. // Nop instruction doesn't do anything. It is safe to just skip it.
@ -233,7 +232,7 @@ impl Validator {
Unreachable => { Unreachable => {
context.sink.emit(isa::Instruction::Unreachable); context.sink.emit(isa::Instruction::Unreachable);
return Ok(InstructionOutcome::Unreachable); return Ok(Outcome::Unreachable);
} }
Block(block_type) => { Block(block_type) => {
@ -375,6 +374,7 @@ impl Validator {
)?; )?;
} }
// Emit the return instruction.
let drop_keep = drop_keep_return( let drop_keep = drop_keep_return(
&context.locals, &context.locals,
&context.value_stack, &context.value_stack,
@ -400,7 +400,7 @@ impl Validator {
); );
context.sink.emit_br(target); context.sink.emit_br(target);
return Ok(InstructionOutcome::Unreachable); return Ok(Outcome::Unreachable);
} }
BrIf(depth) => { BrIf(depth) => {
Validator::validate_br_if(context, depth)?; Validator::validate_br_if(context, depth)?;
@ -431,7 +431,7 @@ impl Validator {
); );
context.sink.emit_br_table(&targets, default_target); context.sink.emit_br_table(&targets, default_target);
return Ok(InstructionOutcome::Unreachable); return Ok(Outcome::Unreachable);
} }
Return => { Return => {
if let BlockType::Value(value_type) = context.return_type()? { if let BlockType::Value(value_type) = context.return_type()? {
@ -445,7 +445,7 @@ impl Validator {
); );
context.sink.emit(isa::Instruction::Return(drop_keep)); context.sink.emit(isa::Instruction::Return(drop_keep));
return Ok(InstructionOutcome::Unreachable); return Ok(Outcome::Unreachable);
} }
Call(index) => { Call(index) => {
@ -1133,9 +1133,14 @@ impl Validator {
} }
} }
Ok(InstructionOutcome::ValidateNextInstruction) Ok(Outcome::NextInstruction)
}
} }
/// Function validator.
struct Validator;
impl Validator {
fn validate_const(context: &mut FunctionValidationContext, value_type: ValueType) -> Result<(), Error> { fn validate_const(context: &mut FunctionValidationContext, value_type: ValueType) -> Result<(), Error> {
push_value(&mut context.value_stack, value_type.into())?; push_value(&mut context.value_stack, value_type.into())?;
Ok(()) Ok(())
@ -1379,8 +1384,7 @@ struct FunctionValidationContext<'a> {
frame_stack: StackWithLimit<BlockFrame>, frame_stack: StackWithLimit<BlockFrame>,
/// Function return type. /// Function return type.
return_type: BlockType, return_type: BlockType,
/// A sink used to emit optimized code.
// TODO: comment
sink: Sink, sink: Sink,
} }
@ -1603,12 +1607,12 @@ fn require_local(locals: &Locals, idx: u32) -> Result<ValueType, Error> {
Ok(locals.type_of_local(idx)?) Ok(locals.type_of_local(idx)?)
} }
/// See stack layout definition in mod isa.
fn relative_local_depth( fn relative_local_depth(
idx: u32, idx: u32,
locals: &Locals, locals: &Locals,
value_stack: &StackWithLimit<StackValueType> value_stack: &StackWithLimit<StackValueType>
) -> Result<u32, Error> { ) -> Result<u32, Error> {
// TODO: Comment stack layout
let value_stack_height = value_stack.len() as u32; let value_stack_height = value_stack.len() as u32;
let locals_and_params_count = locals.count(); let locals_and_params_count = locals.count();
@ -1621,23 +1625,33 @@ fn relative_local_depth(
Ok(depth) Ok(depth)
} }
/// The target of a branch instruction.
///
/// It references a `LabelId` instead of exact instruction address. This is handy
/// for emitting code right away with labels resolved later.
#[derive(Clone)] #[derive(Clone)]
struct Target { struct Target {
label: LabelId, label: LabelId,
drop_keep: isa::DropKeep, drop_keep: isa::DropKeep,
} }
/// A relocation entry that specifies.
#[derive(Debug)] #[derive(Debug)]
enum Reloc { enum Reloc {
/// Patch the destination of the branch instruction (br, br_eqz, br_nez)
/// at the specified pc.
Br { Br {
pc: u32, pc: u32,
}, },
/// Patch the specified destination index inside of br_table instruction at
/// the specified pc.
BrTable { BrTable {
pc: u32, pc: u32,
idx: usize, idx: usize,
}, },
} }
/// Identifier of a label.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
struct LabelId(usize); struct LabelId(usize);
@ -1737,6 +1751,7 @@ impl Sink {
)); ));
} }
/// Create a new unresolved label.
fn new_label(&mut self) -> LabelId { fn new_label(&mut self) -> LabelId {
let label_idx = self.labels.len(); let label_idx = self.labels.len();
self.labels.push( self.labels.push(
@ -1778,6 +1793,7 @@ impl Sink {
self.labels[label.0] = (Label::Resolved(dst_pc), Vec::new()); self.labels[label.0] = (Label::Resolved(dst_pc), Vec::new());
} }
/// Consume this Sink and returns isa::Instruction.
fn into_inner(self) -> Vec<isa::Instruction> { fn into_inner(self) -> Vec<isa::Instruction> {
// At this moment all labels should be resolved. // At this moment all labels should be resolved.
assert!({ assert!({

View File

@ -7,7 +7,7 @@ use parity_wasm::elements::{
}; };
use common::stack; use common::stack;
use self::context::ModuleContextBuilder; use self::context::ModuleContextBuilder;
use self::func::Validator; use self::func::FunctionReader;
use memory_units::Pages; use memory_units::Pages;
use isa; use isa;
@ -258,10 +258,10 @@ pub fn validate_module(module: Module) -> Result<ValidatedModule, Error> {
index index
)), )),
)?; )?;
let code = Validator::validate_function(&context, function, function_body) let code = FunctionReader::read_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 #{} reading/validation error: {}", index, msg))
})?; })?;
code_map.push(code); code_map.push(code);
} }