diff --git a/src/isa.rs b/src/isa.rs index b188843..e4cdde6 100644 --- a/src/isa.rs +++ b/src/isa.rs @@ -74,7 +74,6 @@ use alloc::prelude::*; /// /// Note that this is a `enum` since Wasm doesn't support multiple return /// values at the moment. -#[repr(u8)] #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum Keep { None, @@ -90,30 +89,46 @@ pub struct DropKeep { pub keep: Keep, } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct Target { pub dst_pc: u32, pub drop_keep: DropKeep, } /// A relocation entry that specifies. -#[derive(Debug)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum Reloc { /// Patch the destination of the branch instruction (br, br_eqz, br_nez) /// at the specified pc. - Br { - pc: u32, - }, + Br { pc: u32 }, /// Patch the specified destination index inside of br_table instruction at /// the specified pc. - BrTable { - pc: u32, - idx: usize, - }, + BrTable { pc: u32, idx: usize }, } +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct BrTargets<'a> { + stream: &'a [InstructionInternal], +} + +impl<'a> BrTargets<'a> { + pub(crate) fn from_internal(targets: &'a [InstructionInternal]) -> Self { + BrTargets { stream: targets } + } + + #[inline] + pub fn get(&self, index: u32) -> Target { + match self.stream[index.min(self.stream.len() as u32 - 1) as usize] { + InstructionInternal::BrTableTarget(target) => target, + _ => panic!("BrTable has incorrect target count"), + } + } +} + +/// The main interpreted instruction type. This is what is returned by `InstructionIter`, but +/// it is not what is stored internally. For that, see `InstructionInternal`. #[derive(Debug, Clone, PartialEq)] -pub enum Instruction { +pub enum Instruction<'a> { /// Push a local variable or an argument from the specified depth. GetLocal(u32), @@ -138,7 +153,202 @@ pub enum Instruction { /// is greater than length of the branch table, then the last index will be used. /// /// Validation ensures that there should be at least one target. - BrTable(Box<[Target]>), + BrTable(BrTargets<'a>), + + Unreachable, + Return(DropKeep), + + 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, +} + +/// The internally-stored instruction type. This differs from `Instruction` in that the `BrTable` +/// target list is "unrolled" into seperate instructions in order to be able to A) improve cache +/// usage and B) allow this struct to be `Copy` and therefore allow `Instructions::clone` to be +/// a `memcpy`. It also means that `Instructions::drop` is trivial. The overall speedup on some +/// benchmarks is as high as 13%. +/// +/// When returning instructions we convert to `Instruction`, whose `BrTable` variant internally +/// borrows the list of instructions and returns targets by reading it. +#[derive(Copy, Debug, Clone, PartialEq, Eq)] +pub(crate) enum InstructionInternal { + GetLocal(u32), + SetLocal(u32), + TeeLocal(u32), + Br(Target), + BrIfEqz(Target), + BrIfNez(Target), + BrTable { count: u32 }, + BrTableTarget(Target), Unreachable, Return(DropKeep), @@ -318,7 +528,7 @@ pub enum Instruction { #[derive(Debug, Clone)] pub struct Instructions { - vec: Vec, + vec: Vec, } impl Instructions { @@ -332,27 +542,27 @@ impl Instructions { self.vec.len() as u32 } - pub fn push(&mut self, instruction: Instruction) { + pub(crate) fn push(&mut self, instruction: InstructionInternal) { self.vec.push(instruction); } pub fn patch_relocation(&mut self, reloc: Reloc, dst_pc: u32) { match reloc { Reloc::Br { pc } => match self.vec[pc as usize] { - Instruction::Br(ref mut target) - | Instruction::BrIfEqz(ref mut target) - | Instruction::BrIfNez(ref mut target) => target.dst_pc = dst_pc, + InstructionInternal::Br(ref mut target) + | InstructionInternal::BrIfEqz(ref mut target) + | InstructionInternal::BrIfNez(ref mut target) => target.dst_pc = dst_pc, _ => panic!("branch relocation points to a non-branch instruction"), }, - Reloc::BrTable { pc, idx } => match self.vec[pc as usize] { - Instruction::BrTable(ref mut targets) => targets[idx].dst_pc = dst_pc, + Reloc::BrTable { pc, idx } => match &mut self.vec[pc as usize + idx + 1] { + InstructionInternal::BrTableTarget(target) => target.dst_pc = dst_pc, _ => panic!("brtable relocation points to not brtable instruction"), - } + }, } } pub fn iterate_from(&self, position: u32) -> InstructionIter { - InstructionIter{ + InstructionIter { instructions: &self.vec, position, } @@ -360,7 +570,7 @@ impl Instructions { } pub struct InstructionIter<'a> { - instructions: &'a [Instruction], + instructions: &'a [InstructionInternal], position: u32, } @@ -372,13 +582,212 @@ impl<'a> InstructionIter<'a> { } impl<'a> Iterator for InstructionIter<'a> { - type Item = &'a Instruction; + type Item = Instruction<'a>; #[inline] - fn next(&mut self) -> Option<::Item> { - self.instructions.get(self.position as usize).map(|instruction| { - self.position += 1; - instruction - }) + fn next(&mut self) -> Option { + let internal = if let Some(i) = self.instructions.get(self.position as usize) { + i + } else { + return None; + }; + + let out = match *internal { + InstructionInternal::GetLocal(x) => Instruction::GetLocal(x), + InstructionInternal::SetLocal(x) => Instruction::SetLocal(x), + InstructionInternal::TeeLocal(x) => Instruction::TeeLocal(x), + InstructionInternal::Br(x) => Instruction::Br(x), + InstructionInternal::BrIfEqz(x) => Instruction::BrIfEqz(x), + InstructionInternal::BrIfNez(x) => Instruction::BrIfNez(x), + InstructionInternal::BrTable { count } => { + let start = self.position as usize + 1; + + self.position += count; + + Instruction::BrTable(BrTargets::from_internal( + &self.instructions[start..start + count as usize], + )) + } + InstructionInternal::BrTableTarget(_) => panic!("Executed BrTableTarget"), + + InstructionInternal::Unreachable => Instruction::Unreachable, + InstructionInternal::Return(x) => Instruction::Return(x), + + InstructionInternal::Call(x) => Instruction::Call(x), + InstructionInternal::CallIndirect(x) => Instruction::CallIndirect(x), + + InstructionInternal::Drop => Instruction::Drop, + InstructionInternal::Select => Instruction::Select, + + InstructionInternal::GetGlobal(x) => Instruction::GetGlobal(x), + InstructionInternal::SetGlobal(x) => Instruction::SetGlobal(x), + + InstructionInternal::I32Load(x) => Instruction::I32Load(x), + InstructionInternal::I64Load(x) => Instruction::I64Load(x), + InstructionInternal::F32Load(x) => Instruction::F32Load(x), + InstructionInternal::F64Load(x) => Instruction::F64Load(x), + InstructionInternal::I32Load8S(x) => Instruction::I32Load8S(x), + InstructionInternal::I32Load8U(x) => Instruction::I32Load8U(x), + InstructionInternal::I32Load16S(x) => Instruction::I32Load16S(x), + InstructionInternal::I32Load16U(x) => Instruction::I32Load16U(x), + InstructionInternal::I64Load8S(x) => Instruction::I64Load8S(x), + InstructionInternal::I64Load8U(x) => Instruction::I64Load8U(x), + InstructionInternal::I64Load16S(x) => Instruction::I64Load16S(x), + InstructionInternal::I64Load16U(x) => Instruction::I64Load16U(x), + InstructionInternal::I64Load32S(x) => Instruction::I64Load32S(x), + InstructionInternal::I64Load32U(x) => Instruction::I64Load32U(x), + InstructionInternal::I32Store(x) => Instruction::I32Store(x), + InstructionInternal::I64Store(x) => Instruction::I64Store(x), + InstructionInternal::F32Store(x) => Instruction::F32Store(x), + InstructionInternal::F64Store(x) => Instruction::F64Store(x), + InstructionInternal::I32Store8(x) => Instruction::I32Store8(x), + InstructionInternal::I32Store16(x) => Instruction::I32Store16(x), + InstructionInternal::I64Store8(x) => Instruction::I64Store8(x), + InstructionInternal::I64Store16(x) => Instruction::I64Store16(x), + InstructionInternal::I64Store32(x) => Instruction::I64Store32(x), + + InstructionInternal::CurrentMemory => Instruction::CurrentMemory, + InstructionInternal::GrowMemory => Instruction::GrowMemory, + + InstructionInternal::I32Const(x) => Instruction::I32Const(x), + InstructionInternal::I64Const(x) => Instruction::I64Const(x), + InstructionInternal::F32Const(x) => Instruction::F32Const(x), + InstructionInternal::F64Const(x) => Instruction::F64Const(x), + + InstructionInternal::I32Eqz => Instruction::I32Eqz, + InstructionInternal::I32Eq => Instruction::I32Eq, + InstructionInternal::I32Ne => Instruction::I32Ne, + InstructionInternal::I32LtS => Instruction::I32LtS, + InstructionInternal::I32LtU => Instruction::I32LtU, + InstructionInternal::I32GtS => Instruction::I32GtS, + InstructionInternal::I32GtU => Instruction::I32GtU, + InstructionInternal::I32LeS => Instruction::I32LeS, + InstructionInternal::I32LeU => Instruction::I32LeU, + InstructionInternal::I32GeS => Instruction::I32GeS, + InstructionInternal::I32GeU => Instruction::I32GeU, + + InstructionInternal::I64Eqz => Instruction::I64Eqz, + InstructionInternal::I64Eq => Instruction::I64Eq, + InstructionInternal::I64Ne => Instruction::I64Ne, + InstructionInternal::I64LtS => Instruction::I64LtS, + InstructionInternal::I64LtU => Instruction::I64LtU, + InstructionInternal::I64GtS => Instruction::I64GtS, + InstructionInternal::I64GtU => Instruction::I64GtU, + InstructionInternal::I64LeS => Instruction::I64LeS, + InstructionInternal::I64LeU => Instruction::I64LeU, + InstructionInternal::I64GeS => Instruction::I64GeS, + InstructionInternal::I64GeU => Instruction::I64GeU, + + InstructionInternal::F32Eq => Instruction::F32Eq, + InstructionInternal::F32Ne => Instruction::F32Ne, + InstructionInternal::F32Lt => Instruction::F32Lt, + InstructionInternal::F32Gt => Instruction::F32Gt, + InstructionInternal::F32Le => Instruction::F32Le, + InstructionInternal::F32Ge => Instruction::F32Ge, + + InstructionInternal::F64Eq => Instruction::F64Eq, + InstructionInternal::F64Ne => Instruction::F64Ne, + InstructionInternal::F64Lt => Instruction::F64Lt, + InstructionInternal::F64Gt => Instruction::F64Gt, + InstructionInternal::F64Le => Instruction::F64Le, + InstructionInternal::F64Ge => Instruction::F64Ge, + + InstructionInternal::I32Clz => Instruction::I32Clz, + InstructionInternal::I32Ctz => Instruction::I32Ctz, + InstructionInternal::I32Popcnt => Instruction::I32Popcnt, + InstructionInternal::I32Add => Instruction::I32Add, + InstructionInternal::I32Sub => Instruction::I32Sub, + InstructionInternal::I32Mul => Instruction::I32Mul, + InstructionInternal::I32DivS => Instruction::I32DivS, + InstructionInternal::I32DivU => Instruction::I32DivU, + InstructionInternal::I32RemS => Instruction::I32RemS, + InstructionInternal::I32RemU => Instruction::I32RemU, + InstructionInternal::I32And => Instruction::I32And, + InstructionInternal::I32Or => Instruction::I32Or, + InstructionInternal::I32Xor => Instruction::I32Xor, + InstructionInternal::I32Shl => Instruction::I32Shl, + InstructionInternal::I32ShrS => Instruction::I32ShrS, + InstructionInternal::I32ShrU => Instruction::I32ShrU, + InstructionInternal::I32Rotl => Instruction::I32Rotl, + InstructionInternal::I32Rotr => Instruction::I32Rotr, + + InstructionInternal::I64Clz => Instruction::I64Clz, + InstructionInternal::I64Ctz => Instruction::I64Ctz, + InstructionInternal::I64Popcnt => Instruction::I64Popcnt, + InstructionInternal::I64Add => Instruction::I64Add, + InstructionInternal::I64Sub => Instruction::I64Sub, + InstructionInternal::I64Mul => Instruction::I64Mul, + InstructionInternal::I64DivS => Instruction::I64DivS, + InstructionInternal::I64DivU => Instruction::I64DivU, + InstructionInternal::I64RemS => Instruction::I64RemS, + InstructionInternal::I64RemU => Instruction::I64RemU, + InstructionInternal::I64And => Instruction::I64And, + InstructionInternal::I64Or => Instruction::I64Or, + InstructionInternal::I64Xor => Instruction::I64Xor, + InstructionInternal::I64Shl => Instruction::I64Shl, + InstructionInternal::I64ShrS => Instruction::I64ShrS, + InstructionInternal::I64ShrU => Instruction::I64ShrU, + InstructionInternal::I64Rotl => Instruction::I64Rotl, + InstructionInternal::I64Rotr => Instruction::I64Rotr, + InstructionInternal::F32Abs => Instruction::F32Abs, + InstructionInternal::F32Neg => Instruction::F32Neg, + InstructionInternal::F32Ceil => Instruction::F32Ceil, + InstructionInternal::F32Floor => Instruction::F32Floor, + InstructionInternal::F32Trunc => Instruction::F32Trunc, + InstructionInternal::F32Nearest => Instruction::F32Nearest, + InstructionInternal::F32Sqrt => Instruction::F32Sqrt, + InstructionInternal::F32Add => Instruction::F32Add, + InstructionInternal::F32Sub => Instruction::F32Sub, + InstructionInternal::F32Mul => Instruction::F32Mul, + InstructionInternal::F32Div => Instruction::F32Div, + InstructionInternal::F32Min => Instruction::F32Min, + InstructionInternal::F32Max => Instruction::F32Max, + InstructionInternal::F32Copysign => Instruction::F32Copysign, + InstructionInternal::F64Abs => Instruction::F64Abs, + InstructionInternal::F64Neg => Instruction::F64Neg, + InstructionInternal::F64Ceil => Instruction::F64Ceil, + InstructionInternal::F64Floor => Instruction::F64Floor, + InstructionInternal::F64Trunc => Instruction::F64Trunc, + InstructionInternal::F64Nearest => Instruction::F64Nearest, + InstructionInternal::F64Sqrt => Instruction::F64Sqrt, + InstructionInternal::F64Add => Instruction::F64Add, + InstructionInternal::F64Sub => Instruction::F64Sub, + InstructionInternal::F64Mul => Instruction::F64Mul, + InstructionInternal::F64Div => Instruction::F64Div, + InstructionInternal::F64Min => Instruction::F64Min, + InstructionInternal::F64Max => Instruction::F64Max, + InstructionInternal::F64Copysign => Instruction::F64Copysign, + + InstructionInternal::I32WrapI64 => Instruction::I32WrapI64, + InstructionInternal::I32TruncSF32 => Instruction::I32TruncSF32, + InstructionInternal::I32TruncUF32 => Instruction::I32TruncUF32, + InstructionInternal::I32TruncSF64 => Instruction::I32TruncSF64, + InstructionInternal::I32TruncUF64 => Instruction::I32TruncUF64, + InstructionInternal::I64ExtendSI32 => Instruction::I64ExtendSI32, + InstructionInternal::I64ExtendUI32 => Instruction::I64ExtendUI32, + InstructionInternal::I64TruncSF32 => Instruction::I64TruncSF32, + InstructionInternal::I64TruncUF32 => Instruction::I64TruncUF32, + InstructionInternal::I64TruncSF64 => Instruction::I64TruncSF64, + InstructionInternal::I64TruncUF64 => Instruction::I64TruncUF64, + InstructionInternal::F32ConvertSI32 => Instruction::F32ConvertSI32, + InstructionInternal::F32ConvertUI32 => Instruction::F32ConvertUI32, + InstructionInternal::F32ConvertSI64 => Instruction::F32ConvertSI64, + InstructionInternal::F32ConvertUI64 => Instruction::F32ConvertUI64, + InstructionInternal::F32DemoteF64 => Instruction::F32DemoteF64, + InstructionInternal::F64ConvertSI32 => Instruction::F64ConvertSI32, + InstructionInternal::F64ConvertUI32 => Instruction::F64ConvertUI32, + InstructionInternal::F64ConvertSI64 => Instruction::F64ConvertSI64, + InstructionInternal::F64ConvertUI64 => Instruction::F64ConvertUI64, + InstructionInternal::F64PromoteF32 => Instruction::F64PromoteF32, + + InstructionInternal::I32ReinterpretF32 => Instruction::I32ReinterpretF32, + InstructionInternal::I64ReinterpretF64 => Instruction::I64ReinterpretF64, + InstructionInternal::F32ReinterpretI32 => Instruction::F32ReinterpretI32, + InstructionInternal::F64ReinterpretI64 => Instruction::F64ReinterpretI64, + }; + + self.position += 1; + + Some(out) } } diff --git a/src/runner.rs b/src/runner.rs index 64c464d..fcdd765 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -338,10 +338,15 @@ impl Interpreter { instructions: &isa::Instructions, ) -> Result { let mut iter = instructions.iterate_from(function_context.position); - loop { - let instruction = iter.next().expect("instruction"); - match self.run_instruction(function_context, instruction)? { + loop { + let instruction = iter.next().expect( + "Ran out of instructions, this should be impossible \ + since validation ensures that we either have an explicit \ + return or an implicit block `end`.", + ); + + match self.run_instruction(function_context, &instruction)? { InstructionOutcome::RunNextInstruction => {} InstructionOutcome::Branch(target) => { iter = instructions.iterate_from(target.dst_pc); @@ -370,10 +375,10 @@ impl Interpreter { match instruction { &isa::Instruction::Unreachable => self.run_unreachable(context), - &isa::Instruction::Br(ref target) => self.run_br(context, target.clone()), - &isa::Instruction::BrIfEqz(ref target) => self.run_br_eqz(target.clone()), - &isa::Instruction::BrIfNez(ref target) => self.run_br_nez(target.clone()), - &isa::Instruction::BrTable(ref targets) => self.run_br_table(targets), + &isa::Instruction::Br(target) => self.run_br(context, target.clone()), + &isa::Instruction::BrIfEqz(target) => self.run_br_eqz(target.clone()), + &isa::Instruction::BrIfNez(target) => self.run_br_nez(target.clone()), + &isa::Instruction::BrTable(targets) => self.run_br_table(targets), &isa::Instruction::Return(drop_keep) => self.run_return(drop_keep), &isa::Instruction::Call(index) => self.run_call(context, index), @@ -615,17 +620,11 @@ impl Interpreter { } } - fn run_br_table(&mut self, table: &[isa::Target]) -> Result { + fn run_br_table(&mut self, targets: isa::BrTargets) -> Result { let index: u32 = self.value_stack.pop_as(); - let dst = if (index as usize) < table.len() - 1 { - table[index as usize].clone() - } else { - table - .last() - .expect("Due to validation there should be at least one label") - .clone() - }; + let dst = targets.get(index); + Ok(InstructionOutcome::Branch(dst)) } @@ -1261,8 +1260,8 @@ struct FunctionContext { impl FunctionContext { pub fn new(function: FuncRef) -> Self { - let module = match *function.as_internal() { - FuncInstanceInternal::Internal { ref module, .. } => module.upgrade().expect("module deallocated"), + let module = match function.as_internal() { + FuncInstanceInternal::Internal { module, .. } => module.upgrade().expect("module deallocated"), FuncInstanceInternal::Host { .. } => panic!("Host functions can't be called as internally defined functions; Thus FunctionContext can be created only with internally defined functions; qed"), }; let memory = module.memory_by_index(DEFAULT_MEMORY_INDEX); diff --git a/src/validation/func.rs b/src/validation/func.rs index 02ef454..4f700bd 100644 --- a/src/validation/func.rs +++ b/src/validation/func.rs @@ -1,12 +1,14 @@ #[allow(unused_imports)] use alloc::prelude::*; -use core::u32; -use parity_wasm::elements::{Instruction, BlockType, ValueType, TableElementType, Func, FuncBody}; use common::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX}; +use core::u32; +use parity_wasm::elements::{ + BlockType, Func, FuncBody, Instruction, TableElementType, ValueType, +}; use validation::context::ModuleContext; -use validation::Error; use validation::util::Locals; +use validation::Error; use common::stack::StackWithLimit; use isa; @@ -39,13 +41,9 @@ enum BlockFrameType { /// Usual block frame. /// /// Can be used for an implicit function block. - Block { - end_label: LabelId, - }, + Block { end_label: LabelId }, /// Loop frame (branching to the beginning of block). - Loop { - header: LabelId, - }, + Loop { header: LabelId }, /// True-subblock of if expression. IfTrue { /// If jump happens inside the if-true block then control will @@ -58,9 +56,7 @@ enum BlockFrameType { if_not: LabelId, }, /// False-subblock of if expression. - IfFalse { - end_label: LabelId, - } + IfFalse { end_label: LabelId }, } impl BlockFrameType { @@ -183,9 +179,7 @@ impl FunctionReader { let end_label = context.sink.new_label(); push_label( - BlockFrameType::Block { - end_label, - }, + BlockFrameType::Block { end_label }, result_ty, context.position, &context.value_stack, @@ -198,7 +192,10 @@ impl FunctionReader { Ok(context.into_code()) } - fn read_function_body(context: &mut FunctionValidationContext, body: &[Instruction]) -> Result<(), Error> { + fn read_function_body( + context: &mut FunctionValidationContext, + body: &[Instruction], + ) -> Result<(), Error> { let body_len = body.len(); if body_len == 0 { return Err(Error("Non-empty function body expected".into())); @@ -207,15 +204,19 @@ impl FunctionReader { loop { let instruction = &body[context.position]; - let outcome = FunctionReader::read_instruction(context, instruction) - .map_err(|err| Error(format!("At instruction {:?}(@{}): {}", instruction, context.position, err)))?; + let outcome = + FunctionReader::read_instruction(context, instruction).map_err(|err| { + Error(format!( + "At instruction {:?}(@{}): {}", + instruction, context.position, err + )) + })?; match outcome { Outcome::NextInstruction => (), - Outcome::Unreachable => make_top_frame_polymorphic( - &mut context.value_stack, - &mut context.frame_stack - ), + Outcome::Unreachable => { + make_top_frame_polymorphic(&mut context.value_stack, &mut context.frame_stack) + } } context.position += 1; @@ -225,23 +226,25 @@ impl FunctionReader { } } - fn read_instruction(context: &mut FunctionValidationContext, instruction: &Instruction) -> Result { + fn read_instruction( + context: &mut FunctionValidationContext, + instruction: &Instruction, + ) -> Result { use self::Instruction::*; + match *instruction { // Nop instruction doesn't do anything. It is safe to just skip it. - Nop => {}, + Nop => {} Unreachable => { - context.sink.emit(isa::Instruction::Unreachable); + context.sink.emit(isa::InstructionInternal::Unreachable); return Ok(Outcome::Unreachable); } Block(block_type) => { let end_label = context.sink.new_label(); push_label( - BlockFrameType::Block { - end_label - }, + BlockFrameType::Block { end_label }, block_type, context.position, &context.value_stack, @@ -254,9 +257,7 @@ impl FunctionReader { context.sink.resolve_label(header); push_label( - BlockFrameType::Loop { - header, - }, + BlockFrameType::Loop { header }, block_type, context.position, &context.value_stack, @@ -269,12 +270,13 @@ impl FunctionReader { let if_not = context.sink.new_label(); let end_label = context.sink.new_label(); - pop_value(&mut context.value_stack, &context.frame_stack, ValueType::I32.into())?; + pop_value( + &mut context.value_stack, + &context.frame_stack, + ValueType::I32.into(), + )?; push_label( - BlockFrameType::IfTrue { - if_not, - end_label, - }, + BlockFrameType::IfTrue { if_not, end_label }, block_type, context.position, &context.value_stack, @@ -283,14 +285,15 @@ impl FunctionReader { context.sink.emit_br_eqz(Target { label: if_not, - drop_keep: isa::DropKeep { drop: 0, keep: isa::Keep::None, }, + drop_keep: isa::DropKeep { + drop: 0, + keep: isa::Keep::None, + }, }); } Else => { let (block_type, if_not, end_label) = { - let top_frame = top_label( - &context.frame_stack, - ); + let top_frame = top_label(&context.frame_stack); let (if_not, end_label) = match top_frame.frame_type { BlockFrameType::IfTrue { if_not, end_label } => (if_not, end_label), @@ -303,7 +306,10 @@ impl FunctionReader { // to the "end_label" (it will be resolved at End). context.sink.emit_br(Target { label: end_label, - drop_keep: isa::DropKeep { drop: 0, keep: isa::Keep::None, }, + drop_keep: isa::DropKeep { + drop: 0, + keep: isa::Keep::None, + }, }); // Resolve `if_not` to here so when if condition is unsatisfied control flow @@ -312,14 +318,9 @@ impl FunctionReader { // Then, we pop the current label. It discards all values that pushed in the current // frame. - pop_label( - &mut context.value_stack, - &mut context.frame_stack - )?; + pop_label(&mut context.value_stack, &mut context.frame_stack)?; push_label( - BlockFrameType::IfFalse { - end_label, - }, + BlockFrameType::IfFalse { end_label }, block_type, context.position, &context.value_stack, @@ -335,14 +336,10 @@ impl FunctionReader { if let BlockFrameType::IfTrue { if_not, .. } = frame_type { // A `if` without an `else` can't return a result. if block_type != BlockType::NoResult { - return Err( - Error( - format!( + return Err(Error(format!( "If block without else required to have NoResult block type. But it has {:?} type", block_type - ) - ) - ); + ))); } // Resolve `if_not` label. If the `if's` condition doesn't hold the control will jump @@ -365,7 +362,7 @@ impl FunctionReader { tee_value( &mut context.value_stack, &context.frame_stack, - value_type.into() + value_type.into(), )?; } @@ -375,7 +372,9 @@ impl FunctionReader { &context.value_stack, &context.frame_stack, ); - context.sink.emit(isa::Instruction::Return(drop_keep)); + context + .sink + .emit(isa::InstructionInternal::Return(drop_keep)); } pop_label(&mut context.value_stack, &mut context.frame_stack)?; @@ -388,11 +387,7 @@ impl FunctionReader { Br(depth) => { Validator::validate_br(context, depth)?; - let target = require_target( - depth, - &context.value_stack, - &context.frame_stack, - ); + let target = require_target(depth, &context.value_stack, &context.frame_stack); context.sink.emit_br(target); return Ok(Outcome::Unreachable); @@ -400,11 +395,7 @@ impl FunctionReader { BrIf(depth) => { Validator::validate_br_if(context, depth)?; - let target = require_target( - depth, - &context.value_stack, - &context.frame_stack, - ); + let target = require_target(depth, &context.value_stack, &context.frame_stack); context.sink.emit_br_nez(target); } BrTable(ref table, default) => { @@ -412,719 +403,749 @@ impl FunctionReader { let mut targets = Vec::new(); for depth in table.iter() { - let target = require_target( - *depth, - &context.value_stack, - &context.frame_stack, - ); + let target = require_target(*depth, &context.value_stack, &context.frame_stack); targets.push(target); } - let default_target = require_target( - default, - &context.value_stack, - &context.frame_stack, - ); + let default_target = + require_target(default, &context.value_stack, &context.frame_stack); context.sink.emit_br_table(&targets, default_target); return Ok(Outcome::Unreachable); } Return => { if let BlockType::Value(value_type) = context.return_type()? { - tee_value(&mut context.value_stack, &context.frame_stack, value_type.into())?; + tee_value( + &mut context.value_stack, + &context.frame_stack, + value_type.into(), + )?; } - let drop_keep = drop_keep_return( - &context.locals, - &context.value_stack, - &context.frame_stack, - ); - context.sink.emit(isa::Instruction::Return(drop_keep)); + let drop_keep = + drop_keep_return(&context.locals, &context.value_stack, &context.frame_stack); + context + .sink + .emit(isa::InstructionInternal::Return(drop_keep)); return Ok(Outcome::Unreachable); } Call(index) => { Validator::validate_call(context, index)?; - context.sink.emit(isa::Instruction::Call(index)); + context.sink.emit(isa::InstructionInternal::Call(index)); } CallIndirect(index, _reserved) => { Validator::validate_call_indirect(context, index)?; - context.sink.emit(isa::Instruction::CallIndirect(index)); + context + .sink + .emit(isa::InstructionInternal::CallIndirect(index)); } Drop => { Validator::validate_drop(context)?; - context.sink.emit(isa::Instruction::Drop); + context.sink.emit(isa::InstructionInternal::Drop); } Select => { Validator::validate_select(context)?; - context.sink.emit(isa::Instruction::Select); + context.sink.emit(isa::InstructionInternal::Select); } GetLocal(index) => { // We need to calculate relative depth before validation since // it will change the value stack size. - let depth = relative_local_depth( - index, - &context.locals, - &context.value_stack, - )?; + let depth = relative_local_depth(index, &context.locals, &context.value_stack)?; Validator::validate_get_local(context, index)?; - context.sink.emit( - isa::Instruction::GetLocal(depth), - ); + context.sink.emit(isa::InstructionInternal::GetLocal(depth)); } SetLocal(index) => { Validator::validate_set_local(context, index)?; - let depth = relative_local_depth( - index, - &context.locals, - &context.value_stack, - )?; - context.sink.emit( - isa::Instruction::SetLocal(depth), - ); + let depth = relative_local_depth(index, &context.locals, &context.value_stack)?; + context.sink.emit(isa::InstructionInternal::SetLocal(depth)); } TeeLocal(index) => { Validator::validate_tee_local(context, index)?; - let depth = relative_local_depth( - index, - &context.locals, - &context.value_stack, - )?; - context.sink.emit( - isa::Instruction::TeeLocal(depth), - ); + let depth = relative_local_depth(index, &context.locals, &context.value_stack)?; + context.sink.emit(isa::InstructionInternal::TeeLocal(depth)); } GetGlobal(index) => { Validator::validate_get_global(context, index)?; - context.sink.emit(isa::Instruction::GetGlobal(index)); + context + .sink + .emit(isa::InstructionInternal::GetGlobal(index)); } SetGlobal(index) => { Validator::validate_set_global(context, index)?; - context.sink.emit(isa::Instruction::SetGlobal(index)); + context + .sink + .emit(isa::InstructionInternal::SetGlobal(index)); } I32Load(align, offset) => { Validator::validate_load(context, align, 4, ValueType::I32)?; - context.sink.emit(isa::Instruction::I32Load(offset)); + context.sink.emit(isa::InstructionInternal::I32Load(offset)); } I64Load(align, offset) => { Validator::validate_load(context, align, 8, ValueType::I64)?; - context.sink.emit(isa::Instruction::I64Load(offset)); + context.sink.emit(isa::InstructionInternal::I64Load(offset)); } F32Load(align, offset) => { Validator::validate_load(context, align, 4, ValueType::F32)?; - context.sink.emit(isa::Instruction::F32Load(offset)); + context.sink.emit(isa::InstructionInternal::F32Load(offset)); } F64Load(align, offset) => { Validator::validate_load(context, align, 8, ValueType::F64)?; - context.sink.emit(isa::Instruction::F64Load(offset)); + context.sink.emit(isa::InstructionInternal::F64Load(offset)); } I32Load8S(align, offset) => { Validator::validate_load(context, align, 1, ValueType::I32)?; - context.sink.emit(isa::Instruction::I32Load8S(offset)); + context + .sink + .emit(isa::InstructionInternal::I32Load8S(offset)); } I32Load8U(align, offset) => { Validator::validate_load(context, align, 1, ValueType::I32)?; - context.sink.emit(isa::Instruction::I32Load8U(offset)); + context + .sink + .emit(isa::InstructionInternal::I32Load8U(offset)); } I32Load16S(align, offset) => { Validator::validate_load(context, align, 2, ValueType::I32)?; - context.sink.emit(isa::Instruction::I32Load16S(offset)); + context + .sink + .emit(isa::InstructionInternal::I32Load16S(offset)); } I32Load16U(align, offset) => { Validator::validate_load(context, align, 2, ValueType::I32)?; - context.sink.emit(isa::Instruction::I32Load16U(offset)); + context + .sink + .emit(isa::InstructionInternal::I32Load16U(offset)); } I64Load8S(align, offset) => { Validator::validate_load(context, align, 1, ValueType::I64)?; - context.sink.emit(isa::Instruction::I64Load8S(offset)); + context + .sink + .emit(isa::InstructionInternal::I64Load8S(offset)); } I64Load8U(align, offset) => { Validator::validate_load(context, align, 1, ValueType::I64)?; - context.sink.emit(isa::Instruction::I64Load8U(offset)); + context + .sink + .emit(isa::InstructionInternal::I64Load8U(offset)); } I64Load16S(align, offset) => { Validator::validate_load(context, align, 2, ValueType::I64)?; - context.sink.emit(isa::Instruction::I64Load16S(offset)); + context + .sink + .emit(isa::InstructionInternal::I64Load16S(offset)); } I64Load16U(align, offset) => { Validator::validate_load(context, align, 2, ValueType::I64)?; - context.sink.emit(isa::Instruction::I64Load16U(offset)); + context + .sink + .emit(isa::InstructionInternal::I64Load16U(offset)); } I64Load32S(align, offset) => { Validator::validate_load(context, align, 4, ValueType::I64)?; - context.sink.emit(isa::Instruction::I64Load32S(offset)); + context + .sink + .emit(isa::InstructionInternal::I64Load32S(offset)); } I64Load32U(align, offset) => { Validator::validate_load(context, align, 4, ValueType::I64)?; - context.sink.emit(isa::Instruction::I64Load32U(offset)); + context + .sink + .emit(isa::InstructionInternal::I64Load32U(offset)); } I32Store(align, offset) => { Validator::validate_store(context, align, 4, ValueType::I32)?; - context.sink.emit(isa::Instruction::I32Store(offset)); + context + .sink + .emit(isa::InstructionInternal::I32Store(offset)); } I64Store(align, offset) => { Validator::validate_store(context, align, 8, ValueType::I64)?; - context.sink.emit(isa::Instruction::I64Store(offset)); + context + .sink + .emit(isa::InstructionInternal::I64Store(offset)); } F32Store(align, offset) => { Validator::validate_store(context, align, 4, ValueType::F32)?; - context.sink.emit(isa::Instruction::F32Store(offset)); + context + .sink + .emit(isa::InstructionInternal::F32Store(offset)); } F64Store(align, offset) => { Validator::validate_store(context, align, 8, ValueType::F64)?; - context.sink.emit(isa::Instruction::F64Store(offset)); + context + .sink + .emit(isa::InstructionInternal::F64Store(offset)); } I32Store8(align, offset) => { Validator::validate_store(context, align, 1, ValueType::I32)?; - context.sink.emit(isa::Instruction::I32Store8(offset)); + context + .sink + .emit(isa::InstructionInternal::I32Store8(offset)); } I32Store16(align, offset) => { Validator::validate_store(context, align, 2, ValueType::I32)?; - context.sink.emit(isa::Instruction::I32Store16(offset)); + context + .sink + .emit(isa::InstructionInternal::I32Store16(offset)); } I64Store8(align, offset) => { Validator::validate_store(context, align, 1, ValueType::I64)?; - context.sink.emit(isa::Instruction::I64Store8(offset)); + context + .sink + .emit(isa::InstructionInternal::I64Store8(offset)); } I64Store16(align, offset) => { Validator::validate_store(context, align, 2, ValueType::I64)?; - context.sink.emit(isa::Instruction::I64Store16(offset)); + context + .sink + .emit(isa::InstructionInternal::I64Store16(offset)); } I64Store32(align, offset) => { Validator::validate_store(context, align, 4, ValueType::I64)?; - context.sink.emit(isa::Instruction::I64Store32(offset)); + context + .sink + .emit(isa::InstructionInternal::I64Store32(offset)); } CurrentMemory(_) => { Validator::validate_current_memory(context)?; - context.sink.emit(isa::Instruction::CurrentMemory); + context.sink.emit(isa::InstructionInternal::CurrentMemory); } GrowMemory(_) => { Validator::validate_grow_memory(context)?; - context.sink.emit(isa::Instruction::GrowMemory); + context.sink.emit(isa::InstructionInternal::GrowMemory); } I32Const(v) => { Validator::validate_const(context, ValueType::I32)?; - context.sink.emit(isa::Instruction::I32Const(v)); + context.sink.emit(isa::InstructionInternal::I32Const(v)); } I64Const(v) => { Validator::validate_const(context, ValueType::I64)?; - context.sink.emit(isa::Instruction::I64Const(v)); + context.sink.emit(isa::InstructionInternal::I64Const(v)); } F32Const(v) => { Validator::validate_const(context, ValueType::F32)?; - context.sink.emit(isa::Instruction::F32Const(v)); + context.sink.emit(isa::InstructionInternal::F32Const(v)); } F64Const(v) => { Validator::validate_const(context, ValueType::F64)?; - context.sink.emit(isa::Instruction::F64Const(v)); + context.sink.emit(isa::InstructionInternal::F64Const(v)); } I32Eqz => { Validator::validate_testop(context, ValueType::I32)?; - context.sink.emit(isa::Instruction::I32Eqz); + context.sink.emit(isa::InstructionInternal::I32Eqz); } I32Eq => { Validator::validate_relop(context, ValueType::I32)?; - context.sink.emit(isa::Instruction::I32Eq); + context.sink.emit(isa::InstructionInternal::I32Eq); } I32Ne => { Validator::validate_relop(context, ValueType::I32)?; - context.sink.emit(isa::Instruction::I32Ne); + context.sink.emit(isa::InstructionInternal::I32Ne); } I32LtS => { Validator::validate_relop(context, ValueType::I32)?; - context.sink.emit(isa::Instruction::I32LtS); + context.sink.emit(isa::InstructionInternal::I32LtS); } I32LtU => { Validator::validate_relop(context, ValueType::I32)?; - context.sink.emit(isa::Instruction::I32LtU); + context.sink.emit(isa::InstructionInternal::I32LtU); } I32GtS => { Validator::validate_relop(context, ValueType::I32)?; - context.sink.emit(isa::Instruction::I32GtS); + context.sink.emit(isa::InstructionInternal::I32GtS); } I32GtU => { Validator::validate_relop(context, ValueType::I32)?; - context.sink.emit(isa::Instruction::I32GtU); + context.sink.emit(isa::InstructionInternal::I32GtU); } I32LeS => { Validator::validate_relop(context, ValueType::I32)?; - context.sink.emit(isa::Instruction::I32LeS); + context.sink.emit(isa::InstructionInternal::I32LeS); } I32LeU => { Validator::validate_relop(context, ValueType::I32)?; - context.sink.emit(isa::Instruction::I32LeU); + context.sink.emit(isa::InstructionInternal::I32LeU); } I32GeS => { Validator::validate_relop(context, ValueType::I32)?; - context.sink.emit(isa::Instruction::I32GeS); + context.sink.emit(isa::InstructionInternal::I32GeS); } I32GeU => { Validator::validate_relop(context, ValueType::I32)?; - context.sink.emit(isa::Instruction::I32GeU); + context.sink.emit(isa::InstructionInternal::I32GeU); } I64Eqz => { Validator::validate_testop(context, ValueType::I64)?; - context.sink.emit(isa::Instruction::I64Eqz); + context.sink.emit(isa::InstructionInternal::I64Eqz); } I64Eq => { Validator::validate_relop(context, ValueType::I64)?; - context.sink.emit(isa::Instruction::I64Eq); + context.sink.emit(isa::InstructionInternal::I64Eq); } I64Ne => { Validator::validate_relop(context, ValueType::I64)?; - context.sink.emit(isa::Instruction::I64Ne); + context.sink.emit(isa::InstructionInternal::I64Ne); } I64LtS => { Validator::validate_relop(context, ValueType::I64)?; - context.sink.emit(isa::Instruction::I64LtS); + context.sink.emit(isa::InstructionInternal::I64LtS); } I64LtU => { Validator::validate_relop(context, ValueType::I64)?; - context.sink.emit(isa::Instruction::I64LtU); + context.sink.emit(isa::InstructionInternal::I64LtU); } I64GtS => { Validator::validate_relop(context, ValueType::I64)?; - context.sink.emit(isa::Instruction::I64GtS); + context.sink.emit(isa::InstructionInternal::I64GtS); } I64GtU => { Validator::validate_relop(context, ValueType::I64)?; - context.sink.emit(isa::Instruction::I64GtU); + context.sink.emit(isa::InstructionInternal::I64GtU); } I64LeS => { Validator::validate_relop(context, ValueType::I64)?; - context.sink.emit(isa::Instruction::I64LeS); + context.sink.emit(isa::InstructionInternal::I64LeS); } I64LeU => { Validator::validate_relop(context, ValueType::I64)?; - context.sink.emit(isa::Instruction::I64LeU); + context.sink.emit(isa::InstructionInternal::I64LeU); } I64GeS => { Validator::validate_relop(context, ValueType::I64)?; - context.sink.emit(isa::Instruction::I64GeS); + context.sink.emit(isa::InstructionInternal::I64GeS); } I64GeU => { Validator::validate_relop(context, ValueType::I64)?; - context.sink.emit(isa::Instruction::I64GeU); + context.sink.emit(isa::InstructionInternal::I64GeU); } F32Eq => { Validator::validate_relop(context, ValueType::F32)?; - context.sink.emit(isa::Instruction::F32Eq); + context.sink.emit(isa::InstructionInternal::F32Eq); } F32Ne => { Validator::validate_relop(context, ValueType::F32)?; - context.sink.emit(isa::Instruction::F32Ne); + context.sink.emit(isa::InstructionInternal::F32Ne); } F32Lt => { Validator::validate_relop(context, ValueType::F32)?; - context.sink.emit(isa::Instruction::F32Lt); + context.sink.emit(isa::InstructionInternal::F32Lt); } F32Gt => { Validator::validate_relop(context, ValueType::F32)?; - context.sink.emit(isa::Instruction::F32Gt); + context.sink.emit(isa::InstructionInternal::F32Gt); } F32Le => { Validator::validate_relop(context, ValueType::F32)?; - context.sink.emit(isa::Instruction::F32Le); + context.sink.emit(isa::InstructionInternal::F32Le); } F32Ge => { Validator::validate_relop(context, ValueType::F32)?; - context.sink.emit(isa::Instruction::F32Ge); + context.sink.emit(isa::InstructionInternal::F32Ge); } F64Eq => { Validator::validate_relop(context, ValueType::F64)?; - context.sink.emit(isa::Instruction::F64Eq); + context.sink.emit(isa::InstructionInternal::F64Eq); } F64Ne => { Validator::validate_relop(context, ValueType::F64)?; - context.sink.emit(isa::Instruction::F64Ne); + context.sink.emit(isa::InstructionInternal::F64Ne); } F64Lt => { Validator::validate_relop(context, ValueType::F64)?; - context.sink.emit(isa::Instruction::F64Lt); + context.sink.emit(isa::InstructionInternal::F64Lt); } F64Gt => { Validator::validate_relop(context, ValueType::F64)?; - context.sink.emit(isa::Instruction::F64Gt); + context.sink.emit(isa::InstructionInternal::F64Gt); } F64Le => { Validator::validate_relop(context, ValueType::F64)?; - context.sink.emit(isa::Instruction::F64Le); + context.sink.emit(isa::InstructionInternal::F64Le); } F64Ge => { Validator::validate_relop(context, ValueType::F64)?; - context.sink.emit(isa::Instruction::F64Ge); + context.sink.emit(isa::InstructionInternal::F64Ge); } I32Clz => { Validator::validate_unop(context, ValueType::I32)?; - context.sink.emit(isa::Instruction::I32Clz); + context.sink.emit(isa::InstructionInternal::I32Clz); } I32Ctz => { Validator::validate_unop(context, ValueType::I32)?; - context.sink.emit(isa::Instruction::I32Ctz); + context.sink.emit(isa::InstructionInternal::I32Ctz); } I32Popcnt => { Validator::validate_unop(context, ValueType::I32)?; - context.sink.emit(isa::Instruction::I32Popcnt); + context.sink.emit(isa::InstructionInternal::I32Popcnt); } I32Add => { Validator::validate_binop(context, ValueType::I32)?; - context.sink.emit(isa::Instruction::I32Add); + context.sink.emit(isa::InstructionInternal::I32Add); } I32Sub => { Validator::validate_binop(context, ValueType::I32)?; - context.sink.emit(isa::Instruction::I32Sub); + context.sink.emit(isa::InstructionInternal::I32Sub); } I32Mul => { Validator::validate_binop(context, ValueType::I32)?; - context.sink.emit(isa::Instruction::I32Mul); + context.sink.emit(isa::InstructionInternal::I32Mul); } I32DivS => { Validator::validate_binop(context, ValueType::I32)?; - context.sink.emit(isa::Instruction::I32DivS); + context.sink.emit(isa::InstructionInternal::I32DivS); } I32DivU => { Validator::validate_binop(context, ValueType::I32)?; - context.sink.emit(isa::Instruction::I32DivU); + context.sink.emit(isa::InstructionInternal::I32DivU); } I32RemS => { Validator::validate_binop(context, ValueType::I32)?; - context.sink.emit(isa::Instruction::I32RemS); + context.sink.emit(isa::InstructionInternal::I32RemS); } I32RemU => { Validator::validate_binop(context, ValueType::I32)?; - context.sink.emit(isa::Instruction::I32RemU); + context.sink.emit(isa::InstructionInternal::I32RemU); } I32And => { Validator::validate_binop(context, ValueType::I32)?; - context.sink.emit(isa::Instruction::I32And); + context.sink.emit(isa::InstructionInternal::I32And); } I32Or => { Validator::validate_binop(context, ValueType::I32)?; - context.sink.emit(isa::Instruction::I32Or); + context.sink.emit(isa::InstructionInternal::I32Or); } I32Xor => { Validator::validate_binop(context, ValueType::I32)?; - context.sink.emit(isa::Instruction::I32Xor); + context.sink.emit(isa::InstructionInternal::I32Xor); } I32Shl => { Validator::validate_binop(context, ValueType::I32)?; - context.sink.emit(isa::Instruction::I32Shl); + context.sink.emit(isa::InstructionInternal::I32Shl); } I32ShrS => { Validator::validate_binop(context, ValueType::I32)?; - context.sink.emit(isa::Instruction::I32ShrS); + context.sink.emit(isa::InstructionInternal::I32ShrS); } I32ShrU => { Validator::validate_binop(context, ValueType::I32)?; - context.sink.emit(isa::Instruction::I32ShrU); + context.sink.emit(isa::InstructionInternal::I32ShrU); } I32Rotl => { Validator::validate_binop(context, ValueType::I32)?; - context.sink.emit(isa::Instruction::I32Rotl); + context.sink.emit(isa::InstructionInternal::I32Rotl); } I32Rotr => { Validator::validate_binop(context, ValueType::I32)?; - context.sink.emit(isa::Instruction::I32Rotr); + context.sink.emit(isa::InstructionInternal::I32Rotr); } I64Clz => { Validator::validate_unop(context, ValueType::I64)?; - context.sink.emit(isa::Instruction::I64Clz); + context.sink.emit(isa::InstructionInternal::I64Clz); } I64Ctz => { Validator::validate_unop(context, ValueType::I64)?; - context.sink.emit(isa::Instruction::I64Ctz); + context.sink.emit(isa::InstructionInternal::I64Ctz); } I64Popcnt => { Validator::validate_unop(context, ValueType::I64)?; - context.sink.emit(isa::Instruction::I64Popcnt); + context.sink.emit(isa::InstructionInternal::I64Popcnt); } I64Add => { Validator::validate_binop(context, ValueType::I64)?; - context.sink.emit(isa::Instruction::I64Add); + context.sink.emit(isa::InstructionInternal::I64Add); } I64Sub => { Validator::validate_binop(context, ValueType::I64)?; - context.sink.emit(isa::Instruction::I64Sub); + context.sink.emit(isa::InstructionInternal::I64Sub); } I64Mul => { Validator::validate_binop(context, ValueType::I64)?; - context.sink.emit(isa::Instruction::I64Mul); + context.sink.emit(isa::InstructionInternal::I64Mul); } I64DivS => { Validator::validate_binop(context, ValueType::I64)?; - context.sink.emit(isa::Instruction::I64DivS); + context.sink.emit(isa::InstructionInternal::I64DivS); } I64DivU => { Validator::validate_binop(context, ValueType::I64)?; - context.sink.emit(isa::Instruction::I64DivU); + context.sink.emit(isa::InstructionInternal::I64DivU); } I64RemS => { Validator::validate_binop(context, ValueType::I64)?; - context.sink.emit(isa::Instruction::I64RemS); + context.sink.emit(isa::InstructionInternal::I64RemS); } I64RemU => { Validator::validate_binop(context, ValueType::I64)?; - context.sink.emit(isa::Instruction::I64RemU); + context.sink.emit(isa::InstructionInternal::I64RemU); } I64And => { Validator::validate_binop(context, ValueType::I64)?; - context.sink.emit(isa::Instruction::I64And); + context.sink.emit(isa::InstructionInternal::I64And); } I64Or => { Validator::validate_binop(context, ValueType::I64)?; - context.sink.emit(isa::Instruction::I64Or); + context.sink.emit(isa::InstructionInternal::I64Or); } I64Xor => { Validator::validate_binop(context, ValueType::I64)?; - context.sink.emit(isa::Instruction::I64Xor); + context.sink.emit(isa::InstructionInternal::I64Xor); } I64Shl => { Validator::validate_binop(context, ValueType::I64)?; - context.sink.emit(isa::Instruction::I64Shl); + context.sink.emit(isa::InstructionInternal::I64Shl); } I64ShrS => { Validator::validate_binop(context, ValueType::I64)?; - context.sink.emit(isa::Instruction::I64ShrS); + context.sink.emit(isa::InstructionInternal::I64ShrS); } I64ShrU => { Validator::validate_binop(context, ValueType::I64)?; - context.sink.emit(isa::Instruction::I64ShrU); + context.sink.emit(isa::InstructionInternal::I64ShrU); } I64Rotl => { Validator::validate_binop(context, ValueType::I64)?; - context.sink.emit(isa::Instruction::I64Rotl); + context.sink.emit(isa::InstructionInternal::I64Rotl); } I64Rotr => { Validator::validate_binop(context, ValueType::I64)?; - context.sink.emit(isa::Instruction::I64Rotr); + context.sink.emit(isa::InstructionInternal::I64Rotr); } F32Abs => { Validator::validate_unop(context, ValueType::F32)?; - context.sink.emit(isa::Instruction::F32Abs); + context.sink.emit(isa::InstructionInternal::F32Abs); } F32Neg => { Validator::validate_unop(context, ValueType::F32)?; - context.sink.emit(isa::Instruction::F32Neg); + context.sink.emit(isa::InstructionInternal::F32Neg); } F32Ceil => { Validator::validate_unop(context, ValueType::F32)?; - context.sink.emit(isa::Instruction::F32Ceil); + context.sink.emit(isa::InstructionInternal::F32Ceil); } F32Floor => { Validator::validate_unop(context, ValueType::F32)?; - context.sink.emit(isa::Instruction::F32Floor); + context.sink.emit(isa::InstructionInternal::F32Floor); } F32Trunc => { Validator::validate_unop(context, ValueType::F32)?; - context.sink.emit(isa::Instruction::F32Trunc); + context.sink.emit(isa::InstructionInternal::F32Trunc); } F32Nearest => { Validator::validate_unop(context, ValueType::F32)?; - context.sink.emit(isa::Instruction::F32Nearest); + context.sink.emit(isa::InstructionInternal::F32Nearest); } F32Sqrt => { Validator::validate_unop(context, ValueType::F32)?; - context.sink.emit(isa::Instruction::F32Sqrt); + context.sink.emit(isa::InstructionInternal::F32Sqrt); } F32Add => { Validator::validate_binop(context, ValueType::F32)?; - context.sink.emit(isa::Instruction::F32Add); + context.sink.emit(isa::InstructionInternal::F32Add); } F32Sub => { Validator::validate_binop(context, ValueType::F32)?; - context.sink.emit(isa::Instruction::F32Sub); + context.sink.emit(isa::InstructionInternal::F32Sub); } F32Mul => { Validator::validate_binop(context, ValueType::F32)?; - context.sink.emit(isa::Instruction::F32Mul); + context.sink.emit(isa::InstructionInternal::F32Mul); } F32Div => { Validator::validate_binop(context, ValueType::F32)?; - context.sink.emit(isa::Instruction::F32Div); + context.sink.emit(isa::InstructionInternal::F32Div); } F32Min => { Validator::validate_binop(context, ValueType::F32)?; - context.sink.emit(isa::Instruction::F32Min); + context.sink.emit(isa::InstructionInternal::F32Min); } F32Max => { Validator::validate_binop(context, ValueType::F32)?; - context.sink.emit(isa::Instruction::F32Max); + context.sink.emit(isa::InstructionInternal::F32Max); } F32Copysign => { Validator::validate_binop(context, ValueType::F32)?; - context.sink.emit(isa::Instruction::F32Copysign); + context.sink.emit(isa::InstructionInternal::F32Copysign); } F64Abs => { Validator::validate_unop(context, ValueType::F64)?; - context.sink.emit(isa::Instruction::F64Abs); + context.sink.emit(isa::InstructionInternal::F64Abs); } F64Neg => { Validator::validate_unop(context, ValueType::F64)?; - context.sink.emit(isa::Instruction::F64Neg); + context.sink.emit(isa::InstructionInternal::F64Neg); } F64Ceil => { Validator::validate_unop(context, ValueType::F64)?; - context.sink.emit(isa::Instruction::F64Ceil); + context.sink.emit(isa::InstructionInternal::F64Ceil); } F64Floor => { Validator::validate_unop(context, ValueType::F64)?; - context.sink.emit(isa::Instruction::F64Floor); + context.sink.emit(isa::InstructionInternal::F64Floor); } F64Trunc => { Validator::validate_unop(context, ValueType::F64)?; - context.sink.emit(isa::Instruction::F64Trunc); + context.sink.emit(isa::InstructionInternal::F64Trunc); } F64Nearest => { Validator::validate_unop(context, ValueType::F64)?; - context.sink.emit(isa::Instruction::F64Nearest); + context.sink.emit(isa::InstructionInternal::F64Nearest); } F64Sqrt => { Validator::validate_unop(context, ValueType::F64)?; - context.sink.emit(isa::Instruction::F64Sqrt); + context.sink.emit(isa::InstructionInternal::F64Sqrt); } F64Add => { Validator::validate_binop(context, ValueType::F64)?; - context.sink.emit(isa::Instruction::F64Add); + context.sink.emit(isa::InstructionInternal::F64Add); } F64Sub => { Validator::validate_binop(context, ValueType::F64)?; - context.sink.emit(isa::Instruction::F64Sub); + context.sink.emit(isa::InstructionInternal::F64Sub); } F64Mul => { Validator::validate_binop(context, ValueType::F64)?; - context.sink.emit(isa::Instruction::F64Mul); + context.sink.emit(isa::InstructionInternal::F64Mul); } F64Div => { Validator::validate_binop(context, ValueType::F64)?; - context.sink.emit(isa::Instruction::F64Div); + context.sink.emit(isa::InstructionInternal::F64Div); } F64Min => { Validator::validate_binop(context, ValueType::F64)?; - context.sink.emit(isa::Instruction::F64Min); + context.sink.emit(isa::InstructionInternal::F64Min); } F64Max => { Validator::validate_binop(context, ValueType::F64)?; - context.sink.emit(isa::Instruction::F64Max); + context.sink.emit(isa::InstructionInternal::F64Max); } F64Copysign => { Validator::validate_binop(context, ValueType::F64)?; - context.sink.emit(isa::Instruction::F64Copysign); + context.sink.emit(isa::InstructionInternal::F64Copysign); } I32WrapI64 => { Validator::validate_cvtop(context, ValueType::I64, ValueType::I32)?; - context.sink.emit(isa::Instruction::I32WrapI64); + context.sink.emit(isa::InstructionInternal::I32WrapI64); } I32TruncSF32 => { Validator::validate_cvtop(context, ValueType::F32, ValueType::I32)?; - context.sink.emit(isa::Instruction::I32TruncSF32); + context.sink.emit(isa::InstructionInternal::I32TruncSF32); } I32TruncUF32 => { Validator::validate_cvtop(context, ValueType::F32, ValueType::I32)?; - context.sink.emit(isa::Instruction::I32TruncUF32); + context.sink.emit(isa::InstructionInternal::I32TruncUF32); } I32TruncSF64 => { Validator::validate_cvtop(context, ValueType::F64, ValueType::I32)?; - context.sink.emit(isa::Instruction::I32TruncSF64); + context.sink.emit(isa::InstructionInternal::I32TruncSF64); } I32TruncUF64 => { Validator::validate_cvtop(context, ValueType::F64, ValueType::I32)?; - context.sink.emit(isa::Instruction::I32TruncUF64); + context.sink.emit(isa::InstructionInternal::I32TruncUF64); } I64ExtendSI32 => { Validator::validate_cvtop(context, ValueType::I32, ValueType::I64)?; - context.sink.emit(isa::Instruction::I64ExtendSI32); + context.sink.emit(isa::InstructionInternal::I64ExtendSI32); } I64ExtendUI32 => { Validator::validate_cvtop(context, ValueType::I32, ValueType::I64)?; - context.sink.emit(isa::Instruction::I64ExtendUI32); + context.sink.emit(isa::InstructionInternal::I64ExtendUI32); } I64TruncSF32 => { Validator::validate_cvtop(context, ValueType::F32, ValueType::I64)?; - context.sink.emit(isa::Instruction::I64TruncSF32); + context.sink.emit(isa::InstructionInternal::I64TruncSF32); } I64TruncUF32 => { Validator::validate_cvtop(context, ValueType::F32, ValueType::I64)?; - context.sink.emit(isa::Instruction::I64TruncUF32); + context.sink.emit(isa::InstructionInternal::I64TruncUF32); } I64TruncSF64 => { Validator::validate_cvtop(context, ValueType::F64, ValueType::I64)?; - context.sink.emit(isa::Instruction::I64TruncSF64); + context.sink.emit(isa::InstructionInternal::I64TruncSF64); } I64TruncUF64 => { Validator::validate_cvtop(context, ValueType::F64, ValueType::I64)?; - context.sink.emit(isa::Instruction::I64TruncUF64); + context.sink.emit(isa::InstructionInternal::I64TruncUF64); } F32ConvertSI32 => { Validator::validate_cvtop(context, ValueType::I32, ValueType::F32)?; - context.sink.emit(isa::Instruction::F32ConvertSI32); + context.sink.emit(isa::InstructionInternal::F32ConvertSI32); } F32ConvertUI32 => { Validator::validate_cvtop(context, ValueType::I32, ValueType::F32)?; - context.sink.emit(isa::Instruction::F32ConvertUI32); + context.sink.emit(isa::InstructionInternal::F32ConvertUI32); } F32ConvertSI64 => { Validator::validate_cvtop(context, ValueType::I64, ValueType::F32)?; - context.sink.emit(isa::Instruction::F32ConvertSI64); + context.sink.emit(isa::InstructionInternal::F32ConvertSI64); } F32ConvertUI64 => { Validator::validate_cvtop(context, ValueType::I64, ValueType::F32)?; - context.sink.emit(isa::Instruction::F32ConvertUI64); + context.sink.emit(isa::InstructionInternal::F32ConvertUI64); } F32DemoteF64 => { Validator::validate_cvtop(context, ValueType::F64, ValueType::F32)?; - context.sink.emit(isa::Instruction::F32DemoteF64); + context.sink.emit(isa::InstructionInternal::F32DemoteF64); } F64ConvertSI32 => { Validator::validate_cvtop(context, ValueType::I32, ValueType::F64)?; - context.sink.emit(isa::Instruction::F64ConvertSI32); + context.sink.emit(isa::InstructionInternal::F64ConvertSI32); } F64ConvertUI32 => { Validator::validate_cvtop(context, ValueType::I32, ValueType::F64)?; - context.sink.emit(isa::Instruction::F64ConvertUI32); + context.sink.emit(isa::InstructionInternal::F64ConvertUI32); } F64ConvertSI64 => { Validator::validate_cvtop(context, ValueType::I64, ValueType::F64)?; - context.sink.emit(isa::Instruction::F64ConvertSI64); + context.sink.emit(isa::InstructionInternal::F64ConvertSI64); } F64ConvertUI64 => { Validator::validate_cvtop(context, ValueType::I64, ValueType::F64)?; - context.sink.emit(isa::Instruction::F64ConvertUI64); + context.sink.emit(isa::InstructionInternal::F64ConvertUI64); } F64PromoteF32 => { Validator::validate_cvtop(context, ValueType::F32, ValueType::F64)?; - context.sink.emit(isa::Instruction::F64PromoteF32); + context.sink.emit(isa::InstructionInternal::F64PromoteF32); } I32ReinterpretF32 => { Validator::validate_cvtop(context, ValueType::F32, ValueType::I32)?; - context.sink.emit(isa::Instruction::I32ReinterpretF32); + context + .sink + .emit(isa::InstructionInternal::I32ReinterpretF32); } I64ReinterpretF64 => { Validator::validate_cvtop(context, ValueType::F64, ValueType::I64)?; - context.sink.emit(isa::Instruction::I64ReinterpretF64); + context + .sink + .emit(isa::InstructionInternal::I64ReinterpretF64); } F32ReinterpretI32 => { Validator::validate_cvtop(context, ValueType::I32, ValueType::F32)?; - context.sink.emit(isa::Instruction::F32ReinterpretI32); + context + .sink + .emit(isa::InstructionInternal::F32ReinterpretI32); } F64ReinterpretI64 => { Validator::validate_cvtop(context, ValueType::I64, ValueType::F64)?; - context.sink.emit(isa::Instruction::F64ReinterpretI64); + context + .sink + .emit(isa::InstructionInternal::F64ReinterpretI64); } } @@ -1136,78 +1157,160 @@ impl FunctionReader { 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())?; Ok(()) } - fn validate_unop(context: &mut FunctionValidationContext, value_type: ValueType) -> Result<(), Error> { - pop_value(&mut context.value_stack, &context.frame_stack, value_type.into())?; + fn validate_unop( + context: &mut FunctionValidationContext, + value_type: ValueType, + ) -> Result<(), Error> { + pop_value( + &mut context.value_stack, + &context.frame_stack, + value_type.into(), + )?; push_value(&mut context.value_stack, value_type.into())?; Ok(()) } - fn validate_binop(context: &mut FunctionValidationContext, value_type: ValueType) -> Result<(), Error> { - pop_value(&mut context.value_stack, &context.frame_stack, value_type.into())?; - pop_value(&mut context.value_stack, &context.frame_stack, value_type.into())?; + fn validate_binop( + context: &mut FunctionValidationContext, + value_type: ValueType, + ) -> Result<(), Error> { + pop_value( + &mut context.value_stack, + &context.frame_stack, + value_type.into(), + )?; + pop_value( + &mut context.value_stack, + &context.frame_stack, + value_type.into(), + )?; push_value(&mut context.value_stack, value_type.into())?; Ok(()) } - fn validate_testop(context: &mut FunctionValidationContext, value_type: ValueType) -> Result<(), Error> { - pop_value(&mut context.value_stack, &context.frame_stack, value_type.into())?; + fn validate_testop( + context: &mut FunctionValidationContext, + value_type: ValueType, + ) -> Result<(), Error> { + pop_value( + &mut context.value_stack, + &context.frame_stack, + value_type.into(), + )?; push_value(&mut context.value_stack, ValueType::I32.into())?; Ok(()) } - fn validate_relop(context: &mut FunctionValidationContext, value_type: ValueType) -> Result<(), Error> { - pop_value(&mut context.value_stack, &context.frame_stack, value_type.into())?; - pop_value(&mut context.value_stack, &context.frame_stack, value_type.into())?; + fn validate_relop( + context: &mut FunctionValidationContext, + value_type: ValueType, + ) -> Result<(), Error> { + pop_value( + &mut context.value_stack, + &context.frame_stack, + value_type.into(), + )?; + pop_value( + &mut context.value_stack, + &context.frame_stack, + value_type.into(), + )?; push_value(&mut context.value_stack, ValueType::I32.into())?; Ok(()) } - fn validate_cvtop(context: &mut FunctionValidationContext, value_type1: ValueType, value_type2: ValueType) -> Result<(), Error> { - pop_value(&mut context.value_stack, &context.frame_stack, value_type1.into())?; + fn validate_cvtop( + context: &mut FunctionValidationContext, + value_type1: ValueType, + value_type2: ValueType, + ) -> Result<(), Error> { + pop_value( + &mut context.value_stack, + &context.frame_stack, + value_type1.into(), + )?; push_value(&mut context.value_stack, value_type2.into())?; Ok(()) } fn validate_drop(context: &mut FunctionValidationContext) -> Result<(), Error> { - pop_value(&mut context.value_stack, &context.frame_stack, StackValueType::Any)?; + pop_value( + &mut context.value_stack, + &context.frame_stack, + StackValueType::Any, + )?; Ok(()) } fn validate_select(context: &mut FunctionValidationContext) -> Result<(), Error> { - pop_value(&mut context.value_stack, &context.frame_stack, ValueType::I32.into())?; - let select_type = pop_value(&mut context.value_stack, &context.frame_stack, StackValueType::Any)?; + pop_value( + &mut context.value_stack, + &context.frame_stack, + ValueType::I32.into(), + )?; + let select_type = pop_value( + &mut context.value_stack, + &context.frame_stack, + StackValueType::Any, + )?; pop_value(&mut context.value_stack, &context.frame_stack, select_type)?; push_value(&mut context.value_stack, select_type)?; Ok(()) } - fn validate_get_local(context: &mut FunctionValidationContext, index: u32) -> Result<(), Error> { + fn validate_get_local( + context: &mut FunctionValidationContext, + index: u32, + ) -> Result<(), Error> { let local_type = require_local(&context.locals, index)?; push_value(&mut context.value_stack, local_type.into())?; Ok(()) } - fn validate_set_local(context: &mut FunctionValidationContext, index: u32) -> Result<(), Error> { + fn validate_set_local( + context: &mut FunctionValidationContext, + index: u32, + ) -> Result<(), Error> { let local_type = require_local(&context.locals, index)?; - let value_type = pop_value(&mut context.value_stack, &context.frame_stack, StackValueType::Any)?; - if StackValueType::from(local_type) != value_type { - return Err(Error(format!("Trying to update local {} of type {:?} with value of type {:?}", index, local_type, value_type))); + let value_type = pop_value( + &mut context.value_stack, + &context.frame_stack, + StackValueType::Any, + )?; + if StackValueType::from(local_type) != value_type { + return Err(Error(format!( + "Trying to update local {} of type {:?} with value of type {:?}", + index, local_type, value_type + ))); } Ok(()) } - fn validate_tee_local(context: &mut FunctionValidationContext, index: u32) -> Result<(), Error> { + fn validate_tee_local( + context: &mut FunctionValidationContext, + index: u32, + ) -> Result<(), Error> { let local_type = require_local(&context.locals, index)?; - tee_value(&mut context.value_stack, &context.frame_stack, local_type.into())?; + tee_value( + &mut context.value_stack, + &context.frame_stack, + local_type.into(), + )?; Ok(()) } - fn validate_get_global(context: &mut FunctionValidationContext, index: u32) -> Result<(), Error> { + fn validate_get_global( + context: &mut FunctionValidationContext, + index: u32, + ) -> Result<(), Error> { let global_type: StackValueType = { let global = context.module.require_global(index, None)?; global.content_type().into() @@ -1216,37 +1319,75 @@ impl Validator { Ok(()) } - fn validate_set_global(context: &mut FunctionValidationContext, index: u32) -> Result<(), Error> { + fn validate_set_global( + context: &mut FunctionValidationContext, + index: u32, + ) -> Result<(), Error> { let global_type: StackValueType = { let global = context.module.require_global(index, Some(true))?; global.content_type().into() }; - let value_type = pop_value(&mut context.value_stack, &context.frame_stack, StackValueType::Any)?; + let value_type = pop_value( + &mut context.value_stack, + &context.frame_stack, + StackValueType::Any, + )?; if global_type != value_type { - return Err(Error(format!("Trying to update global {} of type {:?} with value of type {:?}", index, global_type, value_type))); + return Err(Error(format!( + "Trying to update global {} of type {:?} with value of type {:?}", + index, global_type, value_type + ))); } Ok(()) } - fn validate_load(context: &mut FunctionValidationContext, align: u32, max_align: u32, value_type: ValueType) -> Result<(), Error> { + fn validate_load( + context: &mut FunctionValidationContext, + align: u32, + max_align: u32, + value_type: ValueType, + ) -> Result<(), Error> { if 1u32.checked_shl(align).unwrap_or(u32::MAX) > max_align { - return Err(Error(format!("Too large memory alignment 2^{} (expected at most {})", align, max_align))); + return Err(Error(format!( + "Too large memory alignment 2^{} (expected at most {})", + align, max_align + ))); } - pop_value(&mut context.value_stack, &context.frame_stack, ValueType::I32.into())?; + pop_value( + &mut context.value_stack, + &context.frame_stack, + ValueType::I32.into(), + )?; context.module.require_memory(DEFAULT_MEMORY_INDEX)?; push_value(&mut context.value_stack, value_type.into())?; Ok(()) } - fn validate_store(context: &mut FunctionValidationContext, align: u32, max_align: u32, value_type: ValueType) -> Result<(), Error> { + fn validate_store( + context: &mut FunctionValidationContext, + align: u32, + max_align: u32, + value_type: ValueType, + ) -> Result<(), Error> { if 1u32.checked_shl(align).unwrap_or(u32::MAX) > max_align { - return Err(Error(format!("Too large memory alignment 2^{} (expected at most {})", align, max_align))); + return Err(Error(format!( + "Too large memory alignment 2^{} (expected at most {})", + align, max_align + ))); } context.module.require_memory(DEFAULT_MEMORY_INDEX)?; - pop_value(&mut context.value_stack, &context.frame_stack, value_type.into())?; - pop_value(&mut context.value_stack, &context.frame_stack, ValueType::I32.into())?; + pop_value( + &mut context.value_stack, + &context.frame_stack, + value_type.into(), + )?; + pop_value( + &mut context.value_stack, + &context.frame_stack, + ValueType::I32.into(), + )?; Ok(()) } @@ -1257,14 +1398,22 @@ impl Validator { }; if !frame_type.is_loop() { if let BlockType::Value(value_type) = frame_block_type { - tee_value(&mut context.value_stack, &context.frame_stack, value_type.into())?; + tee_value( + &mut context.value_stack, + &context.frame_stack, + value_type.into(), + )?; } } Ok(()) } fn validate_br_if(context: &mut FunctionValidationContext, depth: u32) -> Result<(), Error> { - pop_value(&mut context.value_stack, &context.frame_stack, ValueType::I32.into())?; + pop_value( + &mut context.value_stack, + &context.frame_stack, + ValueType::I32.into(), + )?; let (frame_type, frame_block_type) = { let frame = require_label(depth, &context.frame_stack)?; @@ -1272,13 +1421,21 @@ impl Validator { }; if !frame_type.is_loop() { if let BlockType::Value(value_type) = frame_block_type { - tee_value(&mut context.value_stack, &context.frame_stack, value_type.into())?; + tee_value( + &mut context.value_stack, + &context.frame_stack, + value_type.into(), + )?; } } Ok(()) } - fn validate_br_table(context: &mut FunctionValidationContext, table: &[u32], default: u32) -> Result<(), Error> { + fn validate_br_table( + context: &mut FunctionValidationContext, + table: &[u32], + default: u32, + ) -> Result<(), Error> { let required_block_type: BlockType = { let default_block = require_label(default, &context.frame_stack)?; let required_block_type = if !default_block.frame_type.is_loop() { @@ -1295,23 +1452,26 @@ impl Validator { BlockType::NoResult }; if required_block_type != label_block_type { - return Err( - Error( - format!( - "Labels in br_table points to block of different types: {:?} and {:?}", - required_block_type, - label_block.block_type - ) - ) - ); + return Err(Error(format!( + "Labels in br_table points to block of different types: {:?} and {:?}", + required_block_type, label_block.block_type + ))); } } required_block_type }; - pop_value(&mut context.value_stack, &context.frame_stack, ValueType::I32.into())?; + pop_value( + &mut context.value_stack, + &context.frame_stack, + ValueType::I32.into(), + )?; if let BlockType::Value(value_type) = required_block_type { - tee_value(&mut context.value_stack, &context.frame_stack, value_type.into())?; + tee_value( + &mut context.value_stack, + &context.frame_stack, + value_type.into(), + )?; } Ok(()) @@ -1320,7 +1480,11 @@ impl Validator { fn validate_call(context: &mut FunctionValidationContext, idx: u32) -> Result<(), Error> { let (argument_types, return_type) = context.module.require_function(idx)?; for argument_type in argument_types.iter().rev() { - pop_value(&mut context.value_stack, &context.frame_stack, (*argument_type).into())?; + pop_value( + &mut context.value_stack, + &context.frame_stack, + (*argument_type).into(), + )?; } if let BlockType::Value(value_type) = return_type { push_value(&mut context.value_stack, value_type.into())?; @@ -1328,7 +1492,10 @@ impl Validator { Ok(()) } - fn validate_call_indirect(context: &mut FunctionValidationContext, idx: u32) -> Result<(), Error> { + fn validate_call_indirect( + context: &mut FunctionValidationContext, + idx: u32, + ) -> Result<(), Error> { { let table = context.module.require_table(DEFAULT_TABLE_INDEX)?; if table.elem_type() != TableElementType::AnyFunc { @@ -1340,10 +1507,18 @@ impl Validator { } } - pop_value(&mut context.value_stack, &context.frame_stack, ValueType::I32.into())?; + pop_value( + &mut context.value_stack, + &context.frame_stack, + ValueType::I32.into(), + )?; let (argument_types, return_type) = context.module.require_function_type(idx)?; for argument_type in argument_types.iter().rev() { - pop_value(&mut context.value_stack, &context.frame_stack, (*argument_type).into())?; + pop_value( + &mut context.value_stack, + &context.frame_stack, + (*argument_type).into(), + )?; } if let BlockType::Value(value_type) = return_type { push_value(&mut context.value_stack, value_type.into())?; @@ -1359,7 +1534,11 @@ impl Validator { fn validate_grow_memory(context: &mut FunctionValidationContext) -> Result<(), Error> { context.module.require_memory(DEFAULT_MEMORY_INDEX)?; - pop_value(&mut context.value_stack, &context.frame_stack, ValueType::I32.into())?; + pop_value( + &mut context.value_stack, + &context.frame_stack, + ValueType::I32.into(), + )?; push_value(&mut context.value_stack, ValueType::I32.into())?; Ok(()) } @@ -1416,7 +1595,9 @@ fn make_top_frame_polymorphic( value_stack: &mut StackWithLimit, frame_stack: &mut StackWithLimit, ) { - let frame = frame_stack.top_mut().expect("make_top_frame_polymorphic is called with empty frame stack"); + let frame = frame_stack + .top_mut() + .expect("make_top_frame_polymorphic is called with empty frame stack"); value_stack.resize(frame.value_stack_len, StackValueType::Any); frame.polymorphic_stack = true; } @@ -1501,7 +1682,11 @@ fn pop_label( match block_type { BlockType::NoResult => (), BlockType::Value(required_value_type) => { - let _ = pop_value(value_stack, frame_stack, StackValueType::Specific(required_value_type))?; + let _ = pop_value( + value_stack, + frame_stack, + StackValueType::Specific(required_value_type), + )?; } } @@ -1518,7 +1703,8 @@ fn pop_label( } fn top_label(frame_stack: &StackWithLimit) -> &BlockFrame { - frame_stack.top() + frame_stack + .top() .expect("this function can't be called with empty frame stack") } @@ -1534,8 +1720,7 @@ fn require_target( value_stack: &StackWithLimit, frame_stack: &StackWithLimit, ) -> Target { - let is_stack_polymorphic = top_label(frame_stack) - .polymorphic_stack; + let is_stack_polymorphic = top_label(frame_stack).polymorphic_stack; let frame = require_label(depth, frame_stack).expect("require_target called with a bogus depth"); @@ -1604,7 +1789,7 @@ fn require_local(locals: &Locals, idx: u32) -> Result { fn relative_local_depth( idx: u32, locals: &Locals, - value_stack: &StackWithLimit + value_stack: &StackWithLimit, ) -> Result { let value_stack_height = value_stack.len() as u32; let locals_and_params_count = locals.count(); @@ -1612,9 +1797,7 @@ fn relative_local_depth( let depth = value_stack_height .checked_add(locals_and_params_count) .and_then(|x| x.checked_sub(idx)) - .ok_or_else(|| - Error(String::from("Locals range not in 32-bit range")) - )?; + .ok_or_else(|| Error(String::from("Locals range not in 32-bit range")))?; Ok(depth) } @@ -1655,85 +1838,81 @@ impl Sink { self.ins.current_pc() } - fn pc_or_placeholder isa::Reloc>(&mut self, label: LabelId, reloc_creator: F) -> u32 { + fn pc_or_placeholder isa::Reloc>( + &mut self, + label: LabelId, + reloc_creator: F, + ) -> u32 { match self.labels[label.0] { (Label::Resolved(dst_pc), _) => dst_pc, (Label::NotResolved, ref mut unresolved) => { - unresolved - .push(reloc_creator()); + unresolved.push(reloc_creator()); u32::max_value() } } } - fn emit(&mut self, instruction: isa::Instruction) { + fn emit(&mut self, instruction: isa::InstructionInternal) { self.ins.push(instruction); } fn emit_br(&mut self, target: Target) { - let Target { - label, - drop_keep, - } = target; + let Target { label, drop_keep } = target; let pc = self.cur_pc(); let dst_pc = self.pc_or_placeholder(label, || isa::Reloc::Br { pc }); - self.ins.push(isa::Instruction::Br(isa::Target { + self.ins.push(isa::InstructionInternal::Br(isa::Target { dst_pc, drop_keep: drop_keep.into(), })); } fn emit_br_eqz(&mut self, target: Target) { - let Target { - label, - drop_keep, - } = target; + let Target { label, drop_keep } = target; let pc = self.cur_pc(); let dst_pc = self.pc_or_placeholder(label, || isa::Reloc::Br { pc }); - self.ins.push(isa::Instruction::BrIfEqz(isa::Target { - dst_pc, - drop_keep: drop_keep.into(), - })); + self.ins + .push(isa::InstructionInternal::BrIfEqz(isa::Target { + dst_pc, + drop_keep: drop_keep.into(), + })); } fn emit_br_nez(&mut self, target: Target) { - let Target { - label, - drop_keep, - } = target; + let Target { label, drop_keep } = target; let pc = self.cur_pc(); let dst_pc = self.pc_or_placeholder(label, || isa::Reloc::Br { pc }); - self.ins.push(isa::Instruction::BrIfNez(isa::Target { - dst_pc, - drop_keep: drop_keep.into(), - })); + self.ins + .push(isa::InstructionInternal::BrIfNez(isa::Target { + dst_pc, + drop_keep: drop_keep.into(), + })); } fn emit_br_table(&mut self, targets: &[Target], default: Target) { use core::iter; let pc = self.cur_pc(); - let mut isa_targets = Vec::new(); - for (idx, &Target { label, drop_keep }) in targets.iter().chain(iter::once(&default)).enumerate() { + + self.ins.push(isa::InstructionInternal::BrTable { + count: targets.len() as u32 + 1, + }); + + for (idx, &Target { label, drop_keep }) in + targets.iter().chain(iter::once(&default)).enumerate() + { let dst_pc = self.pc_or_placeholder(label, || isa::Reloc::BrTable { pc, idx }); - isa_targets.push( - isa::Target { + self.ins + .push(isa::InstructionInternal::BrTableTarget(isa::Target { dst_pc, drop_keep: drop_keep.into(), - }, - ); + })); } - self.ins.push(isa::Instruction::BrTable( - isa_targets.into_boxed_slice(), - )); } /// Create a new unresolved label. fn new_label(&mut self) -> LabelId { let label_idx = self.labels.len(); - self.labels.push( - (Label::NotResolved, Vec::new()), - ); + self.labels.push((Label::NotResolved, Vec::new())); LabelId(label_idx) } @@ -1762,14 +1941,19 @@ impl Sink { /// Consume this Sink and returns isa::Instructions. fn into_inner(self) -> isa::Instructions { // At this moment all labels should be resolved. - assert!({ - self.labels.iter().all(|(state, unresolved)| - match (state, unresolved) { - (Label::Resolved(_), unresolved) if unresolved.is_empty() => true, - _ => false, - } - ) - }, "there are unresolved labels left: {:?}", self.labels); + assert!( + { + self.labels + .iter() + .all(|(state, unresolved)| match (state, unresolved) { + (Label::Resolved(_), unresolved) if unresolved.is_empty() => true, + _ => false, + }) + }, + "there are unresolved labels left: {:?}", + self.labels + ); self.ins } } + diff --git a/src/validation/tests.rs b/src/validation/tests.rs index 9a8829e..fad0615 100644 --- a/src/validation/tests.rs +++ b/src/validation/tests.rs @@ -1,11 +1,10 @@ use super::{validate_module, ValidatedModule}; +use isa; use parity_wasm::builder::module; use parity_wasm::elements::{ - External, GlobalEntry, GlobalType, ImportEntry, InitExpr, MemoryType, - Instruction, Instructions, TableType, ValueType, BlockType, deserialize_buffer, - Module, + deserialize_buffer, BlockType, External, GlobalEntry, GlobalType, ImportEntry, InitExpr, + Instruction, Instructions, MemoryType, Module, TableType, ValueType, }; -use isa; use wabt; #[test] @@ -27,45 +26,34 @@ fn limits() { for (min, max, is_valid) in test_cases { // defined table - let m = module() - .table() - .with_min(min) - .with_max(max) - .build() - .build(); + let m = module().table().with_min(min).with_max(max).build().build(); assert_eq!(validate_module(m).is_ok(), is_valid); // imported table let m = module() - .with_import( - ImportEntry::new( - "core".into(), - "table".into(), - External::Table(TableType::new(min, max)) - ) - ) - .build(); + .with_import(ImportEntry::new( + "core".into(), + "table".into(), + External::Table(TableType::new(min, max)), + )).build(); assert_eq!(validate_module(m).is_ok(), is_valid); // defined memory let m = module() .memory() - .with_min(min) - .with_max(max) - .build() + .with_min(min) + .with_max(max) + .build() .build(); assert_eq!(validate_module(m).is_ok(), is_valid); // imported table let m = module() - .with_import( - ImportEntry::new( - "core".into(), - "memory".into(), - External::Memory(MemoryType::new(min, max)) - ) - ) - .build(); + .with_import(ImportEntry::new( + "core".into(), + "memory".into(), + External::Memory(MemoryType::new(min, max)), + )).build(); assert_eq!(validate_module(m).is_ok(), is_valid); } } @@ -73,92 +61,63 @@ fn limits() { #[test] fn global_init_const() { let m = module() - .with_global( - GlobalEntry::new( - GlobalType::new(ValueType::I32, true), - InitExpr::new( - vec![Instruction::I32Const(42), Instruction::End] - ) - ) - ) - .build(); + .with_global(GlobalEntry::new( + GlobalType::new(ValueType::I32, true), + InitExpr::new(vec![Instruction::I32Const(42), Instruction::End]), + )).build(); assert!(validate_module(m).is_ok()); // init expr type differs from declared global type let m = module() - .with_global( - GlobalEntry::new( - GlobalType::new(ValueType::I64, true), - InitExpr::new(vec![Instruction::I32Const(42), Instruction::End]) - ) - ) - .build(); + .with_global(GlobalEntry::new( + GlobalType::new(ValueType::I64, true), + InitExpr::new(vec![Instruction::I32Const(42), Instruction::End]), + )).build(); assert!(validate_module(m).is_err()); } #[test] fn global_init_global() { let m = module() - .with_import( - ImportEntry::new( - "env".into(), - "ext_global".into(), - External::Global(GlobalType::new(ValueType::I32, false)) - ) - ) - .with_global( - GlobalEntry::new( - GlobalType::new(ValueType::I32, true), - InitExpr::new(vec![Instruction::GetGlobal(0), Instruction::End]) - ) - ) - .build(); + .with_import(ImportEntry::new( + "env".into(), + "ext_global".into(), + External::Global(GlobalType::new(ValueType::I32, false)), + )).with_global(GlobalEntry::new( + GlobalType::new(ValueType::I32, true), + InitExpr::new(vec![Instruction::GetGlobal(0), Instruction::End]), + )).build(); assert!(validate_module(m).is_ok()); // get_global can reference only previously defined globals let m = module() - .with_global( - GlobalEntry::new( - GlobalType::new(ValueType::I32, true), - InitExpr::new(vec![Instruction::GetGlobal(0), Instruction::End]) - ) - ) - .build(); + .with_global(GlobalEntry::new( + GlobalType::new(ValueType::I32, true), + InitExpr::new(vec![Instruction::GetGlobal(0), Instruction::End]), + )).build(); assert!(validate_module(m).is_err()); // get_global can reference only const globals let m = module() - .with_import( - ImportEntry::new( - "env".into(), - "ext_global".into(), - External::Global(GlobalType::new(ValueType::I32, true)) - ) - ) - .with_global( - GlobalEntry::new( - GlobalType::new(ValueType::I32, true), - InitExpr::new(vec![Instruction::GetGlobal(0), Instruction::End]) - ) - ) - .build(); + .with_import(ImportEntry::new( + "env".into(), + "ext_global".into(), + External::Global(GlobalType::new(ValueType::I32, true)), + )).with_global(GlobalEntry::new( + GlobalType::new(ValueType::I32, true), + InitExpr::new(vec![Instruction::GetGlobal(0), Instruction::End]), + )).build(); assert!(validate_module(m).is_err()); // get_global in init_expr can only refer to imported globals. let m = module() - .with_global( - GlobalEntry::new( - GlobalType::new(ValueType::I32, false), - InitExpr::new(vec![Instruction::I32Const(0), Instruction::End]) - ) - ) - .with_global( - GlobalEntry::new( - GlobalType::new(ValueType::I32, true), - InitExpr::new(vec![Instruction::GetGlobal(0), Instruction::End]) - ) - ) - .build(); + .with_global(GlobalEntry::new( + GlobalType::new(ValueType::I32, false), + InitExpr::new(vec![Instruction::I32Const(0), Instruction::End]), + )).with_global(GlobalEntry::new( + GlobalType::new(ValueType::I32, true), + InitExpr::new(vec![Instruction::GetGlobal(0), Instruction::End]), + )).build(); assert!(validate_module(m).is_err()); } @@ -166,35 +125,26 @@ fn global_init_global() { fn global_init_misc() { // without delimiting End opcode let m = module() - .with_global( - GlobalEntry::new( - GlobalType::new(ValueType::I32, true), - InitExpr::new(vec![Instruction::I32Const(42)]) - ) - ) - .build(); + .with_global(GlobalEntry::new( + GlobalType::new(ValueType::I32, true), + InitExpr::new(vec![Instruction::I32Const(42)]), + )).build(); assert!(validate_module(m).is_err()); // empty init expr let m = module() - .with_global( - GlobalEntry::new( - GlobalType::new(ValueType::I32, true), - InitExpr::new(vec![Instruction::End]) - ) - ) - .build(); + .with_global(GlobalEntry::new( + GlobalType::new(ValueType::I32, true), + InitExpr::new(vec![Instruction::End]), + )).build(); assert!(validate_module(m).is_err()); // not an constant opcode used let m = module() - .with_global( - GlobalEntry::new( - GlobalType::new(ValueType::I32, true), - InitExpr::new(vec![Instruction::Unreachable, Instruction::End]) - ) - ) - .build(); + .with_global(GlobalEntry::new( + GlobalType::new(ValueType::I32, true), + InitExpr::new(vec![Instruction::Unreachable, Instruction::End]), + )).build(); assert!(validate_module(m).is_err()); } @@ -202,31 +152,25 @@ fn global_init_misc() { fn module_limits_validity() { // module cannot contain more than 1 memory atm. let m = module() - .with_import( - ImportEntry::new( - "core".into(), - "memory".into(), - External::Memory(MemoryType::new(10, None)) - ) - ) - .memory() - .with_min(10) - .build() + .with_import(ImportEntry::new( + "core".into(), + "memory".into(), + External::Memory(MemoryType::new(10, None)), + )).memory() + .with_min(10) + .build() .build(); assert!(validate_module(m).is_err()); // module cannot contain more than 1 table atm. let m = module() - .with_import( - ImportEntry::new( - "core".into(), - "table".into(), - External::Table(TableType::new(10, None)) - ) - ) - .table() - .with_min(10) - .build() + .with_import(ImportEntry::new( + "core".into(), + "table".into(), + External::Table(TableType::new(10, None)), + )).table() + .with_min(10) + .build() .build(); assert!(validate_module(m).is_err()); } @@ -236,19 +180,27 @@ fn funcs() { // recursive function calls is legal. let m = module() .function() - .signature().return_type().i32().build() - .body().with_instructions(Instructions::new(vec![ - Instruction::Call(1), - Instruction::End, - ])).build() - .build() + .signature() + .return_type() + .i32() + .build() + .body() + .with_instructions(Instructions::new(vec![ + Instruction::Call(1), + Instruction::End, + ])).build() + .build() .function() - .signature().return_type().i32().build() - .body().with_instructions(Instructions::new(vec![ - Instruction::Call(0), - Instruction::End, - ])).build() - .build() + .signature() + .return_type() + .i32() + .build() + .body() + .with_instructions(Instructions::new(vec![ + Instruction::Call(0), + Instruction::End, + ])).build() + .build() .build(); assert!(validate_module(m).is_ok()); } @@ -257,26 +209,20 @@ fn funcs() { fn globals() { // import immutable global is legal. let m = module() - .with_import( - ImportEntry::new( - "env".into(), - "ext_global".into(), - External::Global(GlobalType::new(ValueType::I32, false)) - ) - ) - .build(); + .with_import(ImportEntry::new( + "env".into(), + "ext_global".into(), + External::Global(GlobalType::new(ValueType::I32, false)), + )).build(); assert!(validate_module(m).is_ok()); // import mutable global is invalid. let m = module() - .with_import( - ImportEntry::new( - "env".into(), - "ext_global".into(), - External::Global(GlobalType::new(ValueType::I32, true)) - ) - ) - .build(); + .with_import(ImportEntry::new( + "env".into(), + "ext_global".into(), + External::Global(GlobalType::new(ValueType::I32, true)), + )).build(); assert!(validate_module(m).is_err()); } @@ -284,21 +230,23 @@ fn globals() { fn if_else_with_return_type_validation() { let m = module() .function() - .signature().build() - .body().with_instructions(Instructions::new(vec![ - Instruction::I32Const(1), - Instruction::If(BlockType::NoResult), - Instruction::I32Const(1), - Instruction::If(BlockType::Value(ValueType::I32)), - Instruction::I32Const(1), - Instruction::Else, - Instruction::I32Const(2), - Instruction::End, - Instruction::Drop, - Instruction::End, - Instruction::End, - ])).build() - .build() + .signature() + .build() + .body() + .with_instructions(Instructions::new(vec![ + Instruction::I32Const(1), + Instruction::If(BlockType::NoResult), + Instruction::I32Const(1), + Instruction::If(BlockType::Value(ValueType::I32)), + Instruction::I32Const(1), + Instruction::Else, + Instruction::I32Const(2), + Instruction::End, + Instruction::Drop, + Instruction::End, + Instruction::End, + ])).build() + .build() .build(); validate_module(m).unwrap(); } @@ -310,10 +258,8 @@ fn validate(wat: &str) -> ValidatedModule { validated_module } -fn compile(wat: &str) -> (Vec, Vec) { - let validated_module = validate(wat); - let code = &validated_module.code_map[0]; - +fn compile(module: &ValidatedModule) -> (Vec, Vec) { + let code = &module.code_map[0]; let mut instructions = Vec::new(); let mut pcs = Vec::new(); let mut iter = code.iterate_from(0); @@ -323,41 +269,56 @@ fn compile(wat: &str) -> (Vec, Vec) { instructions.push(instruction.clone()); pcs.push(pc); } else { - break + break; } } (instructions, pcs) } +macro_rules! targets { + ($($target:expr),*) => { + ::isa::BrTargets::from_internal( + &[$($target,)*] + .iter() + .map(|&target| ::isa::InstructionInternal::BrTableTarget(target)) + .collect::>()[..] + ) + }; +} + #[test] fn implicit_return_no_value() { - let (code, _) = compile(r#" + let module = validate( + r#" (module (func (export "call") ) ) - "#); + "#, + ); + let (code, _) = compile(&module); assert_eq!( code, - vec![ - isa::Instruction::Return(isa::DropKeep { - drop: 0, - keep: isa::Keep::None, - }) - ] + vec![isa::Instruction::Return(isa::DropKeep { + drop: 0, + keep: isa::Keep::None, + })] ) } #[test] fn implicit_return_with_value() { - let (code, _) = compile(r#" + let module = validate( + r#" (module (func (export "call") (result i32) i32.const 0 ) ) - "#); + "#, + ); + let (code, _) = compile(&module); assert_eq!( code, vec![ @@ -372,32 +333,36 @@ fn implicit_return_with_value() { #[test] fn implicit_return_param() { - let (code, _) = compile(r#" + let module = validate( + r#" (module (func (export "call") (param i32) ) ) - "#); + "#, + ); + let (code, _) = compile(&module); assert_eq!( code, - vec![ - isa::Instruction::Return(isa::DropKeep { - drop: 1, - keep: isa::Keep::None, - }), - ] + vec![isa::Instruction::Return(isa::DropKeep { + drop: 1, + keep: isa::Keep::None, + }),] ) } #[test] fn get_local() { - let (code, _) = compile(r#" + let module = validate( + r#" (module (func (export "call") (param i32) (result i32) get_local 0 ) ) - "#); + "#, + ); + let (code, _) = compile(&module); assert_eq!( code, vec![ @@ -412,14 +377,17 @@ fn get_local() { #[test] fn explicit_return() { - let (code, _) = compile(r#" + let module = validate( + r#" (module (func (export "call") (param i32) (result i32) get_local 0 return ) ) - "#); + "#, + ); + let (code, _) = compile(&module); assert_eq!( code, vec![ @@ -438,7 +406,8 @@ fn explicit_return() { #[test] fn add_params() { - let (code, _) = compile(r#" + let module = validate( + r#" (module (func (export "call") (param i32) (param i32) (result i32) get_local 0 @@ -446,7 +415,9 @@ fn add_params() { i32.add ) ) - "#); + "#, + ); + let (code, _) = compile(&module); assert_eq!( code, vec![ @@ -468,7 +439,8 @@ fn add_params() { #[test] fn drop_locals() { - let (code, _) = compile(r#" + let module = validate( + r#" (module (func (export "call") (param i32) (local i32) @@ -476,7 +448,9 @@ fn drop_locals() { set_local 1 ) ) - "#); + "#, + ); + let (code, _) = compile(&module); assert_eq!( code, vec![ @@ -492,7 +466,8 @@ fn drop_locals() { #[test] fn if_without_else() { - let (code, pcs) = compile(r#" + let module = validate( + r#" (module (func (export "call") (param i32) (result i32) i32.const 1 @@ -503,7 +478,9 @@ fn if_without_else() { i32.const 3 ) ) - "#); + "#, + ); + let (code, pcs) = compile(&module); assert_eq!( code, vec![ @@ -517,7 +494,7 @@ fn if_without_else() { }), isa::Instruction::I32Const(2), isa::Instruction::Return(isa::DropKeep { - drop: 1, // 1 param + drop: 1, // 1 param keep: isa::Keep::Single, // 1 result }), isa::Instruction::I32Const(3), @@ -531,7 +508,8 @@ fn if_without_else() { #[test] fn if_else() { - let (code, pcs) = compile(r#" + let module = validate( + r#" (module (func (export "call") (local i32) @@ -545,7 +523,9 @@ fn if_else() { end ) ) - "#); + "#, + ); + let (code, pcs) = compile(&module); assert_eq!( code, vec![ @@ -578,7 +558,8 @@ fn if_else() { #[test] fn if_else_returns_result() { - let (code, pcs) = compile(r#" + let module = validate( + r#" (module (func (export "call") i32.const 1 @@ -590,7 +571,9 @@ fn if_else_returns_result() { drop ) ) - "#); + "#, + ); + let (code, pcs) = compile(&module); assert_eq!( code, vec![ @@ -622,7 +605,8 @@ fn if_else_returns_result() { #[test] fn if_else_branch_from_true_branch() { - let (code, pcs) = compile(r#" + let module = validate( + r#" (module (func (export "call") i32.const 1 @@ -638,7 +622,9 @@ fn if_else_branch_from_true_branch() { drop ) ) - "#); + "#, + ); + let (code, pcs) = compile(&module); assert_eq!( code, vec![ @@ -680,7 +666,8 @@ fn if_else_branch_from_true_branch() { #[test] fn if_else_branch_from_false_branch() { - let (code, pcs) = compile(r#" + let module = validate( + r#" (module (func (export "call") i32.const 1 @@ -696,7 +683,9 @@ fn if_else_branch_from_false_branch() { drop ) ) - "#); + "#, + ); + let (code, pcs) = compile(&module); assert_eq!( code, vec![ @@ -738,7 +727,8 @@ fn if_else_branch_from_false_branch() { #[test] fn loop_() { - let (code, _) = compile(r#" + let module = validate( + r#" (module (func (export "call") loop (result i32) @@ -749,7 +739,9 @@ fn loop_() { drop ) ) - "#); + "#, + ); + let (code, _) = compile(&module); assert_eq!( code, vec![ @@ -773,28 +765,30 @@ fn loop_() { #[test] fn loop_empty() { - let (code, _) = compile(r#" + let module = validate( + r#" (module (func (export "call") loop end ) ) - "#); + "#, + ); + let (code, _) = compile(&module); assert_eq!( code, - vec![ - isa::Instruction::Return(isa::DropKeep { - drop: 0, - keep: isa::Keep::None, - }), - ] + vec![isa::Instruction::Return(isa::DropKeep { + drop: 0, + keep: isa::Keep::None, + }),] ) } #[test] fn brtable() { - let (code, pcs) = compile(r#" + let module = validate( + r#" (module (func (export "call") block $1 @@ -805,29 +799,29 @@ fn brtable() { end ) ) - "#); + "#, + ); + let (code, pcs) = compile(&module); assert_eq!( code, vec![ isa::Instruction::I32Const(0), - isa::Instruction::BrTable( - vec![ - isa::Target { - dst_pc: 0, - drop_keep: isa::DropKeep { - drop: 0, - keep: isa::Keep::None, - }, + isa::Instruction::BrTable(targets![ + isa::Target { + dst_pc: 0, + drop_keep: isa::DropKeep { + drop: 0, + keep: isa::Keep::None, }, - isa::Target { - dst_pc: pcs[2], - drop_keep: isa::DropKeep { - drop: 0, - keep: isa::Keep::None, - }, + }, + isa::Target { + dst_pc: pcs[2], + drop_keep: isa::DropKeep { + drop: 0, + keep: isa::Keep::None, }, - ].into_boxed_slice() - ), + } + ]), isa::Instruction::Return(isa::DropKeep { drop: 0, keep: isa::Keep::None, @@ -838,7 +832,8 @@ fn brtable() { #[test] fn brtable_returns_result() { - let (code, pcs) = compile(r#" + let module = validate( + r#" (module (func (export "call") block $1 (result i32) @@ -852,30 +847,31 @@ fn brtable_returns_result() { drop ) ) - "#); + "#, + ); + let (code, pcs) = compile(&module); + println!("{:?}", (&code, &pcs)); assert_eq!( code, vec![ isa::Instruction::I32Const(0), isa::Instruction::I32Const(1), - isa::Instruction::BrTable( - vec![ - isa::Target { - dst_pc: pcs[3], - drop_keep: isa::DropKeep { - drop: 0, - keep: isa::Keep::Single, - }, + isa::Instruction::BrTable(targets![ + isa::Target { + dst_pc: pcs[3], + drop_keep: isa::DropKeep { + drop: 0, + keep: isa::Keep::Single, }, - isa::Target { - dst_pc: pcs[4], - drop_keep: isa::DropKeep { - keep: isa::Keep::Single, - drop: 0, - }, + }, + isa::Target { + dst_pc: pcs[4], + drop_keep: isa::DropKeep { + keep: isa::Keep::Single, + drop: 0, }, - ].into_boxed_slice() - ), + } + ]), isa::Instruction::Unreachable, isa::Instruction::Drop, isa::Instruction::Return(isa::DropKeep { @@ -888,7 +884,8 @@ fn brtable_returns_result() { #[test] fn wabt_example() { - let (code, pcs) = compile(r#" + let module = validate( + r#" (module (func (export "call") (param i32) (result i32) block $exit @@ -901,7 +898,9 @@ fn wabt_example() { return ) ) - "#); + "#, + ); + let (code, pcs) = compile(&module); assert_eq!( code, vec![