From b5155dd70bfc9b594695f2fb45ba136c2637ef4f Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Wed, 22 Jun 2022 16:55:16 +0800 Subject: [PATCH 001/129] update tracer --- src/func.rs | 53 ++++++++++- src/global.rs | 4 +- src/isa.rs | 179 +++++++++++++++++++++++++++++++++++++- src/lib.rs | 4 +- src/memory/mod.rs | 3 +- src/memory/vec_bytebuf.rs | 1 + src/module.rs | 18 +++- src/runner.rs | 142 +++++++++++++++++++++++++++++- src/table.rs | 3 +- src/tracer/etable.rs | 70 +++++++++++++++ src/tracer/itable.rs | 35 ++++++++ src/tracer/mod.rs | 75 ++++++++++++++++ 12 files changed, 573 insertions(+), 14 deletions(-) create mode 100644 src/tracer/etable.rs create mode 100644 src/tracer/itable.rs create mode 100644 src/tracer/mod.rs diff --git a/src/func.rs b/src/func.rs index 09026c11c1..79ee21dd7a 100644 --- a/src/func.rs +++ b/src/func.rs @@ -3,6 +3,7 @@ use crate::{ isa, module::ModuleInstance, runner::{check_function_args, Interpreter, InterpreterState, StackRecycler}, + tracer::Tracer, RuntimeValue, Signature, Trap, @@ -21,7 +22,7 @@ use parity_wasm::elements::Local; /// This reference has a reference-counting semantics. /// /// [`FuncInstance`]: struct.FuncInstance.html -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] pub struct FuncRef(Rc); impl ::core::ops::Deref for FuncRef { @@ -45,6 +46,7 @@ impl ::core::ops::Deref for FuncRef { /// See more in [`Externals`]. /// /// [`Externals`]: trait.Externals.html +#[derive(PartialEq)] pub struct FuncInstance(FuncInstanceInternal); #[derive(Clone)] @@ -60,6 +62,36 @@ pub(crate) enum FuncInstanceInternal { }, } +impl PartialEq for FuncInstanceInternal { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + ( + Self::Internal { + signature: l_signature, + body: l_body, + .. + }, + Self::Internal { + signature: r_signature, + body: r_body, + .. + }, + ) => l_signature == r_signature && l_body == r_body, + ( + Self::Host { + signature: l_signature, + host_func_index: l_host_func_index, + }, + Self::Host { + signature: r_signature, + host_func_index: r_host_func_index, + }, + ) => l_signature == r_signature && l_host_func_index == r_host_func_index, + _ => false, + } + } +} + impl fmt::Debug for FuncInstance { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self.as_internal() { @@ -155,6 +187,23 @@ impl FuncInstance { } } + pub fn invoke_trace( + func: &FuncRef, + args: &[RuntimeValue], + externals: &mut E, + tracer: Tracer, + ) -> Result, Trap> { + check_function_args(func.signature(), args)?; + match *func.as_internal() { + FuncInstanceInternal::Internal { .. } => { + let mut interpreter = Interpreter::new(func, args, None)?; + interpreter.tracer = Some(tracer); + interpreter.start_execution(externals) + } + FuncInstanceInternal::Host { .. } => unreachable!(), + } + } + /// Invoke this function using recycled stacks. /// /// # Errors @@ -348,7 +397,7 @@ impl<'args> FuncInvocation<'args> { } } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] pub struct FuncBody { pub locals: Vec, pub code: isa::Instructions, diff --git a/src/global.rs b/src/global.rs index 12bfa48643..16f7a772d5 100644 --- a/src/global.rs +++ b/src/global.rs @@ -8,7 +8,7 @@ use parity_wasm::elements::ValueType as EValueType; /// This reference has a reference-counting semantics. /// /// [`GlobalInstance`]: struct.GlobalInstance.html -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] pub struct GlobalRef(Rc); impl ::core::ops::Deref for GlobalRef { @@ -29,7 +29,7 @@ impl ::core::ops::Deref for GlobalRef { /// /// [`I32`]: enum.Value.html#variant.I32 /// [`I64`]: enum.Value.html#variant.I64 -#[derive(Debug)] +#[derive(Debug, PartialEq)] pub struct GlobalInstance { val: Cell, mutable: bool, diff --git a/src/isa.rs b/src/isa.rs index e2b63cfd42..dea606a26c 100644 --- a/src/isa.rs +++ b/src/isa.rs @@ -341,6 +341,181 @@ pub enum Instruction<'a> { F64ReinterpretI64, } +impl<'a> Into for Instruction<'a> { + fn into(self) -> u32 { + match self { + Instruction::GetLocal(_) => 0, + Instruction::SetLocal(_) => 1, + Instruction::TeeLocal(_) => 2, + Instruction::Br(_) => 3, + Instruction::BrIfEqz(_) => 4, + Instruction::BrIfNez(_) => 5, + Instruction::BrTable(_) => 6, + Instruction::Unreachable => 7, + Instruction::Return(_) => 8, + Instruction::Call(_) => 9, + Instruction::CallIndirect(_) => 10, + Instruction::Drop => 11, + Instruction::Select => 12, + Instruction::GetGlobal(_) => 13, + Instruction::SetGlobal(_) => 14, + Instruction::I32Load(_) => 15, + + Instruction::I64Load(_) => 16, + Instruction::F32Load(_) => 17, + Instruction::F64Load(_) => 18, + Instruction::I32Load8S(_) => 19, + Instruction::I32Load8U(_) => 20, + Instruction::I32Load16S(_) => 21, + Instruction::I32Load16U(_) => 22, + Instruction::I64Load8S(_) => 23, + Instruction::I64Load8U(_) => 24, + Instruction::I64Load16S(_) => 25, + Instruction::I64Load16U(_) => 26, + Instruction::I64Load32S(_) => 27, + Instruction::I64Load32U(_) => 28, + Instruction::I32Store(_) => 29, + Instruction::I64Store(_) => 30, + Instruction::F32Store(_) => 31, + Instruction::F64Store(_) => 32, + Instruction::I32Store8(_) => 33, + Instruction::I32Store16(_) => 34, + Instruction::I64Store8(_) => 35, + Instruction::I64Store16(_) => 36, + Instruction::I64Store32(_) => 37, + Instruction::CurrentMemory => 38, + Instruction::GrowMemory => 39, + Instruction::I32Const(_) => 40, + Instruction::I64Const(_) => 41, + Instruction::F32Const(_) => 42, + Instruction::F64Const(_) => 43, + Instruction::I32Eqz => 44, + Instruction::I32Eq => 45, + Instruction::I32Ne => 46, + Instruction::I32LtS => 47, + Instruction::I32LtU => 48, + Instruction::I32GtS => 49, + Instruction::I32GtU => 50, + Instruction::I32LeS => 51, + Instruction::I32LeU => 52, + Instruction::I32GeS => 53, + Instruction::I32GeU => 54, + Instruction::I64Eqz => 55, + Instruction::I64Eq => 56, + Instruction::I64Ne => 57, + Instruction::I64LtS => 58, + Instruction::I64LtU => 59, + Instruction::I64GtS => 60, + Instruction::I64GtU => 61, + Instruction::I64LeS => 62, + Instruction::I64LeU => 63, + Instruction::I64GeS => 64, + Instruction::I64GeU => 65, + Instruction::F32Eq => 66, + Instruction::F32Ne => 67, + Instruction::F32Lt => 68, + Instruction::F32Gt => 69, + Instruction::F32Le => 70, + Instruction::F32Ge => 71, + Instruction::F64Eq => 72, + Instruction::F64Ne => 73, + Instruction::F64Lt => 74, + Instruction::F64Gt => 75, + Instruction::F64Le => 76, + Instruction::F64Ge => 77, + Instruction::I32Clz => 78, + Instruction::I32Ctz => 79, + Instruction::I32Popcnt => 80, + Instruction::I32Add => 81, + Instruction::I32Sub => 82, + Instruction::I32Mul => 83, + Instruction::I32DivS => 84, + Instruction::I32DivU => 85, + Instruction::I32RemS => 86, + Instruction::I32RemU => 87, + Instruction::I32And => 88, + Instruction::I32Or => 89, + Instruction::I32Xor => 90, + Instruction::I32Shl => 91, + Instruction::I32ShrS => 92, + Instruction::I32ShrU => 93, + Instruction::I32Rotl => 94, + Instruction::I32Rotr => 95, + Instruction::I64Clz => 96, + Instruction::I64Ctz => 97, + Instruction::I64Popcnt => 98, + Instruction::I64Add => 99, + Instruction::I64Sub => 100, + Instruction::I64Mul => 101, + Instruction::I64DivS => 102, + Instruction::I64DivU => 103, + Instruction::I64RemS => 104, + Instruction::I64RemU => 105, + Instruction::I64And => 106, + Instruction::I64Or => 107, + Instruction::I64Xor => 108, + Instruction::I64Shl => 109, + Instruction::I64ShrS => 110, + Instruction::I64ShrU => 111, + Instruction::I64Rotl => 112, + Instruction::I64Rotr => 113, + Instruction::F32Abs => 114, + Instruction::F32Neg => 115, + Instruction::F32Ceil => 116, + Instruction::F32Floor => 117, + Instruction::F32Trunc => 118, + Instruction::F32Nearest => 119, + Instruction::F32Sqrt => 120, + Instruction::F32Add => 121, + Instruction::F32Sub => 122, + Instruction::F32Mul => 123, + Instruction::F32Div => 124, + Instruction::F32Min => 125, + Instruction::F32Max => 126, + Instruction::F32Copysign => 127, + Instruction::F64Abs => 128, + Instruction::F64Neg => 129, + Instruction::F64Ceil => 130, + Instruction::F64Floor => 131, + Instruction::F64Trunc => 132, + Instruction::F64Nearest => 133, + Instruction::F64Sqrt => 134, + Instruction::F64Add => 135, + Instruction::F64Sub => 136, + Instruction::F64Mul => 137, + Instruction::F64Div => 138, + Instruction::F64Min => 139, + Instruction::F64Max => 140, + Instruction::F64Copysign => 141, + Instruction::I32WrapI64 => 142, + Instruction::I32TruncSF32 => 143, + Instruction::I32TruncUF32 => 144, + Instruction::I32TruncSF64 => 145, + Instruction::I32TruncUF64 => 146, + Instruction::I64ExtendSI32 => 147, + Instruction::I64ExtendUI32 => 148, + Instruction::I64TruncSF32 => 149, + Instruction::I64TruncUF32 => 150, + Instruction::I64TruncSF64 => 151, + Instruction::I64TruncUF64 => 152, + Instruction::F32ConvertSI32 => 153, + Instruction::F32ConvertUI32 => 154, + Instruction::F32ConvertSI64 => 155, + Instruction::F32ConvertUI64 => 156, + Instruction::F32DemoteF64 => 157, + Instruction::F64ConvertSI32 => 158, + Instruction::F64ConvertUI32 => 159, + Instruction::F64ConvertSI64 => 160, + Instruction::F64ConvertUI64 => 161, + Instruction::F64PromoteF32 => 162, + Instruction::I32ReinterpretF32 => 163, + Instruction::I64ReinterpretF64 => 164, + Instruction::F32ReinterpretI32 => 165, + Instruction::F64ReinterpretI64 => 166, + } + } +} + /// 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 @@ -537,9 +712,9 @@ pub(crate) enum InstructionInternal { F64ReinterpretI64, } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub struct Instructions { - vec: Vec, + pub(crate) vec: Vec, } impl Instructions { diff --git a/src/lib.rs b/src/lib.rs index b8901624cf..f3679d58c1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -94,7 +94,7 @@ //! } //! ``` -#![warn(missing_docs)] +// #![warn(missing_docs)] #![cfg_attr(not(feature = "std"), no_std)] #![allow(clippy::len_without_is_empty)] #![allow(clippy::new_ret_no_self)] @@ -269,6 +269,8 @@ mod prepare; mod runner; mod table; mod types; +/// Tracer lib for zkWasm +pub mod tracer; pub use self::{ func::{FuncInstance, FuncInvocation, FuncRef, ResumableError}, diff --git a/src/memory/mod.rs b/src/memory/mod.rs index 820eefeb03..d49cabbcb6 100644 --- a/src/memory/mod.rs +++ b/src/memory/mod.rs @@ -36,7 +36,7 @@ pub const LINEAR_MEMORY_PAGE_SIZE: Bytes = Bytes(65536); /// /// [`MemoryInstance`]: struct.MemoryInstance.html /// -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] pub struct MemoryRef(Rc); impl ::core::ops::Deref for MemoryRef { @@ -59,6 +59,7 @@ impl ::core::ops::Deref for MemoryRef { /// At the moment, wasm doesn't provide any way to shrink the memory. /// /// [`LINEAR_MEMORY_PAGE_SIZE`]: constant.LINEAR_MEMORY_PAGE_SIZE.html +#[derive(PartialEq)] pub struct MemoryInstance { /// Memory limits. limits: ResizableLimits, diff --git a/src/memory/vec_bytebuf.rs b/src/memory/vec_bytebuf.rs index 45dcb214b0..6719d7fc63 100644 --- a/src/memory/vec_bytebuf.rs +++ b/src/memory/vec_bytebuf.rs @@ -2,6 +2,7 @@ use alloc::{string::String, vec::Vec}; +#[derive(PartialEq)] pub struct ByteBuf { buf: Vec, } diff --git a/src/module.rs b/src/module.rs index 282f75a59a..1de3f00eb6 100644 --- a/src/module.rs +++ b/src/module.rs @@ -8,6 +8,7 @@ use crate::{ nan_preserving_float::{F32, F64}, runner::StackRecycler, table::TableRef, + tracer::Tracer, types::{GlobalDescriptor, MemoryDescriptor, TableDescriptor}, Error, MemoryInstance, @@ -44,7 +45,7 @@ use validation::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX}; /// should be retained. /// /// [`ModuleInstance`]: struct.ModuleInstance.html -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] pub struct ModuleRef(pub(crate) Rc); impl ::core::ops::Deref for ModuleRef { @@ -56,6 +57,7 @@ impl ::core::ops::Deref for ModuleRef { /// An external value is the runtime representation of an entity /// that can be imported or exported. +#[derive(PartialEq)] pub enum ExternVal { /// [Function][`FuncInstance`]. /// @@ -162,7 +164,7 @@ impl ExternVal { /// [`TableInstance`]: struct.TableInstance.html /// [`GlobalInstance`]: struct.GlobalInstance.html /// [`invoke_export`]: #method.invoke_export -#[derive(Debug)] +#[derive(Debug, PartialEq)] pub struct ModuleInstance { signatures: RefCell>>, tables: RefCell>, @@ -644,6 +646,18 @@ impl ModuleInstance { FuncInstance::invoke(&func_instance, args, externals).map_err(Error::Trap) } + pub fn invoke_export_trace( + &self, + func_name: &str, + args: &[RuntimeValue], + externals: &mut E, + tracer: Tracer, + ) -> Result, Error> { + let func_instance = self.func_by_name(func_name)?; + + FuncInstance::invoke_trace(&func_instance, args, externals, tracer).map_err(Error::Trap) + } + /// Invoke exported function by a name using recycled stacks. /// /// # Errors diff --git a/src/runner.rs b/src/runner.rs index 70db7bd3d4..48b86623ca 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -3,11 +3,15 @@ use crate::{ func::{FuncInstance, FuncInstanceInternal, FuncRef}, host::Externals, - isa, + isa::{self, DropKeep, Keep}, memory::MemoryRef, memory_units::Pages, module::ModuleRef, nan_preserving_float::{F32, F64}, + tracer::{ + etable::{RunInstructionTracePre, RunInstructionTraceStep}, + Tracer, + }, value::{ ArithmeticOps, ExtendInto, @@ -47,7 +51,7 @@ pub const DEFAULT_CALL_STACK_LIMIT: usize = 64 * 1024; /// at these boundaries. #[derive(Copy, Clone, Debug, PartialEq, Default)] #[repr(transparent)] -struct ValueInternal(pub u64); +pub struct ValueInternal(pub u64); impl ValueInternal { pub fn with_type(self, ty: ValueType) -> RuntimeValue { @@ -178,6 +182,7 @@ pub struct Interpreter { return_type: Option, state: InterpreterState, scratch: Vec, + pub(crate) tracer: Option, } impl Interpreter { @@ -208,6 +213,7 @@ impl Interpreter { return_type, state: InterpreterState::Initialized, scratch: Vec::new(), + tracer: None, }) } @@ -353,6 +359,109 @@ impl Interpreter { } } + fn run_instruction_pre( + &mut self, + instructions: &isa::Instruction, + ) -> Option { + match *instructions { + isa::Instruction::BrIfNez(_) => Some(RunInstructionTracePre::BrIfNez { + value: <_>::from_value_internal(*self.value_stack.pick(0)), + }), + isa::Instruction::Return(_) => None, + + isa::Instruction::Call(_) => None, + + isa::Instruction::GetLocal(depth) => { + let value = self.value_stack.pick(depth as usize); + Some(RunInstructionTracePre::GetLocal { + depth, + value: value.clone(), + }) + } + isa::Instruction::I32Const(_) => None, + + isa::Instruction::I32Ne => Some(RunInstructionTracePre::I32Comp { + left: <_>::from_value_internal(*self.value_stack.pick(1)), + right: <_>::from_value_internal(*self.value_stack.pick(0)), + }), + + isa::Instruction::I32Add | isa::Instruction::I32Or => { + Some(RunInstructionTracePre::I32BinOp { + left: <_>::from_value_internal(*self.value_stack.pick(1)), + right: <_>::from_value_internal(*self.value_stack.pick(0)), + }) + } + + _ => { + println!("{:?}", *instructions); + unimplemented!() + } + } + } + + fn run_instruction_post( + &mut self, + pre_status: Option, + instructions: &isa::Instruction, + ) -> RunInstructionTraceStep { + match *instructions { + isa::Instruction::BrIfNez(target) => { + if let RunInstructionTracePre::BrIfNez { value } = pre_status.unwrap() { + RunInstructionTraceStep::BrIfNez { + value, + dst_pc: target.dst_pc, + } + } else { + unreachable!() + } + } + + isa::Instruction::Return(DropKeep { drop, keep }) => RunInstructionTraceStep::Return { + drop, + keep: if keep == Keep::Single { 1 } else { 0 }, + }, + + isa::Instruction::Call(index) => RunInstructionTraceStep::Call { index }, + + isa::Instruction::GetLocal(_) => { + if let RunInstructionTracePre::GetLocal { depth, value } = pre_status.unwrap() { + RunInstructionTraceStep::GetLocal { depth, value } + } else { + unreachable!() + } + } + + isa::Instruction::I32Const(_) => RunInstructionTraceStep::I32Const { + value: <_>::from_value_internal(*self.value_stack.pick(0)), + }, + + isa::Instruction::I32Ne => { + if let RunInstructionTracePre::I32Comp { left, right } = pre_status.unwrap() { + RunInstructionTraceStep::I32Comp { + left, + right, + value: <_>::from_value_internal(*self.value_stack.pick(0)), + } + } else { + unreachable!() + } + } + + isa::Instruction::I32Add | isa::Instruction::I32Or => { + if let RunInstructionTracePre::I32BinOp { left, right } = pre_status.unwrap() { + RunInstructionTraceStep::I32BinOp { + left, + right, + value: <_>::from_value_internal(*self.value_stack.pick(0)), + } + } else { + unreachable!() + } + } + _ => unimplemented!(), + } + } + fn do_run_function( &mut self, function_context: &mut FunctionContext, @@ -361,23 +470,50 @@ impl Interpreter { let mut iter = instructions.iterate_from(function_context.position); loop { + let pc = iter.position(); + let sp = self.value_stack.sp; + 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`.", ); + let pre_status = self.run_instruction_pre(&instruction); + + macro_rules! trace_post { + () => { + let post_status = self.run_instruction_post(pre_status, &instruction); + if let Some(tracer) = self.tracer.as_mut() { + tracer.etable.push( + tracer.lookup_module_instance(&function_context.module), + tracer.lookup_function(&function_context.function), + sp as u64, + pc, + instruction.into(), + post_status, + ); + } + }; + } + match self.run_instruction(function_context, &instruction)? { - InstructionOutcome::RunNextInstruction => {} + InstructionOutcome::RunNextInstruction => { + trace_post!(); + } InstructionOutcome::Branch(target) => { + trace_post!(); iter = instructions.iterate_from(target.dst_pc); self.value_stack.drop_keep(target.drop_keep); } InstructionOutcome::ExecuteCall(func_ref) => { + // We don't record updated pc, the value should be recorded in the next trace log. + trace_post!(); function_context.position = iter.position(); return Ok(RunResult::NestedCall(func_ref)); } InstructionOutcome::Return(drop_keep) => { + trace_post!(); self.value_stack.drop_keep(drop_keep); break; } diff --git a/src/table.rs b/src/table.rs index 9100e58be1..9ab4bb7e8e 100644 --- a/src/table.rs +++ b/src/table.rs @@ -9,7 +9,7 @@ use parity_wasm::elements::ResizableLimits; /// /// [`TableInstance`]: struct.TableInstance.html /// -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] pub struct TableRef(Rc); impl ::core::ops::Deref for TableRef { @@ -32,6 +32,7 @@ impl ::core::ops::Deref for TableRef { /// /// [`grow`]: #method.grow /// +#[derive(PartialEq)] pub struct TableInstance { /// Table limits. limits: ResizableLimits, diff --git a/src/tracer/etable.rs b/src/tracer/etable.rs new file mode 100644 index 0000000000..aa873cd9cc --- /dev/null +++ b/src/tracer/etable.rs @@ -0,0 +1,70 @@ +use crate::runner::ValueInternal; + +use super::itable::IEntry; + +pub enum RunInstructionTracePre { + BrIfNez { value: bool }, + + GetLocal { depth: u32, value: ValueInternal }, + + I32BinOp { left: i32, right: i32 }, + + I32Comp { left: i32, right: i32 }, +} + +#[derive(Debug)] +pub enum RunInstructionTraceStep { + BrIfNez { value: bool, dst_pc: u32 }, + Return { drop: u32, keep: u32 }, + + Call { index: u32 }, + + GetLocal { depth: u32, value: ValueInternal }, + + I32Const { value: i32 }, + + I32BinOp { left: i32, right: i32, value: i32 }, + + I32Comp { left: i32, right: i32, value: bool }, +} + +#[derive(Debug)] +pub struct EEntry { + pub id: u64, + pub sp: u64, + pub inst: IEntry, + pub step: RunInstructionTraceStep, +} + +#[derive(Debug)] +pub struct ETable(pub Vec); + +impl Default for ETable { + fn default() -> Self { + Self(Default::default()) + } +} + +impl ETable { + pub fn push( + &mut self, + module_instance_index: u32, + func_index: u32, + sp: u64, + pc: u32, + opcode: u32, + step: RunInstructionTraceStep, + ) { + self.0.push(EEntry { + id: self.0.len() as u64, + sp, + inst: IEntry { + module_instance_index, + func_index, + pc, + opcode, + }, + step, + }) + } +} diff --git a/src/tracer/itable.rs b/src/tracer/itable.rs new file mode 100644 index 0000000000..9bba1fd54f --- /dev/null +++ b/src/tracer/itable.rs @@ -0,0 +1,35 @@ +use core::fmt::Debug; + +#[derive(Debug)] +pub struct IEntry { + pub module_instance_index: u32, + pub func_index: u32, + pub pc: u32, + pub opcode: u32, +} + +#[derive(Debug)] +pub struct ITable(pub Vec); + +impl Default for ITable { + fn default() -> Self { + Self(vec![]) + } +} + +impl ITable { + pub(crate) fn push( + &mut self, + module_instance_index: u32, + func_index: u32, + pc: u32, + opcode: u32, + ) { + self.0.push(IEntry { + module_instance_index, + func_index, + pc, + opcode, + }) + } +} diff --git a/src/tracer/mod.rs b/src/tracer/mod.rs new file mode 100644 index 0000000000..4543739e5b --- /dev/null +++ b/src/tracer/mod.rs @@ -0,0 +1,75 @@ +use crate::{FuncRef, ModuleRef}; + +use self::{etable::ETable, itable::ITable}; + +pub mod etable; +pub mod itable; + +pub struct Tracer { + pub itable: ITable, + pub etable: ETable, + pub(crate) module_instance_lookup: Vec, + pub(crate) function_lookup: Vec<(FuncRef, u32)>, +} + +impl Tracer { + /// Create an empty tracer + pub fn default() -> Self { + Tracer { + itable: ITable::default(), + etable: ETable::default(), + module_instance_lookup: vec![], + function_lookup: vec![], + } + } +} + +impl Tracer { + pub fn register_module_instance(&mut self, module_instance: &ModuleRef) { + let mut func_index = 0; + + loop { + if let Some(func) = module_instance.func_by_index(func_index) { + let body = func.body().expect("Host function is not allowed"); + let code = &body.code; + let mut iter = code.iterate_from(0); + loop { + let pc = iter.position(); + if let Some(instruction) = iter.next() { + self.itable.push( + self.module_instance_lookup.len() as u32, + func_index, + pc, + instruction.into(), + ) + } else { + break; + } + } + + func_index = func_index + 1; + self.function_lookup.push((func.clone(), func_index)) + } else { + break; + } + } + + self.module_instance_lookup.push(module_instance.clone()); + } + + pub fn lookup_module_instance(&self, module_instance: &ModuleRef) -> u32 { + self.module_instance_lookup + .iter() + .position(|m| m == module_instance) + .unwrap() as u32 + } + + pub fn lookup_function(&self, function: &FuncRef) -> u32 { + let pos = self + .function_lookup + .iter() + .position(|m| m.0 == *function) + .unwrap(); + self.function_lookup.get(pos).unwrap().1 + } +} From 0d2cddf0954bbe28b25c8de5061186b2d13496c2 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Mon, 27 Jun 2022 18:43:42 +0800 Subject: [PATCH 002/129] use Rc for tracer --- src/func.rs | 4 ++-- src/module.rs | 2 +- src/runner.rs | 32 ++++++++++++++++++++++---------- src/tracer/etable.rs | 8 ++++---- src/tracer/itable.rs | 16 ++++++++-------- src/tracer/mod.rs | 1 + 6 files changed, 38 insertions(+), 25 deletions(-) diff --git a/src/func.rs b/src/func.rs index 79ee21dd7a..ddd86d36af 100644 --- a/src/func.rs +++ b/src/func.rs @@ -14,7 +14,7 @@ use alloc::{ rc::{Rc, Weak}, vec::Vec, }; -use core::fmt; +use core::{fmt, cell::RefCell}; use parity_wasm::elements::Local; /// Reference to a function (See [`FuncInstance`] for details). @@ -191,7 +191,7 @@ impl FuncInstance { func: &FuncRef, args: &[RuntimeValue], externals: &mut E, - tracer: Tracer, + tracer: Rc>, ) -> Result, Trap> { check_function_args(func.signature(), args)?; match *func.as_internal() { diff --git a/src/module.rs b/src/module.rs index 1de3f00eb6..807451e080 100644 --- a/src/module.rs +++ b/src/module.rs @@ -651,7 +651,7 @@ impl ModuleInstance { func_name: &str, args: &[RuntimeValue], externals: &mut E, - tracer: Tracer, + tracer: Rc>, ) -> Result, Error> { let func_instance = self.func_by_name(func_name)?; diff --git a/src/runner.rs b/src/runner.rs index 48b86623ca..c09c99c0ef 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -29,8 +29,9 @@ use crate::{ ValueType, }; use alloc::{boxed::Box, vec::Vec}; -use core::{fmt, ops, u32, usize}; +use core::{cell::RefCell, fmt, ops, u32, usize}; use parity_wasm::elements::Local; +use std::rc::Rc; use validation::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX}; /// Maximum number of bytes on the value stack. @@ -182,7 +183,7 @@ pub struct Interpreter { return_type: Option, state: InterpreterState, scratch: Vec, - pub(crate) tracer: Option, + pub(crate) tracer: Option>>, } impl Interpreter { @@ -485,14 +486,25 @@ impl Interpreter { () => { let post_status = self.run_instruction_post(pre_status, &instruction); if let Some(tracer) = self.tracer.as_mut() { - tracer.etable.push( - tracer.lookup_module_instance(&function_context.module), - tracer.lookup_function(&function_context.function), - sp as u64, - pc, - instruction.into(), - post_status, - ); + // let ref_tracer = tracer.borrow(); + let module_instance = { + (*tracer).borrow().lookup_module_instance(&function_context.module) + }; + + let function = { + (*tracer).borrow().lookup_function(&function_context.function) + }; + + { + (*tracer).borrow_mut().etable.push( + module_instance, + function, + sp as u64, + pc, + instruction.into(), + post_status, + ); + } } }; } diff --git a/src/tracer/etable.rs b/src/tracer/etable.rs index aa873cd9cc..c9814e3d4d 100644 --- a/src/tracer/etable.rs +++ b/src/tracer/etable.rs @@ -59,10 +59,10 @@ impl ETable { id: self.0.len() as u64, sp, inst: IEntry { - module_instance_index, - func_index, - pc, - opcode, + module_instance_index: module_instance_index as u16, + func_index: func_index as u16, + pc: pc as u16, + opcode: opcode as u64, }, step, }) diff --git a/src/tracer/itable.rs b/src/tracer/itable.rs index 9bba1fd54f..d33f647a9d 100644 --- a/src/tracer/itable.rs +++ b/src/tracer/itable.rs @@ -2,10 +2,10 @@ use core::fmt::Debug; #[derive(Debug)] pub struct IEntry { - pub module_instance_index: u32, - pub func_index: u32, - pub pc: u32, - pub opcode: u32, + pub module_instance_index: u16, + pub func_index: u16, + pub pc: u16, + pub opcode: u64, } #[derive(Debug)] @@ -26,10 +26,10 @@ impl ITable { opcode: u32, ) { self.0.push(IEntry { - module_instance_index, - func_index, - pc, - opcode, + module_instance_index: module_instance_index as u16, + func_index: func_index as u16, + pc: pc as u16, + opcode: opcode as u64, }) } } diff --git a/src/tracer/mod.rs b/src/tracer/mod.rs index 4543739e5b..716167a2c3 100644 --- a/src/tracer/mod.rs +++ b/src/tracer/mod.rs @@ -5,6 +5,7 @@ use self::{etable::ETable, itable::ITable}; pub mod etable; pub mod itable; +#[derive(Debug)] pub struct Tracer { pub itable: ITable, pub etable: ETable, From c15a16a6b2d94a6fb8aea4260c5e69414a5e0f92 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Wed, 29 Jun 2022 15:22:28 +0800 Subject: [PATCH 003/129] dump values of dropkeep for Return --- src/runner.rs | 30 ++++++++++++++++++++++++------ src/tracer/etable.rs | 2 +- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/runner.rs b/src/runner.rs index c09c99c0ef..d1172dc20a 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -417,10 +417,24 @@ impl Interpreter { } } - isa::Instruction::Return(DropKeep { drop, keep }) => RunInstructionTraceStep::Return { - drop, - keep: if keep == Keep::Single { 1 } else { 0 }, - }, + isa::Instruction::Return(DropKeep { drop, keep }) => { + let mut drop_values = vec![]; + + for i in 0..drop { + drop_values.push(*self.value_stack.pick(i as usize)); + } + + RunInstructionTraceStep::Return { + drop, + keep: if keep == Keep::Single { 1 } else { 0 }, + drop_values, + keep_values: if keep == isa::Keep::Single { + vec![*self.value_stack.top()] + } else { + vec![] + }, + } + } isa::Instruction::Call(index) => RunInstructionTraceStep::Call { index }, @@ -488,11 +502,15 @@ impl Interpreter { if let Some(tracer) = self.tracer.as_mut() { // let ref_tracer = tracer.borrow(); let module_instance = { - (*tracer).borrow().lookup_module_instance(&function_context.module) + (*tracer) + .borrow() + .lookup_module_instance(&function_context.module) }; let function = { - (*tracer).borrow().lookup_function(&function_context.function) + (*tracer) + .borrow() + .lookup_function(&function_context.function) }; { diff --git a/src/tracer/etable.rs b/src/tracer/etable.rs index c9814e3d4d..7f4dec9ac4 100644 --- a/src/tracer/etable.rs +++ b/src/tracer/etable.rs @@ -15,7 +15,7 @@ pub enum RunInstructionTracePre { #[derive(Debug)] pub enum RunInstructionTraceStep { BrIfNez { value: bool, dst_pc: u32 }, - Return { drop: u32, keep: u32 }, + Return { drop: u32, keep: u32, drop_values: Vec, keep_values: Vec }, Call { index: u32 }, From 1f0f120051a3dd985434970f64623363d89e0df6 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Wed, 29 Jun 2022 16:13:15 +0800 Subject: [PATCH 004/129] replace the type of BrIfNez's top with i32 --- src/tracer/etable.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tracer/etable.rs b/src/tracer/etable.rs index 7f4dec9ac4..029b27810f 100644 --- a/src/tracer/etable.rs +++ b/src/tracer/etable.rs @@ -3,7 +3,7 @@ use crate::runner::ValueInternal; use super::itable::IEntry; pub enum RunInstructionTracePre { - BrIfNez { value: bool }, + BrIfNez { value: i32 }, GetLocal { depth: u32, value: ValueInternal }, @@ -14,7 +14,7 @@ pub enum RunInstructionTracePre { #[derive(Debug)] pub enum RunInstructionTraceStep { - BrIfNez { value: bool, dst_pc: u32 }, + BrIfNez { value: i32, dst_pc: u32 }, Return { drop: u32, keep: u32, drop_values: Vec, keep_values: Vec }, Call { index: u32 }, From 3a26f81d8cbd8f46bad9bb53d8bda757b19926ca Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Mon, 11 Jul 2022 16:02:36 +0800 Subject: [PATCH 005/129] option tracer --- src/module.rs | 2 +- src/runner.rs | 56 ++++++++++++++++++++++++++++----------------------- 2 files changed, 32 insertions(+), 26 deletions(-) diff --git a/src/module.rs b/src/module.rs index 807451e080..ca3b7a7338 100644 --- a/src/module.rs +++ b/src/module.rs @@ -642,7 +642,7 @@ impl ModuleInstance { externals: &mut E, ) -> Result, Error> { let func_instance = self.func_by_name(func_name)?; - + println!("{:?}", func_instance.body()); FuncInstance::invoke(&func_instance, args, externals).map_err(Error::Trap) } diff --git a/src/runner.rs b/src/runner.rs index d1172dc20a..e7cf49bb5c 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -494,34 +494,40 @@ impl Interpreter { return or an implicit block `end`.", ); - let pre_status = self.run_instruction_pre(&instruction); + let pre_status = if self.tracer.is_some() { + self.run_instruction_pre(&instruction) + } else { + None + }; macro_rules! trace_post { () => { - let post_status = self.run_instruction_post(pre_status, &instruction); - if let Some(tracer) = self.tracer.as_mut() { - // let ref_tracer = tracer.borrow(); - let module_instance = { - (*tracer) - .borrow() - .lookup_module_instance(&function_context.module) - }; - - let function = { - (*tracer) - .borrow() - .lookup_function(&function_context.function) - }; - - { - (*tracer).borrow_mut().etable.push( - module_instance, - function, - sp as u64, - pc, - instruction.into(), - post_status, - ); + if self.tracer.is_some() { + let post_status = self.run_instruction_post(pre_status, &instruction); + if let Some(tracer) = self.tracer.as_mut() { + // let ref_tracer = tracer.borrow(); + let module_instance = { + (*tracer) + .borrow() + .lookup_module_instance(&function_context.module) + }; + + let function = { + (*tracer) + .borrow() + .lookup_function(&function_context.function) + }; + + { + (*tracer).borrow_mut().etable.push( + module_instance, + function, + sp as u64, + pc, + instruction.into(), + post_status, + ); + } } } }; From 22094c01be0c73db9cae3019914220932c98c447 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Mon, 11 Jul 2022 17:30:09 +0800 Subject: [PATCH 006/129] add run_start_tracer --- src/module.rs | 20 ++++++++++++++++++++ src/tracer/etable.rs | 41 ++++++++++++++++++++++++++++++++--------- src/tracer/itable.rs | 2 +- 3 files changed, 53 insertions(+), 10 deletions(-) diff --git a/src/module.rs b/src/module.rs index ca3b7a7338..81cd77babd 100644 --- a/src/module.rs +++ b/src/module.rs @@ -753,6 +753,26 @@ impl<'a> NotStartedModuleRef<'a> { Ok(self.instance) } + /// Executes `start` function (if any) and returns fully instantiated module. + /// + /// # Errors + /// + /// Returns `Err` if start function traps. + pub fn run_start_tracer( + self, + state: &mut E, + tracer: Rc>, + ) -> Result { + if let Some(start_fn_idx) = self.loaded_module.module().start_section() { + let start_func = self + .instance + .func_by_index(start_fn_idx) + .expect("Due to validation start function should exists"); + FuncInstance::invoke_trace(&start_func, &[], state, tracer)?; + } + Ok(self.instance) + } + /// Executes `start` function (if any) and returns fully instantiated module. /// /// # Errors diff --git a/src/tracer/etable.rs b/src/tracer/etable.rs index 029b27810f..554aedc6d2 100644 --- a/src/tracer/etable.rs +++ b/src/tracer/etable.rs @@ -12,23 +12,46 @@ pub enum RunInstructionTracePre { I32Comp { left: i32, right: i32 }, } -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum RunInstructionTraceStep { - BrIfNez { value: i32, dst_pc: u32 }, - Return { drop: u32, keep: u32, drop_values: Vec, keep_values: Vec }, + BrIfNez { + value: i32, + dst_pc: u32, + }, + Return { + drop: u32, + keep: u32, + drop_values: Vec, + keep_values: Vec, + }, - Call { index: u32 }, + Call { + index: u32, + }, - GetLocal { depth: u32, value: ValueInternal }, + GetLocal { + depth: u32, + value: ValueInternal, + }, - I32Const { value: i32 }, + I32Const { + value: i32, + }, - I32BinOp { left: i32, right: i32, value: i32 }, + I32BinOp { + left: i32, + right: i32, + value: i32, + }, - I32Comp { left: i32, right: i32, value: bool }, + I32Comp { + left: i32, + right: i32, + value: bool, + }, } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct EEntry { pub id: u64, pub sp: u64, diff --git a/src/tracer/itable.rs b/src/tracer/itable.rs index d33f647a9d..b1cd88707b 100644 --- a/src/tracer/itable.rs +++ b/src/tracer/itable.rs @@ -1,6 +1,6 @@ use core::fmt::Debug; -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct IEntry { pub module_instance_index: u16, pub func_index: u16, From 08f3a681610882631e2ef6794744280dfa478463 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Tue, 12 Jul 2022 16:16:18 +0800 Subject: [PATCH 007/129] depends on specs workspace --- Cargo.toml | 1 + src/isa.rs | 183 +++++++++++++++++++++++++++++++++++++++++++ src/runner.rs | 40 ++++++---- src/tracer/etable.rs | 62 +++++---------- src/tracer/itable.rs | 21 ++++- 5 files changed, 247 insertions(+), 60 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 085b02364e..d653b0851e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ exclude = [ "/res/*", "/tests/*", "/fuzz/*", "/benches/*" ] wasmi_core = { version = "0.1", path = "core", default-features = false } validation = { package = "wasmi-validation", version = "0.4", path = "validation", default-features = false } parity-wasm = { version = "0.42.0", default-features = false } +specs = { path = "../specs" } [dev-dependencies] assert_matches = "1.5" diff --git a/src/isa.rs b/src/isa.rs index dea606a26c..1d76457d91 100644 --- a/src/isa.rs +++ b/src/isa.rs @@ -68,6 +68,7 @@ //! use alloc::vec::Vec; +use specs::{itable::Opcode, mtable::VarType}; /// Should we keep a value before "discarding" a stack frame? /// @@ -341,6 +342,188 @@ pub enum Instruction<'a> { F64ReinterpretI64, } +impl<'a> Into for Instruction<'a> { + fn into(self) -> Opcode { + match self { + Instruction::GetLocal(offset) => Opcode::LocalGet { + offset: offset as u64, + }, + Instruction::SetLocal(_) => todo!(), + Instruction::TeeLocal(_) => todo!(), + Instruction::Br(_) => todo!(), + Instruction::BrIfEqz(_) => todo!(), + Instruction::BrIfNez(_) => todo!(), + Instruction::BrTable(_) => todo!(), + Instruction::Unreachable => todo!(), + Instruction::Return(_) => Opcode::Return, + Instruction::Call(_) => todo!(), + Instruction::CallIndirect(_) => todo!(), + Instruction::Drop => Opcode::Drop, + Instruction::Select => todo!(), + Instruction::GetGlobal(_) => todo!(), + Instruction::SetGlobal(_) => todo!(), + Instruction::I32Load(_) => todo!(), + Instruction::I64Load(_) => todo!(), + Instruction::F32Load(_) => todo!(), + Instruction::F64Load(_) => todo!(), + Instruction::I32Load8S(_) => todo!(), + Instruction::I32Load8U(_) => todo!(), + Instruction::I32Load16S(_) => todo!(), + Instruction::I32Load16U(_) => todo!(), + Instruction::I64Load8S(_) => todo!(), + Instruction::I64Load8U(_) => todo!(), + Instruction::I64Load16S(_) => todo!(), + Instruction::I64Load16U(_) => todo!(), + Instruction::I64Load32S(_) => todo!(), + Instruction::I64Load32U(_) => todo!(), + Instruction::I32Store(_) => todo!(), + Instruction::I64Store(_) => todo!(), + Instruction::F32Store(_) => todo!(), + Instruction::F64Store(_) => todo!(), + Instruction::I32Store8(_) => todo!(), + Instruction::I32Store16(_) => todo!(), + Instruction::I64Store8(_) => todo!(), + Instruction::I64Store16(_) => todo!(), + Instruction::I64Store32(_) => todo!(), + Instruction::CurrentMemory => todo!(), + Instruction::GrowMemory => todo!(), + Instruction::I32Const(v) => Opcode::Const { + vtype: VarType::I32, + value: v as u64, + }, + Instruction::I64Const(v) => Opcode::Const { + vtype: VarType::I64, + value: v as u64, + }, + Instruction::F32Const(v) => todo!(), + Instruction::F64Const(v) => todo!(), + Instruction::I32Eqz => todo!(), + Instruction::I32Eq => todo!(), + Instruction::I32Ne => todo!(), + Instruction::I32LtS => todo!(), + Instruction::I32LtU => todo!(), + Instruction::I32GtS => todo!(), + Instruction::I32GtU => todo!(), + Instruction::I32LeS => todo!(), + Instruction::I32LeU => todo!(), + Instruction::I32GeS => todo!(), + Instruction::I32GeU => todo!(), + Instruction::I64Eqz => todo!(), + Instruction::I64Eq => todo!(), + Instruction::I64Ne => todo!(), + Instruction::I64LtS => todo!(), + Instruction::I64LtU => todo!(), + Instruction::I64GtS => todo!(), + Instruction::I64GtU => todo!(), + Instruction::I64LeS => todo!(), + Instruction::I64LeU => todo!(), + Instruction::I64GeS => todo!(), + Instruction::I64GeU => todo!(), + Instruction::F32Eq => todo!(), + Instruction::F32Ne => todo!(), + Instruction::F32Lt => todo!(), + Instruction::F32Gt => todo!(), + Instruction::F32Le => todo!(), + Instruction::F32Ge => todo!(), + Instruction::F64Eq => todo!(), + Instruction::F64Ne => todo!(), + Instruction::F64Lt => todo!(), + Instruction::F64Gt => todo!(), + Instruction::F64Le => todo!(), + Instruction::F64Ge => todo!(), + Instruction::I32Clz => todo!(), + Instruction::I32Ctz => todo!(), + Instruction::I32Popcnt => todo!(), + Instruction::I32Add => todo!(), + Instruction::I32Sub => todo!(), + Instruction::I32Mul => todo!(), + Instruction::I32DivS => todo!(), + Instruction::I32DivU => todo!(), + Instruction::I32RemS => todo!(), + Instruction::I32RemU => todo!(), + Instruction::I32And => todo!(), + Instruction::I32Or => todo!(), + Instruction::I32Xor => todo!(), + Instruction::I32Shl => todo!(), + Instruction::I32ShrS => todo!(), + Instruction::I32ShrU => todo!(), + Instruction::I32Rotl => todo!(), + Instruction::I32Rotr => todo!(), + Instruction::I64Clz => todo!(), + Instruction::I64Ctz => todo!(), + Instruction::I64Popcnt => todo!(), + Instruction::I64Add => todo!(), + Instruction::I64Sub => todo!(), + Instruction::I64Mul => todo!(), + Instruction::I64DivS => todo!(), + Instruction::I64DivU => todo!(), + Instruction::I64RemS => todo!(), + Instruction::I64RemU => todo!(), + Instruction::I64And => todo!(), + Instruction::I64Or => todo!(), + Instruction::I64Xor => todo!(), + Instruction::I64Shl => todo!(), + Instruction::I64ShrS => todo!(), + Instruction::I64ShrU => todo!(), + Instruction::I64Rotl => todo!(), + Instruction::I64Rotr => todo!(), + Instruction::F32Abs => todo!(), + Instruction::F32Neg => todo!(), + Instruction::F32Ceil => todo!(), + Instruction::F32Floor => todo!(), + Instruction::F32Trunc => todo!(), + Instruction::F32Nearest => todo!(), + Instruction::F32Sqrt => todo!(), + Instruction::F32Add => todo!(), + Instruction::F32Sub => todo!(), + Instruction::F32Mul => todo!(), + Instruction::F32Div => todo!(), + Instruction::F32Min => todo!(), + Instruction::F32Max => todo!(), + Instruction::F32Copysign => todo!(), + Instruction::F64Abs => todo!(), + Instruction::F64Neg => todo!(), + Instruction::F64Ceil => todo!(), + Instruction::F64Floor => todo!(), + Instruction::F64Trunc => todo!(), + Instruction::F64Nearest => todo!(), + Instruction::F64Sqrt => todo!(), + Instruction::F64Add => todo!(), + Instruction::F64Sub => todo!(), + Instruction::F64Mul => todo!(), + Instruction::F64Div => todo!(), + Instruction::F64Min => todo!(), + Instruction::F64Max => todo!(), + Instruction::F64Copysign => todo!(), + Instruction::I32WrapI64 => todo!(), + Instruction::I32TruncSF32 => todo!(), + Instruction::I32TruncUF32 => todo!(), + Instruction::I32TruncSF64 => todo!(), + Instruction::I32TruncUF64 => todo!(), + Instruction::I64ExtendSI32 => todo!(), + Instruction::I64ExtendUI32 => todo!(), + Instruction::I64TruncSF32 => todo!(), + Instruction::I64TruncUF32 => todo!(), + Instruction::I64TruncSF64 => todo!(), + Instruction::I64TruncUF64 => todo!(), + Instruction::F32ConvertSI32 => todo!(), + Instruction::F32ConvertUI32 => todo!(), + Instruction::F32ConvertSI64 => todo!(), + Instruction::F32ConvertUI64 => todo!(), + Instruction::F32DemoteF64 => todo!(), + Instruction::F64ConvertSI32 => todo!(), + Instruction::F64ConvertUI32 => todo!(), + Instruction::F64ConvertSI64 => todo!(), + Instruction::F64ConvertUI64 => todo!(), + Instruction::F64PromoteF32 => todo!(), + Instruction::I32ReinterpretF32 => todo!(), + Instruction::I64ReinterpretF64 => todo!(), + Instruction::F32ReinterpretI32 => todo!(), + Instruction::F64ReinterpretI64 => todo!(), + } + } +} + impl<'a> Into for Instruction<'a> { fn into(self) -> u32 { match self { diff --git a/src/runner.rs b/src/runner.rs index e7cf49bb5c..e6ece0c52c 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -8,10 +8,7 @@ use crate::{ memory_units::Pages, module::ModuleRef, nan_preserving_float::{F32, F64}, - tracer::{ - etable::{RunInstructionTracePre, RunInstructionTraceStep}, - Tracer, - }, + tracer::{etable::RunInstructionTracePre, Tracer}, value::{ ArithmeticOps, ExtendInto, @@ -31,6 +28,7 @@ use crate::{ use alloc::{boxed::Box, vec::Vec}; use core::{cell::RefCell, fmt, ops, u32, usize}; use parity_wasm::elements::Local; +use specs::{step::StepInfo, types::Value}; use std::rc::Rc; use validation::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX}; @@ -65,6 +63,17 @@ impl ValueInternal { } } +impl ValueInternal { + pub fn value_with_type(self, ty: specs::types::ValueType) -> Value { + match ty { + specs::types::ValueType::I32 => Value::I32(<_>::from_value_internal(self)), + specs::types::ValueType::I64 => Value::I64(<_>::from_value_internal(self)), + specs::types::ValueType::U32 => Value::U32(<_>::from_value_internal(self)), + specs::types::ValueType::U64 => Value::U64(<_>::from_value_internal(self)), + } + } +} + trait FromValueInternal where Self: Sized, @@ -404,11 +413,11 @@ impl Interpreter { &mut self, pre_status: Option, instructions: &isa::Instruction, - ) -> RunInstructionTraceStep { + ) -> StepInfo { match *instructions { isa::Instruction::BrIfNez(target) => { if let RunInstructionTracePre::BrIfNez { value } = pre_status.unwrap() { - RunInstructionTraceStep::BrIfNez { + StepInfo::BrIfNez { value, dst_pc: target.dst_pc, } @@ -424,35 +433,38 @@ impl Interpreter { drop_values.push(*self.value_stack.pick(i as usize)); } - RunInstructionTraceStep::Return { + StepInfo::Return { drop, keep: if keep == Keep::Single { 1 } else { 0 }, - drop_values, + drop_values: drop_values.iter().map(|v| v.0).collect::>(), keep_values: if keep == isa::Keep::Single { - vec![*self.value_stack.top()] + vec![(*self.value_stack.top()).0] } else { vec![] }, } } - isa::Instruction::Call(index) => RunInstructionTraceStep::Call { index }, + isa::Instruction::Call(index) => StepInfo::Call { index }, isa::Instruction::GetLocal(_) => { if let RunInstructionTracePre::GetLocal { depth, value } = pre_status.unwrap() { - RunInstructionTraceStep::GetLocal { depth, value } + StepInfo::GetLocal { + depth, + value: <_>::from_value_internal(value), + } } else { unreachable!() } } - isa::Instruction::I32Const(_) => RunInstructionTraceStep::I32Const { + isa::Instruction::I32Const(_) => StepInfo::I32Const { value: <_>::from_value_internal(*self.value_stack.pick(0)), }, isa::Instruction::I32Ne => { if let RunInstructionTracePre::I32Comp { left, right } = pre_status.unwrap() { - RunInstructionTraceStep::I32Comp { + StepInfo::I32Comp { left, right, value: <_>::from_value_internal(*self.value_stack.pick(0)), @@ -464,7 +476,7 @@ impl Interpreter { isa::Instruction::I32Add | isa::Instruction::I32Or => { if let RunInstructionTracePre::I32BinOp { left, right } = pre_status.unwrap() { - RunInstructionTraceStep::I32BinOp { + StepInfo::I32BinOp { left, right, value: <_>::from_value_internal(*self.value_stack.pick(0)), diff --git a/src/tracer/etable.rs b/src/tracer/etable.rs index 554aedc6d2..a36620251c 100644 --- a/src/tracer/etable.rs +++ b/src/tracer/etable.rs @@ -1,3 +1,5 @@ +use specs::{etable::EventTableEntry, itable::Opcode, step::StepInfo}; + use crate::runner::ValueInternal; use super::itable::IEntry; @@ -12,51 +14,25 @@ pub enum RunInstructionTracePre { I32Comp { left: i32, right: i32 }, } -#[derive(Debug, Clone)] -pub enum RunInstructionTraceStep { - BrIfNez { - value: i32, - dst_pc: u32, - }, - Return { - drop: u32, - keep: u32, - drop_values: Vec, - keep_values: Vec, - }, - - Call { - index: u32, - }, - - GetLocal { - depth: u32, - value: ValueInternal, - }, - - I32Const { - value: i32, - }, - - I32BinOp { - left: i32, - right: i32, - value: i32, - }, - - I32Comp { - left: i32, - right: i32, - value: bool, - }, -} - #[derive(Debug, Clone)] pub struct EEntry { pub id: u64, pub sp: u64, pub inst: IEntry, - pub step: RunInstructionTraceStep, + pub step: StepInfo, +} + +impl Into for EEntry { + fn into(self) -> EventTableEntry { + EventTableEntry { + eid: self.id, + sp: self.sp, + // FIXME: fill with correct value + last_jump_eid: 0, + inst: self.inst.into(), + step_info: self.step.clone(), + } + } } #[derive(Debug)] @@ -75,8 +51,8 @@ impl ETable { func_index: u32, sp: u64, pc: u32, - opcode: u32, - step: RunInstructionTraceStep, + opcode: Opcode, + step: StepInfo, ) { self.0.push(EEntry { id: self.0.len() as u64, @@ -85,7 +61,7 @@ impl ETable { module_instance_index: module_instance_index as u16, func_index: func_index as u16, pc: pc as u16, - opcode: opcode as u64, + opcode, }, step, }) diff --git a/src/tracer/itable.rs b/src/tracer/itable.rs index b1cd88707b..b7cddab794 100644 --- a/src/tracer/itable.rs +++ b/src/tracer/itable.rs @@ -1,11 +1,26 @@ use core::fmt::Debug; +use specs::itable::{InstructionTableEntry, Opcode}; + #[derive(Debug, Clone)] pub struct IEntry { pub module_instance_index: u16, pub func_index: u16, pub pc: u16, - pub opcode: u64, + pub opcode: Opcode, +} + +impl Into for IEntry { + fn into(self) -> InstructionTableEntry { + InstructionTableEntry { + moid: self.module_instance_index, + mmid: self.module_instance_index, + fid: self.func_index, + bid: 0, + iid: self.pc, + opcode: self.opcode, + } + } } #[derive(Debug)] @@ -23,13 +38,13 @@ impl ITable { module_instance_index: u32, func_index: u32, pc: u32, - opcode: u32, + opcode: Opcode, ) { self.0.push(IEntry { module_instance_index: module_instance_index as u16, func_index: func_index as u16, pc: pc as u16, - opcode: opcode as u64, + opcode, }) } } From b78c150e12bce3f70284e676e571ac0f3ccfecc7 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Tue, 12 Jul 2022 16:17:31 +0800 Subject: [PATCH 008/129] fix compiling warning --- src/isa.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/isa.rs b/src/isa.rs index 1d76457d91..09ba0f4750 100644 --- a/src/isa.rs +++ b/src/isa.rs @@ -395,8 +395,8 @@ impl<'a> Into for Instruction<'a> { vtype: VarType::I64, value: v as u64, }, - Instruction::F32Const(v) => todo!(), - Instruction::F64Const(v) => todo!(), + Instruction::F32Const(_) => todo!(), + Instruction::F64Const(_) => todo!(), Instruction::I32Eqz => todo!(), Instruction::I32Eq => todo!(), Instruction::I32Ne => todo!(), From dc4f35355af9967ed892899f05297bf791ba1819 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Wed, 13 Jul 2022 12:05:14 +0800 Subject: [PATCH 009/129] support drop --- src/runner.rs | 10 ++++++++++ src/tracer/etable.rs | 2 ++ 2 files changed, 12 insertions(+) diff --git a/src/runner.rs b/src/runner.rs index e6ece0c52c..c3154a5582 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -379,6 +379,9 @@ impl Interpreter { }), isa::Instruction::Return(_) => None, + isa::Instruction::Drop => Some(RunInstructionTracePre::Drop { + value: <_>::from_value_internal(*self.value_stack.pick(0)), + }), isa::Instruction::Call(_) => None, isa::Instruction::GetLocal(depth) => { @@ -445,6 +448,13 @@ impl Interpreter { } } + isa::Instruction::Drop => { + if let RunInstructionTracePre::Drop { value } = pre_status.unwrap() { + StepInfo::Drop { value: value } + } else { + unreachable!() + } + } isa::Instruction::Call(index) => StepInfo::Call { index }, isa::Instruction::GetLocal(_) => { diff --git a/src/tracer/etable.rs b/src/tracer/etable.rs index a36620251c..12ffec5f0e 100644 --- a/src/tracer/etable.rs +++ b/src/tracer/etable.rs @@ -12,6 +12,8 @@ pub enum RunInstructionTracePre { I32BinOp { left: i32, right: i32 }, I32Comp { left: i32, right: i32 }, + + Drop { value: u64 }, } #[derive(Debug, Clone)] From 0e1942aaf80bf1cb66f5e522c511adabcdc110a9 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Wed, 13 Jul 2022 14:39:59 +0800 Subject: [PATCH 010/129] get type of Local --- src/isa.rs | 32 +++++++++++++++++--------------- src/prepare/compile.rs | 39 ++++++++++++++++++++++++++++++++------- src/runner.rs | 19 +++++++++++++------ src/tracer/etable.rs | 3 ++- 4 files changed, 64 insertions(+), 29 deletions(-) diff --git a/src/isa.rs b/src/isa.rs index 09ba0f4750..f87aa2a4bc 100644 --- a/src/isa.rs +++ b/src/isa.rs @@ -68,6 +68,7 @@ //! use alloc::vec::Vec; +use parity_wasm::elements::ValueType; use specs::{itable::Opcode, mtable::VarType}; /// Should we keep a value before "discarding" a stack frame? @@ -141,13 +142,13 @@ impl<'a> BrTargets<'a> { #[allow(clippy::upper_case_acronyms)] pub enum Instruction<'a> { /// Push a local variable or an argument from the specified depth. - GetLocal(u32), + GetLocal(u32, ValueType), /// Pop a value and put it in at the specified depth. - SetLocal(u32), + SetLocal(u32, ValueType), /// Copy a value to the specified depth. - TeeLocal(u32), + TeeLocal(u32, ValueType), /// Similar to the Wasm ones, but instead of a label depth /// they specify direct PC. @@ -345,11 +346,12 @@ pub enum Instruction<'a> { impl<'a> Into for Instruction<'a> { fn into(self) -> Opcode { match self { - Instruction::GetLocal(offset) => Opcode::LocalGet { + Instruction::GetLocal(offset, typ) => Opcode::LocalGet { offset: offset as u64, + vtype: typ.into(), }, - Instruction::SetLocal(_) => todo!(), - Instruction::TeeLocal(_) => todo!(), + Instruction::SetLocal(..) => todo!(), + Instruction::TeeLocal(..) => todo!(), Instruction::Br(_) => todo!(), Instruction::BrIfEqz(_) => todo!(), Instruction::BrIfNez(_) => todo!(), @@ -527,9 +529,9 @@ impl<'a> Into for Instruction<'a> { impl<'a> Into for Instruction<'a> { fn into(self) -> u32 { match self { - Instruction::GetLocal(_) => 0, - Instruction::SetLocal(_) => 1, - Instruction::TeeLocal(_) => 2, + Instruction::GetLocal(..) => 0, + Instruction::SetLocal(..) => 1, + Instruction::TeeLocal(..) => 2, Instruction::Br(_) => 3, Instruction::BrIfEqz(_) => 4, Instruction::BrIfNez(_) => 5, @@ -710,9 +712,9 @@ impl<'a> Into for Instruction<'a> { #[derive(Copy, Debug, Clone, PartialEq, Eq)] #[allow(clippy::upper_case_acronyms)] pub(crate) enum InstructionInternal { - GetLocal(u32), - SetLocal(u32), - TeeLocal(u32), + GetLocal(u32, ValueType), + SetLocal(u32, ValueType), + TeeLocal(u32, ValueType), Br(Target), BrIfEqz(Target), BrIfNez(Target), @@ -958,9 +960,9 @@ impl<'a> Iterator for InstructionIter<'a> { let internal = self.instructions.get(self.position as usize)?; let out = match *internal { - InstructionInternal::GetLocal(x) => Instruction::GetLocal(x), - InstructionInternal::SetLocal(x) => Instruction::SetLocal(x), - InstructionInternal::TeeLocal(x) => Instruction::TeeLocal(x), + InstructionInternal::GetLocal(x, typ) => Instruction::GetLocal(x, typ), + InstructionInternal::SetLocal(x, typ) => Instruction::SetLocal(x, typ), + InstructionInternal::TeeLocal(x, typ) => Instruction::TeeLocal(x, typ), InstructionInternal::Br(x) => Instruction::Br(x), InstructionInternal::BrIfEqz(x) => Instruction::BrIfEqz(x), InstructionInternal::BrIfNez(x) => Instruction::BrIfNez(x), diff --git a/src/prepare/compile.rs b/src/prepare/compile.rs index d5a9f62a01..4bfc651186 100644 --- a/src/prepare/compile.rs +++ b/src/prepare/compile.rs @@ -1,6 +1,6 @@ use alloc::{string::String, vec::Vec}; -use parity_wasm::elements::{BlockType, FuncBody, Instruction}; +use parity_wasm::elements::{BlockType, FuncBody, Instruction, ValueType}; use crate::isa; use validation::{ @@ -332,19 +332,25 @@ impl Compiler { 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, typ) = + relative_local_depth_type(index, &context.locals, &context.value_stack)?; context.step(instruction)?; - self.sink.emit(isa::InstructionInternal::GetLocal(depth)); + self.sink + .emit(isa::InstructionInternal::GetLocal(depth, typ)); } SetLocal(index) => { context.step(instruction)?; - let depth = relative_local_depth(index, &context.locals, &context.value_stack)?; - self.sink.emit(isa::InstructionInternal::SetLocal(depth)); + let (depth, typ) = + relative_local_depth_type(index, &context.locals, &context.value_stack)?; + self.sink + .emit(isa::InstructionInternal::SetLocal(depth, typ)); } TeeLocal(index) => { context.step(instruction)?; - let depth = relative_local_depth(index, &context.locals, &context.value_stack)?; - self.sink.emit(isa::InstructionInternal::TeeLocal(depth)); + let (depth, typ) = + relative_local_depth_type(index, &context.locals, &context.value_stack)?; + self.sink + .emit(isa::InstructionInternal::TeeLocal(depth, typ)); } GetGlobal(index) => { context.step(instruction)?; @@ -1127,6 +1133,25 @@ fn relative_local_depth( Ok(depth) } +/// Returns a relative depth on the stack of a local variable specified +/// by `idx`. +/// +/// See stack layout definition in mod isa. +fn relative_local_depth_type( + idx: u32, + locals: &Locals, + value_stack: &StackWithLimit, +) -> Result<(u32, ValueType), Error> { + let value_stack_height = value_stack.len() as u32; + let locals_and_params_count = locals.count(); + + 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((depth, locals.type_of_local(idx).unwrap())) +} + /// The target of a branch instruction. /// /// It references a `LabelId` instead of exact instruction address. This is handy diff --git a/src/runner.rs b/src/runner.rs index c3154a5582..64becaa085 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -384,11 +384,12 @@ impl Interpreter { }), isa::Instruction::Call(_) => None, - isa::Instruction::GetLocal(depth) => { + isa::Instruction::GetLocal(depth, vtype) => { let value = self.value_stack.pick(depth as usize); Some(RunInstructionTracePre::GetLocal { depth, value: value.clone(), + vtype, }) } isa::Instruction::I32Const(_) => None, @@ -457,11 +458,17 @@ impl Interpreter { } isa::Instruction::Call(index) => StepInfo::Call { index }, - isa::Instruction::GetLocal(_) => { - if let RunInstructionTracePre::GetLocal { depth, value } = pre_status.unwrap() { + isa::Instruction::GetLocal(..) => { + if let RunInstructionTracePre::GetLocal { + depth, + value, + vtype, + } = pre_status.unwrap() + { StepInfo::GetLocal { depth, value: <_>::from_value_internal(value), + vtype: vtype.into(), } } else { unreachable!() @@ -602,9 +609,9 @@ impl Interpreter { isa::Instruction::Drop => self.run_drop(), isa::Instruction::Select => self.run_select(), - isa::Instruction::GetLocal(depth) => self.run_get_local(*depth), - isa::Instruction::SetLocal(depth) => self.run_set_local(*depth), - isa::Instruction::TeeLocal(depth) => self.run_tee_local(*depth), + isa::Instruction::GetLocal(depth, ..) => self.run_get_local(*depth), + isa::Instruction::SetLocal(depth, ..) => self.run_set_local(*depth), + isa::Instruction::TeeLocal(depth, ..) => self.run_tee_local(*depth), isa::Instruction::GetGlobal(index) => self.run_get_global(context, *index), isa::Instruction::SetGlobal(index) => self.run_set_global(context, *index), diff --git a/src/tracer/etable.rs b/src/tracer/etable.rs index 12ffec5f0e..89b2d01be7 100644 --- a/src/tracer/etable.rs +++ b/src/tracer/etable.rs @@ -1,3 +1,4 @@ +use parity_wasm::elements::ValueType; use specs::{etable::EventTableEntry, itable::Opcode, step::StepInfo}; use crate::runner::ValueInternal; @@ -7,7 +8,7 @@ use super::itable::IEntry; pub enum RunInstructionTracePre { BrIfNez { value: i32 }, - GetLocal { depth: u32, value: ValueInternal }, + GetLocal { depth: u32, value: ValueInternal, vtype: ValueType }, I32BinOp { left: i32, right: i32 }, From 0a82e8866091d0214fbd8e4ffd3db53a27a72357 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Wed, 13 Jul 2022 15:39:33 +0800 Subject: [PATCH 011/129] add dropkeep info for Return --- src/isa.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/isa.rs b/src/isa.rs index f87aa2a4bc..628f879ef5 100644 --- a/src/isa.rs +++ b/src/isa.rs @@ -357,7 +357,10 @@ impl<'a> Into for Instruction<'a> { Instruction::BrIfNez(_) => todo!(), Instruction::BrTable(_) => todo!(), Instruction::Unreachable => todo!(), - Instruction::Return(_) => Opcode::Return, + Instruction::Return(drop_keep) => Opcode::Return { + drop: drop_keep.drop, + keep: if drop_keep.keep == Keep::Single { 1 } else { 0 }, + }, Instruction::Call(_) => todo!(), Instruction::CallIndirect(_) => todo!(), Instruction::Drop => Opcode::Drop, From 761a99afe79536e2bbc1a4a3783143074caa29f9 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Thu, 14 Jul 2022 10:10:35 +0800 Subject: [PATCH 012/129] expose type of keep of Return --- src/isa.rs | 12 ++++-- src/prepare/compile.rs | 89 ++++++++++++++++++++++++------------------ src/runner.rs | 17 ++++---- 3 files changed, 68 insertions(+), 50 deletions(-) diff --git a/src/isa.rs b/src/isa.rs index 628f879ef5..b6969717a7 100644 --- a/src/isa.rs +++ b/src/isa.rs @@ -80,7 +80,7 @@ pub enum Keep { None, /// Pop one value from the yet-to-be-discarded stack frame to the /// current stack frame. - Single, + Single(ValueType), } impl Keep { @@ -88,7 +88,7 @@ impl Keep { pub fn count(&self) -> u32 { match *self { Keep::None => 0, - Keep::Single => 1, + Keep::Single(..) => 1, } } } @@ -359,7 +359,11 @@ impl<'a> Into for Instruction<'a> { Instruction::Unreachable => todo!(), Instruction::Return(drop_keep) => Opcode::Return { drop: drop_keep.drop, - keep: if drop_keep.keep == Keep::Single { 1 } else { 0 }, + keep: if let Keep::Single(t) = drop_keep.keep { + vec![t.into()] + } else { + vec![] + }, }, Instruction::Call(_) => todo!(), Instruction::CallIndirect(_) => todo!(), @@ -540,7 +544,7 @@ impl<'a> Into for Instruction<'a> { Instruction::BrIfNez(_) => 5, Instruction::BrTable(_) => 6, Instruction::Unreachable => 7, - Instruction::Return(_) => 8, + Instruction::Return(..) => 8, Instruction::Call(_) => 9, Instruction::CallIndirect(_) => 10, Instruction::Drop => 11, diff --git a/src/prepare/compile.rs b/src/prepare/compile.rs index 4bfc651186..7ee0f034cc 100644 --- a/src/prepare/compile.rs +++ b/src/prepare/compile.rs @@ -2,7 +2,7 @@ use alloc::{string::String, vec::Vec}; use parity_wasm::elements::{BlockType, FuncBody, Instruction, ValueType}; -use crate::isa; +use crate::isa::{self, Keep}; use validation::{ func::{ require_label, @@ -227,7 +227,7 @@ impl Compiler { Br(depth) => { let target = require_target( depth, - context.value_stack.len(), + &context.value_stack, &context.frame_stack, &self.label_stack, ); @@ -247,7 +247,7 @@ impl Compiler { let target = require_target( depth, - context.value_stack.len(), + &context.value_stack, &context.frame_stack, &self.label_stack, ) @@ -263,38 +263,43 @@ impl Compiler { // At this point, the condition value is at the top of the stack. // But at the point of actual jump the condition will already be // popped off. - let value_stack_height = context.value_stack.len().saturating_sub(1); - let targets = br_table_data - .table - .iter() - .map(|depth| { - require_target( - *depth, - value_stack_height, - &context.frame_stack, - &self.label_stack, - ) - }) - .collect::, _>>(); - let default_target = require_target( - br_table_data.default, - value_stack_height, - &context.frame_stack, - &self.label_stack, - ); - - context.step(instruction)?; - - // These two unwraps are guaranteed to succeed by validation. - const REQUIRE_TARGET_PROOF: &str = - "validation step ensures that the value stack underflows; - validation also ensures that the depth is correct; - qed"; - let targets = targets.expect(REQUIRE_TARGET_PROOF); - let default_target = default_target.expect(REQUIRE_TARGET_PROOF); - - self.sink.emit_br_table(&targets, default_target); + // TODO: pass context.value_stack to require? but how to handle -1 + todo!(); + /* + let value_stack_height = context.value_stack.len().saturating_sub(1); + + let targets = br_table_data + .table + .iter() + .map(|depth| { + require_target( + *depth, + value_stack_height, + &context.frame_stack, + &self.label_stack, + ) + }) + .collect::, _>>(); + let default_target = require_target( + br_table_data.default, + value_stack_height, + &context.frame_stack, + &self.label_stack, + ); + + context.step(instruction)?; + + // These two unwraps are guaranteed to succeed by validation. + const REQUIRE_TARGET_PROOF: &str = + "validation step ensures that the value stack underflows; + validation also ensures that the depth is correct; + qed"; + let targets = targets.expect(REQUIRE_TARGET_PROOF); + let default_target = default_target.expect(REQUIRE_TARGET_PROOF); + + self.sink.emit_br_table(&targets, default_target); + */ } Return => { let drop_keep = @@ -308,6 +313,7 @@ impl Compiler { `drop_keep_return` can't fail; qed", ); + self.sink.emit(isa::InstructionInternal::Return(drop_keep)); } Call(index) => { @@ -1000,16 +1006,21 @@ fn compute_drop_keep( in_stack_polymorphic_state: bool, started_with: StartedWith, block_type: BlockType, - actual_value_stack_height: usize, + actual_value_stack: &StackWithLimit, start_value_stack_height: usize, ) -> Result { + let actual_value_stack_height = actual_value_stack.len(); + // Find out how many values we need to keep (copy to the new stack location after the drop). let keep: isa::Keep = match (started_with, block_type) { // A loop doesn't take a value upon a branch. It can return value // only via reaching it's closing `End` operator. (StartedWith::Loop, _) => isa::Keep::None, - (_, BlockType::Value(_)) => isa::Keep::Single, + (_, BlockType::Value(_)) => isa::Keep::Single(match actual_value_stack.top().unwrap() { + StackValueType::Any => todo!(), + StackValueType::Specific(t) => *t, + }), (_, BlockType::NoResult) => isa::Keep::None, }; @@ -1046,7 +1057,7 @@ fn compute_drop_keep( /// - if underflow of the value stack detected. fn require_target( depth: u32, - value_stack_height: usize, + value_stack: &StackWithLimit, frame_stack: &StackWithLimit, label_stack: &[BlockFrameType], ) -> Result { @@ -1068,7 +1079,7 @@ fn require_target( is_stack_polymorphic, frame.started_with, frame.block_type, - value_stack_height, + value_stack, frame.value_stack_len, )?; @@ -1104,7 +1115,7 @@ fn drop_keep_return( is_stack_polymorphic, frame.started_with, frame.block_type, - value_stack.len(), + value_stack, frame.value_stack_len, )?; diff --git a/src/runner.rs b/src/runner.rs index 64becaa085..5079f00402 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -377,7 +377,7 @@ impl Interpreter { isa::Instruction::BrIfNez(_) => Some(RunInstructionTracePre::BrIfNez { value: <_>::from_value_internal(*self.value_stack.pick(0)), }), - isa::Instruction::Return(_) => None, + isa::Instruction::Return(..) => None, isa::Instruction::Drop => Some(RunInstructionTracePre::Drop { value: <_>::from_value_internal(*self.value_stack.pick(0)), @@ -439,13 +439,16 @@ impl Interpreter { StepInfo::Return { drop, - keep: if keep == Keep::Single { 1 } else { 0 }, - drop_values: drop_values.iter().map(|v| v.0).collect::>(), - keep_values: if keep == isa::Keep::Single { - vec![(*self.value_stack.top()).0] + keep: if let Keep::Single(t) = keep { + vec![t.into()] } else { vec![] }, + drop_values: drop_values.iter().map(|v| v.0).collect::>(), + keep_values: match keep { + Keep::None => vec![(*self.value_stack.top()).0], + Keep::Single(_) => vec![], + }, } } @@ -601,7 +604,7 @@ impl Interpreter { isa::Instruction::BrIfEqz(target) => self.run_br_eqz(*target), isa::Instruction::BrIfNez(target) => self.run_br_nez(*target), isa::Instruction::BrTable(targets) => self.run_br_table(*targets), - isa::Instruction::Return(drop_keep) => self.run_return(*drop_keep), + isa::Instruction::Return(drop_keep, ..) => self.run_return(*drop_keep), isa::Instruction::Call(index) => self.run_call(context, *index), isa::Instruction::CallIndirect(index) => self.run_call_indirect(context, *index), @@ -1589,7 +1592,7 @@ impl core::fmt::Debug for ValueStack { impl ValueStack { #[inline] fn drop_keep(&mut self, drop_keep: isa::DropKeep) { - if drop_keep.keep == isa::Keep::Single { + if let isa::Keep::Single(_) = drop_keep.keep { let top = *self.top(); *self.pick_mut(drop_keep.drop as usize + 1) = top; } From 5ff693b361f8f28d24d741fb7b812454c3215d1c Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Thu, 14 Jul 2022 10:13:20 +0800 Subject: [PATCH 013/129] bugfix: dropkeep --- src/runner.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/runner.rs b/src/runner.rs index 5079f00402..2821484eb2 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -446,8 +446,8 @@ impl Interpreter { }, drop_values: drop_values.iter().map(|v| v.0).collect::>(), keep_values: match keep { - Keep::None => vec![(*self.value_stack.top()).0], - Keep::Single(_) => vec![], + Keep::Single(_) => vec![(*self.value_stack.top()).0], + Keep::None => vec![], }, } } From d6d838d08ad2222140c03d8f27a2c424d5ae8543 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Thu, 14 Jul 2022 14:21:22 +0800 Subject: [PATCH 014/129] add jtable --- src/runner.rs | 25 ++++++++++++++----------- src/tracer/etable.rs | 34 ++++++++++++++++++++++++++-------- src/tracer/itable.rs | 10 +++++++--- src/tracer/jtable.rs | 41 +++++++++++++++++++++++++++++++++++++++++ src/tracer/mod.rs | 13 ++++++++++--- 5 files changed, 98 insertions(+), 25 deletions(-) create mode 100644 src/tracer/jtable.rs diff --git a/src/runner.rs b/src/runner.rs index 2821484eb2..87a08352b0 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -550,17 +550,19 @@ impl Interpreter { .lookup_function(&function_context.function) }; - { - (*tracer).borrow_mut().etable.push( - module_instance, - function, - sp as u64, - pc, - instruction.into(), - post_status, - ); - } + Some((*tracer).borrow_mut().etable.push( + module_instance, + function, + sp as u64, + pc, + instruction.into(), + post_status, + )) + } else { + None } + } else { + None } }; } @@ -576,7 +578,8 @@ impl Interpreter { } InstructionOutcome::ExecuteCall(func_ref) => { // We don't record updated pc, the value should be recorded in the next trace log. - trace_post!(); + let eentry = trace_post!(); + function_context.position = iter.position(); return Ok(RunResult::NestedCall(func_ref)); } diff --git a/src/tracer/etable.rs b/src/tracer/etable.rs index 89b2d01be7..26a1b1d451 100644 --- a/src/tracer/etable.rs +++ b/src/tracer/etable.rs @@ -6,15 +6,29 @@ use crate::runner::ValueInternal; use super::itable::IEntry; pub enum RunInstructionTracePre { - BrIfNez { value: i32 }, + BrIfNez { + value: i32, + }, - GetLocal { depth: u32, value: ValueInternal, vtype: ValueType }, + GetLocal { + depth: u32, + value: ValueInternal, + vtype: ValueType, + }, - I32BinOp { left: i32, right: i32 }, + I32BinOp { + left: i32, + right: i32, + }, - I32Comp { left: i32, right: i32 }, + I32Comp { + left: i32, + right: i32, + }, - Drop { value: u64 }, + Drop { + value: u64, + }, } #[derive(Debug, Clone)] @@ -56,8 +70,8 @@ impl ETable { pc: u32, opcode: Opcode, step: StepInfo, - ) { - self.0.push(EEntry { + ) -> EEntry { + let eentry = EEntry { id: self.0.len() as u64, sp, inst: IEntry { @@ -67,6 +81,10 @@ impl ETable { opcode, }, step, - }) + }; + + self.0.push(eentry.clone()); + + eentry } } diff --git a/src/tracer/itable.rs b/src/tracer/itable.rs index b7cddab794..b7bb1575bd 100644 --- a/src/tracer/itable.rs +++ b/src/tracer/itable.rs @@ -39,12 +39,16 @@ impl ITable { func_index: u32, pc: u32, opcode: Opcode, - ) { - self.0.push(IEntry { + ) -> IEntry { + let ientry = IEntry { module_instance_index: module_instance_index as u16, func_index: func_index as u16, pc: pc as u16, opcode, - }) + }; + + self.0.push(ientry.clone()); + + ientry } } diff --git a/src/tracer/jtable.rs b/src/tracer/jtable.rs new file mode 100644 index 0000000000..1b46ae6f5a --- /dev/null +++ b/src/tracer/jtable.rs @@ -0,0 +1,41 @@ +use specs::jtable::JumpTableEntry; + +use super::itable::IEntry; + +#[derive(Debug, Clone)] +pub struct JEntry { + eid: u64, + last_jump_eid: u64, + inst: IEntry, +} + +#[derive(Debug)] +pub struct JTable(pub Vec); + +impl JTable { + pub fn new(first_inst: &IEntry) -> Self { + JTable(vec![JEntry { + eid: 0, + last_jump_eid: 0, + inst: first_inst.clone(), + }]) + } + + pub fn push(&mut self, eid: u64, last_jump_eid: u64, inst: &IEntry) { + self.0.push(JEntry { + eid, + last_jump_eid, + inst: inst.clone(), + }) + } +} + +impl Into for JEntry { + fn into(self) -> JumpTableEntry { + JumpTableEntry { + eid: self.eid, + last_jump_eid: self.last_jump_eid, + inst: Box::new(self.inst.into()), + } + } +} diff --git a/src/tracer/mod.rs b/src/tracer/mod.rs index 716167a2c3..fe3b0b185d 100644 --- a/src/tracer/mod.rs +++ b/src/tracer/mod.rs @@ -1,14 +1,16 @@ use crate::{FuncRef, ModuleRef}; -use self::{etable::ETable, itable::ITable}; +use self::{etable::ETable, itable::ITable, jtable::JTable}; pub mod etable; pub mod itable; +pub mod jtable; #[derive(Debug)] pub struct Tracer { pub itable: ITable, pub etable: ETable, + pub jtable: Option, pub(crate) module_instance_lookup: Vec, pub(crate) function_lookup: Vec<(FuncRef, u32)>, } @@ -19,6 +21,7 @@ impl Tracer { Tracer { itable: ITable::default(), etable: ETable::default(), + jtable: None, module_instance_lookup: vec![], function_lookup: vec![], } @@ -37,12 +40,16 @@ impl Tracer { loop { let pc = iter.position(); if let Some(instruction) = iter.next() { - self.itable.push( + let ientry = self.itable.push( self.module_instance_lookup.len() as u32, func_index, pc, instruction.into(), - ) + ); + + if self.jtable.is_none() { + self.jtable = Some(JTable::new(&ientry)) + } } else { break; } From 32de987e71ac84b7761ef3cbc46b5919ea0e292f Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Thu, 14 Jul 2022 17:44:58 +0800 Subject: [PATCH 015/129] fill jtable --- src/prepare/compile.rs | 2 +- src/runner.rs | 45 +++++++++++++++++++++++++++++------------- src/tracer/etable.rs | 6 ++++-- src/tracer/mod.rs | 36 ++++++++++++++++++++++++++++++++- 4 files changed, 71 insertions(+), 18 deletions(-) diff --git a/src/prepare/compile.rs b/src/prepare/compile.rs index 7ee0f034cc..09ce89eed6 100644 --- a/src/prepare/compile.rs +++ b/src/prepare/compile.rs @@ -2,7 +2,7 @@ use alloc::{string::String, vec::Vec}; use parity_wasm::elements::{BlockType, FuncBody, Instruction, ValueType}; -use crate::isa::{self, Keep}; +use crate::isa::{self}; use validation::{ func::{ require_label, diff --git a/src/runner.rs b/src/runner.rs index 87a08352b0..a59658ed85 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -26,7 +26,7 @@ use crate::{ ValueType, }; use alloc::{boxed::Box, vec::Vec}; -use core::{cell::RefCell, fmt, ops, u32, usize}; +use core::{borrow::Borrow, cell::RefCell, fmt, ops, u32, usize}; use parity_wasm::elements::Local; use specs::{step::StepInfo, types::Value}; use std::rc::Rc; @@ -322,6 +322,23 @@ impl Interpreter { match *nested_func.as_internal() { FuncInstanceInternal::Internal { .. } => { let nested_context = FunctionContext::new(nested_func.clone()); + + if let Some(trace) = self.tracer.as_mut() { + let eid = trace.borrow_mut().eid(); + let last_jump_eid = trace.borrow_mut().last_jump_eid(); + let inst = trace + .borrow_mut() + .lookup_first_inst(&nested_context.function); + + let mut trace = trace.borrow_mut(); + let jtable = trace.jtable.as_mut(); + if let Some(jtable) = jtable { + jtable.push(eid, last_jump_eid, &inst); + } + + trace.push_frame(); + } + self.call_stack.push(function_context); self.call_stack.push(nested_context); } @@ -537,24 +554,20 @@ impl Interpreter { if self.tracer.is_some() { let post_status = self.run_instruction_post(pre_status, &instruction); if let Some(tracer) = self.tracer.as_mut() { - // let ref_tracer = tracer.borrow(); - let module_instance = { - (*tracer) - .borrow() - .lookup_module_instance(&function_context.module) - }; + let mut tracer = tracer.borrow_mut(); + let module_instance = + tracer.lookup_module_instance(&function_context.module); - let function = { - (*tracer) - .borrow() - .lookup_function(&function_context.function) - }; + let function = tracer.lookup_function(&function_context.function); + + let last_jump_eid = tracer.last_jump_eid(); - Some((*tracer).borrow_mut().etable.push( + Some(tracer.etable.push( module_instance, function, sp as u64, pc, + last_jump_eid, instruction.into(), post_status, )) @@ -565,7 +578,7 @@ impl Interpreter { None } }; - } + }; match self.run_instruction(function_context, &instruction)? { InstructionOutcome::RunNextInstruction => { @@ -585,6 +598,10 @@ impl Interpreter { } InstructionOutcome::Return(drop_keep) => { trace_post!(); + if let Some(trace) = self.tracer.as_mut() { + trace.borrow_mut().pop_frame(); + } + self.value_stack.drop_keep(drop_keep); break; } diff --git a/src/tracer/etable.rs b/src/tracer/etable.rs index 26a1b1d451..4c150b199c 100644 --- a/src/tracer/etable.rs +++ b/src/tracer/etable.rs @@ -35,6 +35,7 @@ pub enum RunInstructionTracePre { pub struct EEntry { pub id: u64, pub sp: u64, + pub last_jump_eid: u64, pub inst: IEntry, pub step: StepInfo, } @@ -44,8 +45,7 @@ impl Into for EEntry { EventTableEntry { eid: self.id, sp: self.sp, - // FIXME: fill with correct value - last_jump_eid: 0, + last_jump_eid: self.last_jump_eid, inst: self.inst.into(), step_info: self.step.clone(), } @@ -68,12 +68,14 @@ impl ETable { func_index: u32, sp: u64, pc: u32, + last_jump_eid: u64, opcode: Opcode, step: StepInfo, ) -> EEntry { let eentry = EEntry { id: self.0.len() as u64, sp, + last_jump_eid, inst: IEntry { module_instance_index: module_instance_index as u16, func_index: func_index as u16, diff --git a/src/tracer/mod.rs b/src/tracer/mod.rs index fe3b0b185d..75add8068a 100644 --- a/src/tracer/mod.rs +++ b/src/tracer/mod.rs @@ -1,6 +1,10 @@ use crate::{FuncRef, ModuleRef}; -use self::{etable::ETable, itable::ITable, jtable::JTable}; +use self::{ + etable::ETable, + itable::{IEntry, ITable}, + jtable::JTable, +}; pub mod etable; pub mod itable; @@ -13,6 +17,7 @@ pub struct Tracer { pub jtable: Option, pub(crate) module_instance_lookup: Vec, pub(crate) function_lookup: Vec<(FuncRef, u32)>, + last_jump_eid: Vec, } impl Tracer { @@ -21,11 +26,28 @@ impl Tracer { Tracer { itable: ITable::default(), etable: ETable::default(), + last_jump_eid: vec![0], jtable: None, module_instance_lookup: vec![], function_lookup: vec![], } } + + pub fn push_frame(&mut self) { + self.last_jump_eid.push(self.etable.0.last().unwrap().id); + } + + pub fn pop_frame(&mut self) { + self.last_jump_eid.pop().unwrap(); + } + + pub fn last_jump_eid(&self) -> u64 { + *self.last_jump_eid.last().unwrap() + } + + pub fn eid(&self) -> u64 { + self.etable.0.last().unwrap().id + } } impl Tracer { @@ -80,4 +102,16 @@ impl Tracer { .unwrap(); self.function_lookup.get(pos).unwrap().1 } + + pub fn lookup_first_inst(&self, function: &FuncRef) -> IEntry { + let function_idx = self.lookup_function(function); + + for ientry in &self.itable.0 { + if ientry.func_index as u32 == function_idx { + return ientry.clone(); + } + } + + unreachable!(); + } } From e1b8cbafedb86b3c66bd2a7c83416a772a1b5ace Mon Sep 17 00:00:00 2001 From: Heng Zhang Date: Thu, 14 Jul 2022 19:39:35 +0800 Subject: [PATCH 016/129] remove bid --- src/tracer/itable.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tracer/itable.rs b/src/tracer/itable.rs index b7bb1575bd..50ab914dcd 100644 --- a/src/tracer/itable.rs +++ b/src/tracer/itable.rs @@ -16,7 +16,6 @@ impl Into for IEntry { moid: self.module_instance_index, mmid: self.module_instance_index, fid: self.func_index, - bid: 0, iid: self.pc, opcode: self.opcode, } From 7b10e72378b7ad78d978c1908c62fdb7809f5815 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Fri, 15 Jul 2022 14:21:01 +0800 Subject: [PATCH 017/129] bugfix: get block type from Blocktype --- src/prepare/compile.rs | 84 +++++++++++++++++++----------------------- src/prepare/tests.rs | 65 ++++++++++++++++---------------- 2 files changed, 72 insertions(+), 77 deletions(-) diff --git a/src/prepare/compile.rs b/src/prepare/compile.rs index 09ce89eed6..03d4a9b9f2 100644 --- a/src/prepare/compile.rs +++ b/src/prepare/compile.rs @@ -227,7 +227,7 @@ impl Compiler { Br(depth) => { let target = require_target( depth, - &context.value_stack, + context.value_stack.len(), &context.frame_stack, &self.label_stack, ); @@ -247,7 +247,7 @@ impl Compiler { let target = require_target( depth, - &context.value_stack, + context.value_stack.len(), &context.frame_stack, &self.label_stack, ) @@ -263,43 +263,38 @@ impl Compiler { // At this point, the condition value is at the top of the stack. // But at the point of actual jump the condition will already be // popped off. + let value_stack_height = context.value_stack.len().saturating_sub(1); - // TODO: pass context.value_stack to require? but how to handle -1 - todo!(); - /* - let value_stack_height = context.value_stack.len().saturating_sub(1); - - let targets = br_table_data - .table - .iter() - .map(|depth| { - require_target( - *depth, - value_stack_height, - &context.frame_stack, - &self.label_stack, - ) - }) - .collect::, _>>(); - let default_target = require_target( - br_table_data.default, - value_stack_height, - &context.frame_stack, - &self.label_stack, - ); - - context.step(instruction)?; - - // These two unwraps are guaranteed to succeed by validation. - const REQUIRE_TARGET_PROOF: &str = - "validation step ensures that the value stack underflows; + let targets = br_table_data + .table + .iter() + .map(|depth| { + require_target( + *depth, + value_stack_height, + &context.frame_stack, + &self.label_stack, + ) + }) + .collect::, _>>(); + let default_target = require_target( + br_table_data.default, + value_stack_height, + &context.frame_stack, + &self.label_stack, + ); + + context.step(instruction)?; + + // These two unwraps are guaranteed to succeed by validation. + const REQUIRE_TARGET_PROOF: &str = + "validation step ensures that the value stack underflows; validation also ensures that the depth is correct; qed"; - let targets = targets.expect(REQUIRE_TARGET_PROOF); - let default_target = default_target.expect(REQUIRE_TARGET_PROOF); + let targets = targets.expect(REQUIRE_TARGET_PROOF); + let default_target = default_target.expect(REQUIRE_TARGET_PROOF); - self.sink.emit_br_table(&targets, default_target); - */ + self.sink.emit_br_table(&targets, default_target); } Return => { let drop_keep = @@ -1006,21 +1001,16 @@ fn compute_drop_keep( in_stack_polymorphic_state: bool, started_with: StartedWith, block_type: BlockType, - actual_value_stack: &StackWithLimit, + actual_value_stack_height: usize, start_value_stack_height: usize, ) -> Result { - let actual_value_stack_height = actual_value_stack.len(); - // Find out how many values we need to keep (copy to the new stack location after the drop). let keep: isa::Keep = match (started_with, block_type) { // A loop doesn't take a value upon a branch. It can return value // only via reaching it's closing `End` operator. (StartedWith::Loop, _) => isa::Keep::None, - (_, BlockType::Value(_)) => isa::Keep::Single(match actual_value_stack.top().unwrap() { - StackValueType::Any => todo!(), - StackValueType::Specific(t) => *t, - }), + (_, BlockType::Value(v)) => isa::Keep::Single(v), (_, BlockType::NoResult) => isa::Keep::None, }; @@ -1057,7 +1047,7 @@ fn compute_drop_keep( /// - if underflow of the value stack detected. fn require_target( depth: u32, - value_stack: &StackWithLimit, + value_stack_height: usize, frame_stack: &StackWithLimit, label_stack: &[BlockFrameType], ) -> Result { @@ -1079,7 +1069,7 @@ fn require_target( is_stack_polymorphic, frame.started_with, frame.block_type, - value_stack, + value_stack_height, frame.value_stack_len, )?; @@ -1115,7 +1105,7 @@ fn drop_keep_return( is_stack_polymorphic, frame.started_with, frame.block_type, - value_stack, + value_stack.len(), frame.value_stack_len, )?; @@ -1153,6 +1143,7 @@ fn relative_local_depth_type( locals: &Locals, value_stack: &StackWithLimit, ) -> Result<(u32, ValueType), Error> { + println!("idx: {} , locals {:?}", idx, locals.count()); let value_stack_height = value_stack.len() as u32; let locals_and_params_count = locals.count(); @@ -1160,7 +1151,8 @@ fn relative_local_depth_type( .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((depth, locals.type_of_local(idx).unwrap())) + let typ = locals.type_of_local(idx)?; + Ok((depth, typ)) } /// The target of a branch instruction. diff --git a/src/prepare/tests.rs b/src/prepare/tests.rs index 40005a917a..36afa25ec3 100644 --- a/src/prepare/tests.rs +++ b/src/prepare/tests.rs @@ -6,7 +6,10 @@ use std::println; use super::{compile_module, CompiledModule}; use crate::isa; -use parity_wasm::{deserialize_buffer, elements::Module}; +use parity_wasm::{ + deserialize_buffer, + elements::{Module, ValueType}, +}; fn validate(wat: &str) -> CompiledModule { let wasm = wat::parse_str(wat).unwrap(); @@ -81,7 +84,7 @@ fn implicit_return_with_value() { isa::Instruction::I32Const(0), isa::Instruction::Return(isa::DropKeep { drop: 0, - keep: isa::Keep::Single, + keep: isa::Keep::Single(ValueType::I32), }), ] ) @@ -122,10 +125,10 @@ fn get_local() { assert_eq!( code, vec![ - isa::Instruction::GetLocal(1), + isa::Instruction::GetLocal(1, ValueType::I32), isa::Instruction::Return(isa::DropKeep { drop: 1, - keep: isa::Keep::Single, + keep: isa::Keep::Single(ValueType::I32), }), ] ) @@ -148,12 +151,12 @@ fn get_local_2() { assert_eq!( code, vec![ - isa::Instruction::GetLocal(2), - isa::Instruction::GetLocal(2), + isa::Instruction::GetLocal(2, ValueType::I32), + isa::Instruction::GetLocal(2, ValueType::I32), isa::Instruction::Drop, isa::Instruction::Return(isa::DropKeep { drop: 2, - keep: isa::Keep::Single, + keep: isa::Keep::Single(ValueType::I32), }), ] ) @@ -175,14 +178,14 @@ fn explicit_return() { assert_eq!( code, vec![ - isa::Instruction::GetLocal(1), + isa::Instruction::GetLocal(1, ValueType::I32), isa::Instruction::Return(isa::DropKeep { drop: 1, - keep: isa::Keep::Single, + keep: isa::Keep::Single(ValueType::I32), }), isa::Instruction::Return(isa::DropKeep { drop: 1, - keep: isa::Keep::Single, + keep: isa::Keep::Single(ValueType::I32), }), ] ) @@ -210,12 +213,12 @@ fn add_params() { // takes the value below the previous one (i.e the second argument) and then, it increments // the stack pointer. And then the same thing hapens with the value below the previous one // (which happens to be the value loaded by the first get_local). - isa::Instruction::GetLocal(2), - isa::Instruction::GetLocal(2), + isa::Instruction::GetLocal(2, ValueType::I32), + isa::Instruction::GetLocal(2, ValueType::I32), isa::Instruction::I32Add, isa::Instruction::Return(isa::DropKeep { drop: 2, - keep: isa::Keep::Single, + keep: isa::Keep::Single(ValueType::I32), }), ] ) @@ -238,8 +241,8 @@ fn drop_locals() { assert_eq!( code, vec![ - isa::Instruction::GetLocal(2), - isa::Instruction::SetLocal(1), + isa::Instruction::GetLocal(2, ValueType::I32), + isa::Instruction::SetLocal(1, ValueType::I32), isa::Instruction::Return(isa::DropKeep { drop: 2, keep: isa::Keep::None, @@ -279,12 +282,12 @@ fn if_without_else() { isa::Instruction::I32Const(2), isa::Instruction::Return(isa::DropKeep { drop: 1, // 1 param - keep: isa::Keep::Single, // 1 result + keep: isa::Keep::Single(ValueType::I32), // 1 result }), isa::Instruction::I32Const(3), isa::Instruction::Return(isa::DropKeep { drop: 1, - keep: isa::Keep::Single, + keep: isa::Keep::Single(ValueType::I32), }), ] ) @@ -322,7 +325,7 @@ fn if_else() { }, }), isa::Instruction::I32Const(2), - isa::Instruction::SetLocal(1), + isa::Instruction::SetLocal(1, ValueType::I32), isa::Instruction::Br(isa::Target { dst_pc: pcs[7], drop_keep: isa::DropKeep { @@ -331,7 +334,7 @@ fn if_else() { }, }), isa::Instruction::I32Const(3), - isa::Instruction::SetLocal(1), + isa::Instruction::SetLocal(1, ValueType::I32), isa::Instruction::Return(isa::DropKeep { drop: 1, keep: isa::Keep::None, @@ -426,7 +429,7 @@ fn if_else_branch_from_true_branch() { dst_pc: pcs[9], drop_keep: isa::DropKeep { drop: 0, - keep: isa::Keep::Single, + keep: isa::Keep::Single(ValueType::I32), }, }), isa::Instruction::Drop, @@ -495,7 +498,7 @@ fn if_else_branch_from_false_branch() { dst_pc: pcs[9], drop_keep: isa::DropKeep { drop: 0, - keep: isa::Keep::Single, + keep: isa::Keep::Single(ValueType::I32), }, }), isa::Instruction::Drop, @@ -603,14 +606,14 @@ fn spec_as_br_if_value_cond() { dst_pc: 9, drop_keep: isa::DropKeep { drop: 1, - keep: isa::Keep::Single + keep: isa::Keep::Single(ValueType::I32) } }, isa::Target { dst_pc: 9, drop_keep: isa::DropKeep { drop: 1, - keep: isa::Keep::Single + keep: isa::Keep::Single(ValueType::I32) } } ]), @@ -618,14 +621,14 @@ fn spec_as_br_if_value_cond() { dst_pc: 9, drop_keep: isa::DropKeep { drop: 0, - keep: isa::Keep::Single + keep: isa::Keep::Single(ValueType::I32) } }), Drop, I32Const(7), Return(isa::DropKeep { drop: 0, - keep: isa::Keep::Single + keep: isa::Keep::Single(ValueType::I32) }) ] ); @@ -707,13 +710,13 @@ fn brtable_returns_result() { dst_pc: pcs[3], drop_keep: isa::DropKeep { drop: 0, - keep: isa::Keep::Single, + keep: isa::Keep::Single(ValueType::I32), }, }, isa::Target { dst_pc: pcs[4], drop_keep: isa::DropKeep { - keep: isa::Keep::Single, + keep: isa::Keep::Single(ValueType::I32), drop: 0, }, } @@ -750,7 +753,7 @@ fn wabt_example() { assert_eq!( code, vec![ - isa::Instruction::GetLocal(1), + isa::Instruction::GetLocal(1, ValueType::I32), isa::Instruction::BrIfNez(isa::Target { dst_pc: pcs[4], drop_keep: isa::DropKeep { @@ -761,16 +764,16 @@ fn wabt_example() { isa::Instruction::I32Const(1), isa::Instruction::Return(isa::DropKeep { drop: 1, // 1 parameter - keep: isa::Keep::Single, + keep: isa::Keep::Single(ValueType::I32), }), isa::Instruction::I32Const(2), isa::Instruction::Return(isa::DropKeep { drop: 1, - keep: isa::Keep::Single, + keep: isa::Keep::Single(ValueType::I32), }), isa::Instruction::Return(isa::DropKeep { drop: 1, - keep: isa::Keep::Single, + keep: isa::Keep::Single(ValueType::I32), }), ] ) From 023827b32684baaf87b03f9055e05df8a700c58e Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Fri, 15 Jul 2022 14:50:54 +0800 Subject: [PATCH 018/129] remove print --- src/module.rs | 1 - src/prepare/compile.rs | 1 - 2 files changed, 2 deletions(-) diff --git a/src/module.rs b/src/module.rs index 81cd77babd..19d6fd1fae 100644 --- a/src/module.rs +++ b/src/module.rs @@ -642,7 +642,6 @@ impl ModuleInstance { externals: &mut E, ) -> Result, Error> { let func_instance = self.func_by_name(func_name)?; - println!("{:?}", func_instance.body()); FuncInstance::invoke(&func_instance, args, externals).map_err(Error::Trap) } diff --git a/src/prepare/compile.rs b/src/prepare/compile.rs index 03d4a9b9f2..3cd0b0e5e3 100644 --- a/src/prepare/compile.rs +++ b/src/prepare/compile.rs @@ -1143,7 +1143,6 @@ fn relative_local_depth_type( locals: &Locals, value_stack: &StackWithLimit, ) -> Result<(u32, ValueType), Error> { - println!("idx: {} , locals {:?}", idx, locals.count()); let value_stack_height = value_stack.len() as u32; let locals_and_params_count = locals.count(); From 788122feb25c3a1c04a38fd9f937ee77d4addd7b Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Fri, 15 Jul 2022 16:19:13 +0800 Subject: [PATCH 019/129] adapt sp, mmid --- src/runner.rs | 3 ++- src/tracer/etable.rs | 38 +++++++++++++++++++++++++++++++------- src/tracer/mod.rs | 30 +++++++++++++++++++----------- 3 files changed, 52 insertions(+), 19 deletions(-) diff --git a/src/runner.rs b/src/runner.rs index a59658ed85..f5a9f64aef 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -33,7 +33,8 @@ use std::rc::Rc; use validation::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX}; /// Maximum number of bytes on the value stack. -pub const DEFAULT_VALUE_STACK_LIMIT: usize = 1024 * 1024; +/// wasmi's default value is 1024 * 1024, we set 4096 to adapt zkWasm +pub const DEFAULT_VALUE_STACK_LIMIT: usize = 4096; /// Maximum number of levels on the call stack. pub const DEFAULT_CALL_STACK_LIMIT: usize = 64 * 1024; diff --git a/src/tracer/etable.rs b/src/tracer/etable.rs index 4c150b199c..51b6cc9a79 100644 --- a/src/tracer/etable.rs +++ b/src/tracer/etable.rs @@ -1,7 +1,7 @@ use parity_wasm::elements::ValueType; use specs::{etable::EventTableEntry, itable::Opcode, step::StepInfo}; -use crate::runner::ValueInternal; +use crate::{runner::ValueInternal, DEFAULT_VALUE_STACK_LIMIT}; use super::itable::IEntry; @@ -44,7 +44,11 @@ impl Into for EEntry { fn into(self) -> EventTableEntry { EventTableEntry { eid: self.id, - sp: self.sp, + sp: (DEFAULT_VALUE_STACK_LIMIT as u64) + .checked_sub(self.sp) + .unwrap() + .checked_sub(1) + .unwrap(), last_jump_eid: self.last_jump_eid, inst: self.inst.into(), step_info: self.step.clone(), @@ -53,18 +57,38 @@ impl Into for EEntry { } #[derive(Debug)] -pub struct ETable(pub Vec); +pub struct ETable { + eid: u64, + entries: Vec, +} impl Default for ETable { fn default() -> Self { - Self(Default::default()) + Self { + eid: 1, + entries: vec![], + } } } impl ETable { + pub fn get_latest_eid(&self) -> u64 { + self.entries.last().unwrap().id + } + + pub fn get_entries(&self) -> &Vec { + &self.entries + } + + fn allocate_eid(&mut self) -> u64 { + let r = self.eid; + self.eid = r + 1; + return r; + } + pub fn push( &mut self, - module_instance_index: u32, + module_instance_index: u16, func_index: u32, sp: u64, pc: u32, @@ -73,7 +97,7 @@ impl ETable { step: StepInfo, ) -> EEntry { let eentry = EEntry { - id: self.0.len() as u64, + id: self.allocate_eid(), sp, last_jump_eid, inst: IEntry { @@ -85,7 +109,7 @@ impl ETable { step, }; - self.0.push(eentry.clone()); + self.entries.push(eentry.clone()); eentry } diff --git a/src/tracer/mod.rs b/src/tracer/mod.rs index 75add8068a..94d7e93e1b 100644 --- a/src/tracer/mod.rs +++ b/src/tracer/mod.rs @@ -15,8 +15,8 @@ pub struct Tracer { pub itable: ITable, pub etable: ETable, pub jtable: Option, - pub(crate) module_instance_lookup: Vec, - pub(crate) function_lookup: Vec<(FuncRef, u32)>, + module_instance_lookup: Vec<(ModuleRef, u16)>, + function_lookup: Vec<(FuncRef, u32)>, last_jump_eid: Vec, } @@ -34,19 +34,23 @@ impl Tracer { } pub fn push_frame(&mut self) { - self.last_jump_eid.push(self.etable.0.last().unwrap().id); + self.last_jump_eid.push(self.etable.get_latest_eid()); } pub fn pop_frame(&mut self) { self.last_jump_eid.pop().unwrap(); } + pub fn next_module_id(&self) -> u16 { + (self.module_instance_lookup.len() as u16) + 1 + } + pub fn last_jump_eid(&self) -> u64 { *self.last_jump_eid.last().unwrap() } pub fn eid(&self) -> u64 { - self.etable.0.last().unwrap().id + self.etable.get_latest_eid() } } @@ -63,7 +67,7 @@ impl Tracer { let pc = iter.position(); if let Some(instruction) = iter.next() { let ientry = self.itable.push( - self.module_instance_lookup.len() as u32, + self.next_module_id() as u32, func_index, pc, instruction.into(), @@ -84,14 +88,18 @@ impl Tracer { } } - self.module_instance_lookup.push(module_instance.clone()); + self.module_instance_lookup + .push((module_instance.clone(), self.next_module_id())); } - pub fn lookup_module_instance(&self, module_instance: &ModuleRef) -> u32 { - self.module_instance_lookup - .iter() - .position(|m| m == module_instance) - .unwrap() as u32 + pub fn lookup_module_instance(&self, module_instance: &ModuleRef) -> u16 { + for m in &self.module_instance_lookup { + if &m.0 == module_instance { + return m.1; + } + } + + unreachable!() } pub fn lookup_function(&self, function: &FuncRef) -> u32 { From 9587ddbd1ab1d5d296e93d9c6c303eb1402aa598 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Fri, 15 Jul 2022 17:05:46 +0800 Subject: [PATCH 020/129] fid starts from 1 --- src/tracer/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tracer/mod.rs b/src/tracer/mod.rs index 94d7e93e1b..14be2675f0 100644 --- a/src/tracer/mod.rs +++ b/src/tracer/mod.rs @@ -68,7 +68,7 @@ impl Tracer { if let Some(instruction) = iter.next() { let ientry = self.itable.push( self.next_module_id() as u32, - func_index, + func_index + 1, pc, instruction.into(), ); @@ -82,7 +82,7 @@ impl Tracer { } func_index = func_index + 1; - self.function_lookup.push((func.clone(), func_index)) + self.function_lookup.push((func.clone(), func_index + 1)) } else { break; } From 9d10882056900ad090262da864e79384c365fd93 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Fri, 15 Jul 2022 17:29:57 +0800 Subject: [PATCH 021/129] bugfix: incr func_index correctly --- src/tracer/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tracer/mod.rs b/src/tracer/mod.rs index 14be2675f0..d23e3aa8da 100644 --- a/src/tracer/mod.rs +++ b/src/tracer/mod.rs @@ -81,8 +81,8 @@ impl Tracer { } } + self.function_lookup.push((func.clone(), func_index + 1)); func_index = func_index + 1; - self.function_lookup.push((func.clone(), func_index + 1)) } else { break; } From 5c7ea9b54a4b0c5daebc6840b3999c6daec071f0 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Sat, 16 Jul 2022 21:16:24 +0800 Subject: [PATCH 022/129] bugfix: set the index of start function to zero --- src/prepare/compile.rs | 2 +- src/runner.rs | 6 +++--- src/tracer/mod.rs | 24 ++++++++++++++++++++---- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/prepare/compile.rs b/src/prepare/compile.rs index 3cd0b0e5e3..831b45535a 100644 --- a/src/prepare/compile.rs +++ b/src/prepare/compile.rs @@ -1119,7 +1119,7 @@ fn drop_keep_return( /// by `idx`. /// /// See stack layout definition in mod isa. -fn relative_local_depth( +fn _relative_local_depth( idx: u32, locals: &Locals, value_stack: &StackWithLimit, diff --git a/src/runner.rs b/src/runner.rs index f5a9f64aef..58871612c1 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -26,7 +26,7 @@ use crate::{ ValueType, }; use alloc::{boxed::Box, vec::Vec}; -use core::{borrow::Borrow, cell::RefCell, fmt, ops, u32, usize}; +use core::{cell::RefCell, fmt, ops, u32, usize}; use parity_wasm::elements::Local; use specs::{step::StepInfo, types::Value}; use std::rc::Rc; @@ -579,7 +579,7 @@ impl Interpreter { None } }; - }; + } match self.run_instruction(function_context, &instruction)? { InstructionOutcome::RunNextInstruction => { @@ -592,7 +592,7 @@ impl Interpreter { } InstructionOutcome::ExecuteCall(func_ref) => { // We don't record updated pc, the value should be recorded in the next trace log. - let eentry = trace_post!(); + trace_post!(); function_context.position = iter.position(); return Ok(RunResult::NestedCall(func_ref)); diff --git a/src/tracer/mod.rs b/src/tracer/mod.rs index d23e3aa8da..67d4409593 100644 --- a/src/tracer/mod.rs +++ b/src/tracer/mod.rs @@ -1,4 +1,4 @@ -use crate::{FuncRef, ModuleRef}; +use crate::{FuncRef, Module, ModuleRef}; use self::{ etable::ETable, @@ -18,6 +18,7 @@ pub struct Tracer { module_instance_lookup: Vec<(ModuleRef, u16)>, function_lookup: Vec<(FuncRef, u32)>, last_jump_eid: Vec, + function_index_allocator: u32, } impl Tracer { @@ -30,6 +31,7 @@ impl Tracer { jtable: None, module_instance_lookup: vec![], function_lookup: vec![], + function_index_allocator: 1, } } @@ -52,14 +54,27 @@ impl Tracer { pub fn eid(&self) -> u64 { self.etable.get_latest_eid() } + + fn allocate_func_index(&mut self) -> u32 { + let r = self.function_index_allocator; + self.function_index_allocator = r + 1; + r + } } impl Tracer { - pub fn register_module_instance(&mut self, module_instance: &ModuleRef) { + pub fn register_module_instance(&mut self, module: &Module, module_instance: &ModuleRef) { let mut func_index = 0; + let start_fn_idx = module.module().start_section(); + loop { if let Some(func) = module_instance.func_by_index(func_index) { + let func_index_in_itable = if Some(func_index) == start_fn_idx { + 0 + } else { + self.allocate_func_index() + }; let body = func.body().expect("Host function is not allowed"); let code = &body.code; let mut iter = code.iterate_from(0); @@ -68,7 +83,7 @@ impl Tracer { if let Some(instruction) = iter.next() { let ientry = self.itable.push( self.next_module_id() as u32, - func_index + 1, + func_index_in_itable, pc, instruction.into(), ); @@ -81,7 +96,8 @@ impl Tracer { } } - self.function_lookup.push((func.clone(), func_index + 1)); + self.function_lookup + .push((func.clone(), func_index_in_itable)); func_index = func_index + 1; } else { break; From 851f59721156b2bf188d38ef0032f8208ae243f1 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Mon, 18 Jul 2022 11:38:37 +0800 Subject: [PATCH 023/129] add i32const --- src/isa.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/isa.rs b/src/isa.rs index b6969717a7..9fa453f875 100644 --- a/src/isa.rs +++ b/src/isa.rs @@ -69,7 +69,7 @@ use alloc::vec::Vec; use parity_wasm::elements::ValueType; -use specs::{itable::Opcode, mtable::VarType}; +use specs::{itable::{Opcode, BinOp}, mtable::VarType}; /// Should we keep a value before "discarding" a stack frame? /// @@ -443,7 +443,10 @@ impl<'a> Into for Instruction<'a> { Instruction::I32Clz => todo!(), Instruction::I32Ctz => todo!(), Instruction::I32Popcnt => todo!(), - Instruction::I32Add => todo!(), + Instruction::I32Add => Opcode::Bin { + class: BinOp::Add, + vtype: VarType::I32, + }, Instruction::I32Sub => todo!(), Instruction::I32Mul => todo!(), Instruction::I32DivS => todo!(), From b518a3bc3e18da8e459ebb966f4ff43932b6a809 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Mon, 18 Jul 2022 12:08:23 +0800 Subject: [PATCH 024/129] add i32or, i32ne supporting --- src/isa.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/isa.rs b/src/isa.rs index 9fa453f875..fa0a71bf3c 100644 --- a/src/isa.rs +++ b/src/isa.rs @@ -69,7 +69,10 @@ use alloc::vec::Vec; use parity_wasm::elements::ValueType; -use specs::{itable::{Opcode, BinOp}, mtable::VarType}; +use specs::{ + itable::{BinOp, Opcode, RelOp}, + mtable::VarType, +}; /// Should we keep a value before "discarding" a stack frame? /// @@ -408,7 +411,10 @@ impl<'a> Into for Instruction<'a> { Instruction::F64Const(_) => todo!(), Instruction::I32Eqz => todo!(), Instruction::I32Eq => todo!(), - Instruction::I32Ne => todo!(), + Instruction::I32Ne => Opcode::Rel { + class: RelOp::Ne, + vtype: VarType::I32, + }, Instruction::I32LtS => todo!(), Instruction::I32LtU => todo!(), Instruction::I32GtS => todo!(), @@ -454,7 +460,10 @@ impl<'a> Into for Instruction<'a> { Instruction::I32RemS => todo!(), Instruction::I32RemU => todo!(), Instruction::I32And => todo!(), - Instruction::I32Or => todo!(), + Instruction::I32Or => Opcode::Bin { + class: BinOp::Or, + vtype: VarType::I32, + }, Instruction::I32Xor => todo!(), Instruction::I32Shl => todo!(), Instruction::I32ShrS => todo!(), From 0ba38331445b3d247a0f58c50c1bfe1e92cc6679 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Mon, 18 Jul 2022 14:42:05 +0800 Subject: [PATCH 025/129] add call op --- src/isa.rs | 20 ++++++++-- src/runner.rs | 27 ++++++++++++- src/tracer/etable.rs | 4 +- src/tracer/itable.rs | 4 +- src/tracer/mod.rs | 91 +++++++++++++++++++++++++++----------------- 5 files changed, 102 insertions(+), 44 deletions(-) diff --git a/src/isa.rs b/src/isa.rs index fa0a71bf3c..8239b0f562 100644 --- a/src/isa.rs +++ b/src/isa.rs @@ -67,6 +67,8 @@ //! - Reserved immediates are ignored for `call_indirect`, `current_memory`, `grow_memory`. //! +use std::collections::HashMap; + use alloc::vec::Vec; use parity_wasm::elements::ValueType; use specs::{ @@ -346,8 +348,8 @@ pub enum Instruction<'a> { F64ReinterpretI64, } -impl<'a> Into for Instruction<'a> { - fn into(self) -> Opcode { +impl<'a> Instruction<'a> { + pub fn into(self, function_mapping: &HashMap) -> Opcode { match self { Instruction::GetLocal(offset, typ) => Opcode::LocalGet { offset: offset as u64, @@ -357,7 +359,15 @@ impl<'a> Into for Instruction<'a> { Instruction::TeeLocal(..) => todo!(), Instruction::Br(_) => todo!(), Instruction::BrIfEqz(_) => todo!(), - Instruction::BrIfNez(_) => todo!(), + Instruction::BrIfNez(Target { dst_pc, drop_keep }) => Opcode::BrIf { + drop: drop_keep.drop, + keep: if let Keep::Single(t) = drop_keep.keep { + vec![t.into()] + } else { + vec![] + }, + dst_pc, + }, Instruction::BrTable(_) => todo!(), Instruction::Unreachable => todo!(), Instruction::Return(drop_keep) => Opcode::Return { @@ -368,7 +378,9 @@ impl<'a> Into for Instruction<'a> { vec![] }, }, - Instruction::Call(_) => todo!(), + Instruction::Call(func_index) => Opcode::Call { + index: *function_mapping.get(&func_index).unwrap(), + }, Instruction::CallIndirect(_) => todo!(), Instruction::Drop => Opcode::Drop, Instruction::Select => todo!(), diff --git a/src/runner.rs b/src/runner.rs index 58871612c1..0994bd8b07 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -477,7 +477,25 @@ impl Interpreter { unreachable!() } } - isa::Instruction::Call(index) => StepInfo::Call { index }, + isa::Instruction::Call(index) => { + let function_context = self.call_stack.pop().expect( + "on loop entry - not empty; on loop continue - checking for emptiness; qed", + ); + + let func = function_context + .module() + .func_by_index(index) + .expect("Due to validation func should exists"); + + self.call_stack.push(function_context); + + if let Some(tracer) = self.tracer.as_deref() { + let index = tracer.borrow().lookup_function(&func); + StepInfo::Call { index } + } else { + unreachable!() + } + } isa::Instruction::GetLocal(..) => { if let RunInstructionTracePre::GetLocal { @@ -555,6 +573,11 @@ impl Interpreter { if self.tracer.is_some() { let post_status = self.run_instruction_post(pre_status, &instruction); if let Some(tracer) = self.tracer.as_mut() { + let instruction = { + let tracer = tracer.borrow(); + instruction.into(&tracer.function_index_translation) + }; + let mut tracer = tracer.borrow_mut(); let module_instance = tracer.lookup_module_instance(&function_context.module); @@ -569,7 +592,7 @@ impl Interpreter { sp as u64, pc, last_jump_eid, - instruction.into(), + instruction, post_status, )) } else { diff --git a/src/tracer/etable.rs b/src/tracer/etable.rs index 51b6cc9a79..6dbf3a36f4 100644 --- a/src/tracer/etable.rs +++ b/src/tracer/etable.rs @@ -89,7 +89,7 @@ impl ETable { pub fn push( &mut self, module_instance_index: u16, - func_index: u32, + func_index: u16, sp: u64, pc: u32, last_jump_eid: u64, @@ -102,7 +102,7 @@ impl ETable { last_jump_eid, inst: IEntry { module_instance_index: module_instance_index as u16, - func_index: func_index as u16, + func_index, pc: pc as u16, opcode, }, diff --git a/src/tracer/itable.rs b/src/tracer/itable.rs index 50ab914dcd..4a25807bdb 100644 --- a/src/tracer/itable.rs +++ b/src/tracer/itable.rs @@ -35,13 +35,13 @@ impl ITable { pub(crate) fn push( &mut self, module_instance_index: u32, - func_index: u32, + func_index: u16, pc: u32, opcode: Opcode, ) -> IEntry { let ientry = IEntry { module_instance_index: module_instance_index as u16, - func_index: func_index as u16, + func_index, pc: pc as u16, opcode, }; diff --git a/src/tracer/mod.rs b/src/tracer/mod.rs index 67d4409593..ca76ec6c05 100644 --- a/src/tracer/mod.rs +++ b/src/tracer/mod.rs @@ -1,3 +1,5 @@ +use std::collections::HashMap; + use crate::{FuncRef, Module, ModuleRef}; use self::{ @@ -16,9 +18,10 @@ pub struct Tracer { pub etable: ETable, pub jtable: Option, module_instance_lookup: Vec<(ModuleRef, u16)>, - function_lookup: Vec<(FuncRef, u32)>, + function_lookup: Vec<(FuncRef, u16)>, last_jump_eid: Vec, function_index_allocator: u32, + pub function_index_translation: HashMap, } impl Tracer { @@ -32,6 +35,7 @@ impl Tracer { module_instance_lookup: vec![], function_lookup: vec![], function_index_allocator: 1, + function_index_translation: Default::default(), } } @@ -64,43 +68,62 @@ impl Tracer { impl Tracer { pub fn register_module_instance(&mut self, module: &Module, module_instance: &ModuleRef) { - let mut func_index = 0; - let start_fn_idx = module.module().start_section(); - loop { - if let Some(func) = module_instance.func_by_index(func_index) { - let func_index_in_itable = if Some(func_index) == start_fn_idx { - 0 + { + let mut func_index = 0; + + loop { + if let Some(func) = module_instance.func_by_index(func_index) { + let func_index_in_itable = if Some(func_index) == start_fn_idx { + 0 + } else { + self.allocate_func_index() + }; + + self.function_lookup + .push((func.clone(), func_index_in_itable as u16)); + self.function_index_translation + .insert(func_index, func_index_in_itable as u16); + func_index = func_index + 1; } else { - self.allocate_func_index() - }; - let body = func.body().expect("Host function is not allowed"); - let code = &body.code; - let mut iter = code.iterate_from(0); - loop { - let pc = iter.position(); - if let Some(instruction) = iter.next() { - let ientry = self.itable.push( - self.next_module_id() as u32, - func_index_in_itable, - pc, - instruction.into(), - ); - - if self.jtable.is_none() { - self.jtable = Some(JTable::new(&ientry)) + break; + } + } + } + + { + let mut func_index = 0; + + loop { + if let Some(func) = module_instance.func_by_index(func_index) { + let func_index_in_itable = + self.function_index_translation.get(&func_index).unwrap(); + let body = func.body().expect("Host function is not allowed"); + let code = &body.code; + let mut iter = code.iterate_from(0); + loop { + let pc = iter.position(); + if let Some(instruction) = iter.next() { + let ientry = self.itable.push( + self.next_module_id() as u32, + *func_index_in_itable, + pc, + instruction.into(&self.function_index_translation), + ); + + if self.jtable.is_none() { + self.jtable = Some(JTable::new(&ientry)) + } + } else { + break; } - } else { - break; } - } - self.function_lookup - .push((func.clone(), func_index_in_itable)); - func_index = func_index + 1; - } else { - break; + func_index = func_index + 1; + } else { + break; + } } } @@ -118,7 +141,7 @@ impl Tracer { unreachable!() } - pub fn lookup_function(&self, function: &FuncRef) -> u32 { + pub fn lookup_function(&self, function: &FuncRef) -> u16 { let pos = self .function_lookup .iter() @@ -131,7 +154,7 @@ impl Tracer { let function_idx = self.lookup_function(function); for ientry in &self.itable.0 { - if ientry.func_index as u32 == function_idx { + if ientry.func_index as u16 == function_idx { return ientry.clone(); } } From 9e855cf1574b3a8a754937c6e490a238f4fe2d29 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Mon, 18 Jul 2022 15:32:05 +0800 Subject: [PATCH 026/129] bugfix: fix func tranlation --- src/runner.rs | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/src/runner.rs b/src/runner.rs index 0994bd8b07..a02f4a514d 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -478,20 +478,14 @@ impl Interpreter { } } isa::Instruction::Call(index) => { - let function_context = self.call_stack.pop().expect( - "on loop entry - not empty; on loop continue - checking for emptiness; qed", - ); - - let func = function_context - .module() - .func_by_index(index) - .expect("Due to validation func should exists"); - - self.call_stack.push(function_context); - if let Some(tracer) = self.tracer.as_deref() { - let index = tracer.borrow().lookup_function(&func); - StepInfo::Call { index } + StepInfo::Call { + index: *tracer + .borrow() + .function_index_translation + .get(&index) + .unwrap(), + } } else { unreachable!() } From 77341018b18349a2d57d8c3f3c14de673df99af1 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Mon, 18 Jul 2022 15:53:50 +0800 Subject: [PATCH 027/129] bugfix: read top of valuestack correctly --- src/runner.rs | 28 ++++++++++++---------------- src/tracer/etable.rs | 4 +--- 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/src/runner.rs b/src/runner.rs index a02f4a514d..15f5ecf05b 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -393,13 +393,11 @@ impl Interpreter { ) -> Option { match *instructions { isa::Instruction::BrIfNez(_) => Some(RunInstructionTracePre::BrIfNez { - value: <_>::from_value_internal(*self.value_stack.pick(0)), + value: <_>::from_value_internal(*self.value_stack.top()), }), isa::Instruction::Return(..) => None, - isa::Instruction::Drop => Some(RunInstructionTracePre::Drop { - value: <_>::from_value_internal(*self.value_stack.pick(0)), - }), + isa::Instruction::Drop => Some(RunInstructionTracePre::Drop), isa::Instruction::Call(_) => None, isa::Instruction::GetLocal(depth, vtype) => { @@ -413,14 +411,14 @@ impl Interpreter { isa::Instruction::I32Const(_) => None, isa::Instruction::I32Ne => Some(RunInstructionTracePre::I32Comp { - left: <_>::from_value_internal(*self.value_stack.pick(1)), - right: <_>::from_value_internal(*self.value_stack.pick(0)), + left: <_>::from_value_internal(*self.value_stack.pick(2)), + right: <_>::from_value_internal(*self.value_stack.pick(1)), }), isa::Instruction::I32Add | isa::Instruction::I32Or => { Some(RunInstructionTracePre::I32BinOp { - left: <_>::from_value_internal(*self.value_stack.pick(1)), - right: <_>::from_value_internal(*self.value_stack.pick(0)), + left: <_>::from_value_internal(*self.value_stack.pick(2)), + right: <_>::from_value_internal(*self.value_stack.pick(1)), }) } @@ -451,7 +449,7 @@ impl Interpreter { isa::Instruction::Return(DropKeep { drop, keep }) => { let mut drop_values = vec![]; - for i in 0..drop { + for i in 1..=drop { drop_values.push(*self.value_stack.pick(i as usize)); } @@ -471,8 +469,8 @@ impl Interpreter { } isa::Instruction::Drop => { - if let RunInstructionTracePre::Drop { value } = pre_status.unwrap() { - StepInfo::Drop { value: value } + if let RunInstructionTracePre::Drop = pre_status.unwrap() { + StepInfo::Drop } else { unreachable!() } @@ -508,16 +506,14 @@ impl Interpreter { } } - isa::Instruction::I32Const(_) => StepInfo::I32Const { - value: <_>::from_value_internal(*self.value_stack.pick(0)), - }, + isa::Instruction::I32Const(value) => StepInfo::I32Const { value }, isa::Instruction::I32Ne => { if let RunInstructionTracePre::I32Comp { left, right } = pre_status.unwrap() { StepInfo::I32Comp { left, right, - value: <_>::from_value_internal(*self.value_stack.pick(0)), + value: <_>::from_value_internal(*self.value_stack.top()), } } else { unreachable!() @@ -529,7 +525,7 @@ impl Interpreter { StepInfo::I32BinOp { left, right, - value: <_>::from_value_internal(*self.value_stack.pick(0)), + value: <_>::from_value_internal(*self.value_stack.top()), } } else { unreachable!() diff --git a/src/tracer/etable.rs b/src/tracer/etable.rs index 6dbf3a36f4..6bfe1adc69 100644 --- a/src/tracer/etable.rs +++ b/src/tracer/etable.rs @@ -26,9 +26,7 @@ pub enum RunInstructionTracePre { right: i32, }, - Drop { - value: u64, - }, + Drop, } #[derive(Debug, Clone)] From 92fa01111d262ad2f272e506d859a48736e0085a Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Tue, 19 Jul 2022 11:47:17 +0800 Subject: [PATCH 028/129] add inst type for binop --- src/runner.rs | 22 ++++++++++++++-------- src/tracer/etable.rs | 3 ++- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/runner.rs b/src/runner.rs index 15f5ecf05b..bf2bf8b91f 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -28,7 +28,7 @@ use crate::{ use alloc::{boxed::Box, vec::Vec}; use core::{cell::RefCell, fmt, ops, u32, usize}; use parity_wasm::elements::Local; -use specs::{step::StepInfo, types::Value}; +use specs::{itable::BinOp, step::StepInfo, types::Value}; use std::rc::Rc; use validation::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX}; @@ -415,12 +415,16 @@ impl Interpreter { right: <_>::from_value_internal(*self.value_stack.pick(1)), }), - isa::Instruction::I32Add | isa::Instruction::I32Or => { - Some(RunInstructionTracePre::I32BinOp { - left: <_>::from_value_internal(*self.value_stack.pick(2)), - right: <_>::from_value_internal(*self.value_stack.pick(1)), - }) - } + isa::Instruction::I32Add => Some(RunInstructionTracePre::I32BinOp { + class: BinOp::Add, + left: <_>::from_value_internal(*self.value_stack.pick(2)), + right: <_>::from_value_internal(*self.value_stack.pick(1)), + }), + isa::Instruction::I32Or => Some(RunInstructionTracePre::I32BinOp { + class: BinOp::Or, + left: <_>::from_value_internal(*self.value_stack.pick(2)), + right: <_>::from_value_internal(*self.value_stack.pick(1)), + }), _ => { println!("{:?}", *instructions); @@ -521,8 +525,10 @@ impl Interpreter { } isa::Instruction::I32Add | isa::Instruction::I32Or => { - if let RunInstructionTracePre::I32BinOp { left, right } = pre_status.unwrap() { + if let RunInstructionTracePre::I32BinOp { class, left, right } = pre_status.unwrap() + { StepInfo::I32BinOp { + class, left, right, value: <_>::from_value_internal(*self.value_stack.top()), diff --git a/src/tracer/etable.rs b/src/tracer/etable.rs index 6bfe1adc69..5be82eb61b 100644 --- a/src/tracer/etable.rs +++ b/src/tracer/etable.rs @@ -1,5 +1,5 @@ use parity_wasm::elements::ValueType; -use specs::{etable::EventTableEntry, itable::Opcode, step::StepInfo}; +use specs::{etable::EventTableEntry, itable::{Opcode, BinOp}, step::StepInfo}; use crate::{runner::ValueInternal, DEFAULT_VALUE_STACK_LIMIT}; @@ -17,6 +17,7 @@ pub enum RunInstructionTracePre { }, I32BinOp { + class: BinOp, left: i32, right: i32, }, From 614a8b73c022f712b3602946a5303ca634e9d95e Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Tue, 19 Jul 2022 14:13:47 +0800 Subject: [PATCH 029/129] adapt zkWasm --- src/isa.rs | 6 +++--- src/runner.rs | 26 ++++++++++++++++++++++---- src/tracer/etable.rs | 11 ++++++++++- 3 files changed, 35 insertions(+), 8 deletions(-) diff --git a/src/isa.rs b/src/isa.rs index 8239b0f562..33d1c60d13 100644 --- a/src/isa.rs +++ b/src/isa.rs @@ -72,7 +72,7 @@ use std::collections::HashMap; use alloc::vec::Vec; use parity_wasm::elements::ValueType; use specs::{ - itable::{BinOp, Opcode, RelOp}, + itable::{BinOp, BitOp, Opcode, RelOp}, mtable::VarType, }; @@ -472,8 +472,8 @@ impl<'a> Instruction<'a> { Instruction::I32RemS => todo!(), Instruction::I32RemU => todo!(), Instruction::I32And => todo!(), - Instruction::I32Or => Opcode::Bin { - class: BinOp::Or, + Instruction::I32Or => Opcode::BinBit { + class: BitOp::Or, vtype: VarType::I32, }, Instruction::I32Xor => todo!(), diff --git a/src/runner.rs b/src/runner.rs index bf2bf8b91f..e4f291cb42 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -28,7 +28,11 @@ use crate::{ use alloc::{boxed::Box, vec::Vec}; use core::{cell::RefCell, fmt, ops, u32, usize}; use parity_wasm::elements::Local; -use specs::{itable::BinOp, step::StepInfo, types::Value}; +use specs::{ + itable::{BinOp, BitOp}, + step::StepInfo, + types::Value, +}; use std::rc::Rc; use validation::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX}; @@ -420,8 +424,8 @@ impl Interpreter { left: <_>::from_value_internal(*self.value_stack.pick(2)), right: <_>::from_value_internal(*self.value_stack.pick(1)), }), - isa::Instruction::I32Or => Some(RunInstructionTracePre::I32BinOp { - class: BinOp::Or, + isa::Instruction::I32Or => Some(RunInstructionTracePre::I32BinBitOp { + class: BitOp::Or, left: <_>::from_value_internal(*self.value_stack.pick(2)), right: <_>::from_value_internal(*self.value_stack.pick(1)), }), @@ -524,7 +528,7 @@ impl Interpreter { } } - isa::Instruction::I32Add | isa::Instruction::I32Or => { + isa::Instruction::I32Add => { if let RunInstructionTracePre::I32BinOp { class, left, right } = pre_status.unwrap() { StepInfo::I32BinOp { @@ -537,6 +541,20 @@ impl Interpreter { unreachable!() } } + isa::Instruction::I32Or => { + if let RunInstructionTracePre::I32BinBitOp { class, left, right } = + pre_status.unwrap() + { + StepInfo::I32BinBitOp { + class, + left, + right, + value: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } _ => unimplemented!(), } } diff --git a/src/tracer/etable.rs b/src/tracer/etable.rs index 5be82eb61b..136d9a9b15 100644 --- a/src/tracer/etable.rs +++ b/src/tracer/etable.rs @@ -1,5 +1,9 @@ use parity_wasm::elements::ValueType; -use specs::{etable::EventTableEntry, itable::{Opcode, BinOp}, step::StepInfo}; +use specs::{ + etable::EventTableEntry, + itable::{BinOp, BitOp, Opcode}, + step::StepInfo, +}; use crate::{runner::ValueInternal, DEFAULT_VALUE_STACK_LIMIT}; @@ -21,6 +25,11 @@ pub enum RunInstructionTracePre { left: i32, right: i32, }, + I32BinBitOp { + class: BitOp, + left: i32, + right: i32, + }, I32Comp { left: i32, From c7d09bf076ae94160a04faffc7eeb3f75714f531 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Wed, 20 Jul 2022 12:14:11 +0800 Subject: [PATCH 030/129] support i32.eq --- src/isa.rs | 5 ++++- src/runner.rs | 19 ++++++++++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/isa.rs b/src/isa.rs index 33d1c60d13..4307be380a 100644 --- a/src/isa.rs +++ b/src/isa.rs @@ -422,7 +422,10 @@ impl<'a> Instruction<'a> { Instruction::F32Const(_) => todo!(), Instruction::F64Const(_) => todo!(), Instruction::I32Eqz => todo!(), - Instruction::I32Eq => todo!(), + Instruction::I32Eq => Opcode::Rel { + class: RelOp::Eq, + vtype: VarType::I32, + }, Instruction::I32Ne => Opcode::Rel { class: RelOp::Ne, vtype: VarType::I32, diff --git a/src/runner.rs b/src/runner.rs index e4f291cb42..4ce87b6dc6 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -29,7 +29,7 @@ use alloc::{boxed::Box, vec::Vec}; use core::{cell::RefCell, fmt, ops, u32, usize}; use parity_wasm::elements::Local; use specs::{ - itable::{BinOp, BitOp}, + itable::{BinOp, BitOp, RelOp}, step::StepInfo, types::Value, }; @@ -414,6 +414,10 @@ impl Interpreter { } isa::Instruction::I32Const(_) => None, + isa::Instruction::I32Eq => Some(RunInstructionTracePre::I32Comp { + left: <_>::from_value_internal(*self.value_stack.pick(2)), + right: <_>::from_value_internal(*self.value_stack.pick(1)), + }), isa::Instruction::I32Ne => Some(RunInstructionTracePre::I32Comp { left: <_>::from_value_internal(*self.value_stack.pick(2)), right: <_>::from_value_internal(*self.value_stack.pick(1)), @@ -516,9 +520,22 @@ impl Interpreter { isa::Instruction::I32Const(value) => StepInfo::I32Const { value }, + isa::Instruction::I32Eq => { + if let RunInstructionTracePre::I32Comp { left, right } = pre_status.unwrap() { + StepInfo::I32Comp { + class: RelOp::Eq, + left, + right, + value: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } isa::Instruction::I32Ne => { if let RunInstructionTracePre::I32Comp { left, right } = pre_status.unwrap() { StepInfo::I32Comp { + class: RelOp::Ne, left, right, value: <_>::from_value_internal(*self.value_stack.top()), From 620c6147ecc61c16c8f92b6c7ad64236ca32de8b Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Wed, 20 Jul 2022 16:01:35 +0800 Subject: [PATCH 031/129] support br if --- src/runner.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/runner.rs b/src/runner.rs index 4ce87b6dc6..d0a500f83a 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -449,9 +449,26 @@ impl Interpreter { match *instructions { isa::Instruction::BrIfNez(target) => { if let RunInstructionTracePre::BrIfNez { value } = pre_status.unwrap() { + let mut drop_values = vec![]; + + for i in 1..=target.drop_keep.drop { + drop_values.push(*self.value_stack.pick(i as usize)); + } + StepInfo::BrIfNez { - value, + condition: value, dst_pc: target.dst_pc, + drop: target.drop_keep.drop, + keep: if let Keep::Single(t) = target.drop_keep.keep { + vec![t.into()] + } else { + vec![] + }, + drop_values: drop_values.iter().map(|v| v.0).collect::>(), + keep_values: match target.drop_keep.keep { + Keep::Single(_) => vec![(*self.value_stack.top()).0], + Keep::None => vec![], + }, } } else { unreachable!() From 049ae20f325a12c0d570bbf0dbd766fa99858166 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Thu, 21 Jul 2022 13:58:45 +0800 Subject: [PATCH 032/129] fix jentry --- src/func.rs | 4 ++-- src/runner.rs | 8 +++++--- src/tracer/jtable.rs | 8 ++------ src/tracer/mod.rs | 16 ++++++++++++++-- 4 files changed, 23 insertions(+), 13 deletions(-) diff --git a/src/func.rs b/src/func.rs index ddd86d36af..a17eaed23d 100644 --- a/src/func.rs +++ b/src/func.rs @@ -1,6 +1,6 @@ use crate::{ host::Externals, - isa, + isa::{self}, module::ModuleInstance, runner::{check_function_args, Interpreter, InterpreterState, StackRecycler}, tracer::Tracer, @@ -14,7 +14,7 @@ use alloc::{ rc::{Rc, Weak}, vec::Vec, }; -use core::{fmt, cell::RefCell}; +use core::{cell::RefCell, fmt}; use parity_wasm::elements::Local; /// Reference to a function (See [`FuncInstance`] for details). diff --git a/src/runner.rs b/src/runner.rs index d0a500f83a..8648cc8081 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -331,9 +331,11 @@ impl Interpreter { if let Some(trace) = self.tracer.as_mut() { let eid = trace.borrow_mut().eid(); let last_jump_eid = trace.borrow_mut().last_jump_eid(); - let inst = trace - .borrow_mut() - .lookup_first_inst(&nested_context.function); + + let inst = trace.borrow_mut().lookup_ientry( + &function_context.function, + function_context.position, + ); let mut trace = trace.borrow_mut(); let jtable = trace.jtable.as_mut(); diff --git a/src/tracer/jtable.rs b/src/tracer/jtable.rs index 1b46ae6f5a..a8419fbd1f 100644 --- a/src/tracer/jtable.rs +++ b/src/tracer/jtable.rs @@ -13,12 +13,8 @@ pub struct JEntry { pub struct JTable(pub Vec); impl JTable { - pub fn new(first_inst: &IEntry) -> Self { - JTable(vec![JEntry { - eid: 0, - last_jump_eid: 0, - inst: first_inst.clone(), - }]) + pub fn new() -> Self { + JTable(vec![]) } pub fn push(&mut self, eid: u64, last_jump_eid: u64, inst: &IEntry) { diff --git a/src/tracer/mod.rs b/src/tracer/mod.rs index ca76ec6c05..499b6e573f 100644 --- a/src/tracer/mod.rs +++ b/src/tracer/mod.rs @@ -105,7 +105,7 @@ impl Tracer { loop { let pc = iter.position(); if let Some(instruction) = iter.next() { - let ientry = self.itable.push( + let _ = self.itable.push( self.next_module_id() as u32, *func_index_in_itable, pc, @@ -113,7 +113,7 @@ impl Tracer { ); if self.jtable.is_none() { - self.jtable = Some(JTable::new(&ientry)) + self.jtable = Some(JTable::new()) } } else { break; @@ -150,6 +150,18 @@ impl Tracer { self.function_lookup.get(pos).unwrap().1 } + pub fn lookup_ientry(&self, function: &FuncRef, pos: u32) -> IEntry { + let function_idx = self.lookup_function(function); + + for ientry in &self.itable.0 { + if ientry.func_index as u16 == function_idx && ientry.pc as u32 == pos { + return ientry.clone(); + } + } + + unreachable!() + } + pub fn lookup_first_inst(&self, function: &FuncRef) -> IEntry { let function_idx = self.lookup_function(function); From eccb428365392cd8e76ca1441687c35512d88aa2 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Thu, 21 Jul 2022 16:09:07 +0800 Subject: [PATCH 033/129] bugfix: convert i32 to u64 correctly --- src/isa.rs | 2 +- src/runner.rs | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/isa.rs b/src/isa.rs index 4307be380a..da6d354a43 100644 --- a/src/isa.rs +++ b/src/isa.rs @@ -413,7 +413,7 @@ impl<'a> Instruction<'a> { Instruction::GrowMemory => todo!(), Instruction::I32Const(v) => Opcode::Const { vtype: VarType::I32, - value: v as u64, + value: v as u32 as u64, }, Instruction::I64Const(v) => Opcode::Const { vtype: VarType::I64, diff --git a/src/runner.rs b/src/runner.rs index 8648cc8081..95b3e17e5b 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -537,7 +537,10 @@ impl Interpreter { } } - isa::Instruction::I32Const(value) => StepInfo::I32Const { value }, + isa::Instruction::I32Const(value) => { + println!("value: {:?}", value); + StepInfo::I32Const { value } + } isa::Instruction::I32Eq => { if let RunInstructionTracePre::I32Comp { left, right } = pre_status.unwrap() { From 23f04d48b1c88b9edc57cbf6542bbf5abed4d5c7 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Thu, 21 Jul 2022 16:14:23 +0800 Subject: [PATCH 034/129] remove print --- src/runner.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/runner.rs b/src/runner.rs index 95b3e17e5b..8648cc8081 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -537,10 +537,7 @@ impl Interpreter { } } - isa::Instruction::I32Const(value) => { - println!("value: {:?}", value); - StepInfo::I32Const { value } - } + isa::Instruction::I32Const(value) => StepInfo::I32Const { value }, isa::Instruction::I32Eq => { if let RunInstructionTracePre::I32Comp { left, right } = pre_status.unwrap() { From 3d6193e41ef52ce339ed59b34a3385ee71cb4753 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Mon, 25 Jul 2022 15:09:57 +0800 Subject: [PATCH 035/129] support i32.store/load, teelocal --- src/isa.rs | 15 +++++-- src/runner.rs | 94 ++++++++++++++++++++++++++++++++++++++------ src/tracer/etable.rs | 12 ++++++ 3 files changed, 105 insertions(+), 16 deletions(-) diff --git a/src/isa.rs b/src/isa.rs index da6d354a43..b868349aa3 100644 --- a/src/isa.rs +++ b/src/isa.rs @@ -356,7 +356,10 @@ impl<'a> Instruction<'a> { vtype: typ.into(), }, Instruction::SetLocal(..) => todo!(), - Instruction::TeeLocal(..) => todo!(), + Instruction::TeeLocal(offset, typ) => Opcode::LocalTee { + offset: offset as u64, + vtype: typ.into(), + }, Instruction::Br(_) => todo!(), Instruction::BrIfEqz(_) => todo!(), Instruction::BrIfNez(Target { dst_pc, drop_keep }) => Opcode::BrIf { @@ -386,7 +389,10 @@ impl<'a> Instruction<'a> { Instruction::Select => todo!(), Instruction::GetGlobal(_) => todo!(), Instruction::SetGlobal(_) => todo!(), - Instruction::I32Load(_) => todo!(), + Instruction::I32Load(offset) => Opcode::Load { + offset, + vtype: VarType::I32, + }, Instruction::I64Load(_) => todo!(), Instruction::F32Load(_) => todo!(), Instruction::F64Load(_) => todo!(), @@ -400,7 +406,10 @@ impl<'a> Instruction<'a> { Instruction::I64Load16U(_) => todo!(), Instruction::I64Load32S(_) => todo!(), Instruction::I64Load32U(_) => todo!(), - Instruction::I32Store(_) => todo!(), + Instruction::I32Store(offset) => Opcode::Store { + offset, + vtype: VarType::I32, + }, Instruction::I64Store(_) => todo!(), Instruction::F32Store(_) => todo!(), Instruction::F64Store(_) => todo!(), diff --git a/src/runner.rs b/src/runner.rs index 8648cc8081..a98b6cd3eb 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -398,22 +398,49 @@ impl Interpreter { instructions: &isa::Instruction, ) -> Option { match *instructions { + isa::Instruction::GetLocal(depth, vtype) => { + let value = self.value_stack.pick(depth as usize); + Some(RunInstructionTracePre::GetLocal { + depth, + value: value.clone(), + vtype, + }) + } + isa::Instruction::TeeLocal(..) => None, + isa::Instruction::BrIfNez(_) => Some(RunInstructionTracePre::BrIfNez { value: <_>::from_value_internal(*self.value_stack.top()), }), isa::Instruction::Return(..) => None, - isa::Instruction::Drop => Some(RunInstructionTracePre::Drop), isa::Instruction::Call(_) => None, + isa::Instruction::Drop => Some(RunInstructionTracePre::Drop), - isa::Instruction::GetLocal(depth, vtype) => { - let value = self.value_stack.pick(depth as usize); - Some(RunInstructionTracePre::GetLocal { - depth, - value: value.clone(), - vtype, + isa::Instruction::I32Load(offset) => { + let raw_address = <_>::from_value_internal(*self.value_stack.top()); + let address = + effective_address(offset, raw_address).map_or(None, |addr| Some(addr)); + + Some(RunInstructionTracePre::Load { + offset, + address, + vtype: parity_wasm::elements::ValueType::I32, + }) + } + isa::Instruction::I32Store(offset) => { + let value = <_>::from_value_internal(*self.value_stack.pick(1)); + let raw_address = <_>::from_value_internal(*self.value_stack.pick(2)); + let address = + effective_address(offset, raw_address).map_or(None, |addr| Some(addr)); + + Some(RunInstructionTracePre::Store { + offset, + address, + value, + vtype: parity_wasm::elements::ValueType::I32, }) } + isa::Instruction::I32Const(_) => None, isa::Instruction::I32Eq => Some(RunInstructionTracePre::I32Comp { @@ -449,6 +476,28 @@ impl Interpreter { instructions: &isa::Instruction, ) -> StepInfo { match *instructions { + isa::Instruction::GetLocal(..) => { + if let RunInstructionTracePre::GetLocal { + depth, + value, + vtype, + } = pre_status.unwrap() + { + StepInfo::GetLocal { + depth, + value: <_>::from_value_internal(value), + vtype: vtype.into(), + } + } else { + unreachable!() + } + } + isa::Instruction::TeeLocal(depth, vtype) => StepInfo::TeeLocal { + depth, + value: <_>::from_value_internal(*self.value_stack.top()), + vtype: vtype.into(), + }, + isa::Instruction::BrIfNez(target) => { if let RunInstructionTracePre::BrIfNez { value } = pre_status.unwrap() { let mut drop_values = vec![]; @@ -520,17 +569,36 @@ impl Interpreter { } } - isa::Instruction::GetLocal(..) => { - if let RunInstructionTracePre::GetLocal { - depth, + isa::Instruction::I32Load(..) => { + if let RunInstructionTracePre::Load { + offset, + address, + vtype, + } = pre_status.unwrap() + { + StepInfo::Load { + vtype: vtype.into(), + offset, + address: address.unwrap(), + value: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } + isa::Instruction::I32Store(..) => { + if let RunInstructionTracePre::Store { + offset, + address, value, vtype, } = pre_status.unwrap() { - StepInfo::GetLocal { - depth, - value: <_>::from_value_internal(value), + StepInfo::Store { vtype: vtype.into(), + offset, + address: address.unwrap(), + value: value as u32 as u64, } } else { unreachable!() diff --git a/src/tracer/etable.rs b/src/tracer/etable.rs index 136d9a9b15..486d0d3d6b 100644 --- a/src/tracer/etable.rs +++ b/src/tracer/etable.rs @@ -20,6 +20,18 @@ pub enum RunInstructionTracePre { vtype: ValueType, }, + Load { + offset: u32, + address: Option, // use option in case of memory out of bound + vtype: ValueType, + }, + Store { + offset: u32, + address: Option, + value: i32, + vtype: ValueType, + }, + I32BinOp { class: BinOp, left: i32, From af0996d5aa993c7ada90ec7ac4df2b6dff43e458 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Mon, 25 Jul 2022 18:58:57 +0800 Subject: [PATCH 036/129] push imtable --- src/module.rs | 38 +++++++++++++++++++++++++++++++++++--- src/tracer/imtable.rs | 33 +++++++++++++++++++++++++++++++++ src/tracer/mod.rs | 15 ++++++++++++++- 3 files changed, 82 insertions(+), 4 deletions(-) create mode 100644 src/tracer/imtable.rs diff --git a/src/module.rs b/src/module.rs index 19d6fd1fae..92aaa56b97 100644 --- a/src/module.rs +++ b/src/module.rs @@ -418,6 +418,7 @@ impl ModuleInstance { pub fn with_externvals<'a, 'i, I: Iterator>( loaded_module: &'a Module, extern_vals: I, + tracer: Option>>, ) -> Result, Error> { let module = loaded_module.module(); @@ -474,6 +475,16 @@ impl ModuleInstance { .memory_by_index(DEFAULT_MEMORY_INDEX) .expect("Due to validation default memory should exists"); memory_inst.set(offset_val, data_segment.value())?; + + match &tracer { + Some(tracer) => { + let t = tracer.clone(); + let module_id = { (*t).borrow().next_module_id() }; + let mut t = (*t).borrow_mut(); + t.push_init_memory(module_id, offset_val, data_segment.value()); + } + None => (), + } } Ok(NotStartedModuleRef { @@ -545,6 +556,7 @@ impl ModuleInstance { pub fn new<'m, I: ImportResolver>( loaded_module: &'m Module, imports: &I, + tracer: Option>>, ) -> Result, Error> { let module = loaded_module.module(); @@ -584,7 +596,21 @@ impl ModuleInstance { extern_vals.push(extern_val); } - Self::with_externvals(loaded_module, extern_vals.iter()) + let module_ref = Self::with_externvals(loaded_module, extern_vals.iter(), tracer.clone()); + + let _ = module_ref.as_ref().map(|module_ref| { + let module = module_ref.loaded_module; + match tracer { + Some(tracer) => { + (*tracer) + .borrow_mut() + .register_module_instance(module, &module_ref.instance); + } + None => (), + } + }); + + module_ref } /// Invoke exported function by a name. @@ -892,7 +918,8 @@ mod tests { (start $f)) "#, ); - let module = ModuleInstance::new(&module_with_start, &ImportsBuilder::default()).unwrap(); + let module = + ModuleInstance::new(&module_with_start, &ImportsBuilder::default(), None).unwrap(); assert!(!module.has_start()); module.assert_no_start(); } @@ -914,6 +941,7 @@ mod tests { 0 ),)] .iter(), + None, ) .is_ok()); @@ -925,11 +953,14 @@ mod tests { ExternVal::Func(FuncInstance::alloc_host(Signature::new(&[][..], None), 1)), ] .iter(), + None, ) .is_err()); // externval vector is shorter than import count. - assert!(ModuleInstance::with_externvals(&module_with_single_import, [].iter(),).is_err()); + assert!( + ModuleInstance::with_externvals(&module_with_single_import, [].iter(), None).is_err() + ); // externval vector has an unexpected type. assert!(ModuleInstance::with_externvals( @@ -939,6 +970,7 @@ mod tests { 0 ),)] .iter(), + None, ) .is_err()); } diff --git a/src/tracer/imtable.rs b/src/tracer/imtable.rs new file mode 100644 index 0000000000..5b99958ef9 --- /dev/null +++ b/src/tracer/imtable.rs @@ -0,0 +1,33 @@ +use specs::imtable::InitMemoryTableEntry; + +#[derive(Debug, Clone)] +pub struct IMEntry { + pub module_instance_index: u16, + pub offset: u32, + pub value: u8, +} + +impl Into for IMEntry { + fn into(self) -> InitMemoryTableEntry { + InitMemoryTableEntry { + mmid: self.module_instance_index as u64, + offset: self.offset as u64, + value: self.value, + } + } +} + +#[derive(Debug, Default)] +pub struct IMTable(pub Vec); + +impl IMTable { + pub(crate) fn push(&mut self, module_instance_index: u16, offset: usize, value: &[u8]) { + for idx in 0..value.len() { + self.0.push(IMEntry { + module_instance_index, + offset: (offset + idx) as u32, + value: value[idx], + }) + } + } +} diff --git a/src/tracer/mod.rs b/src/tracer/mod.rs index 499b6e573f..db9a2c31ea 100644 --- a/src/tracer/mod.rs +++ b/src/tracer/mod.rs @@ -4,17 +4,20 @@ use crate::{FuncRef, Module, ModuleRef}; use self::{ etable::ETable, + imtable::IMTable, itable::{IEntry, ITable}, jtable::JTable, }; pub mod etable; +pub mod imtable; pub mod itable; pub mod jtable; #[derive(Debug)] pub struct Tracer { pub itable: ITable, + pub imtable: IMTable, pub etable: ETable, pub jtable: Option, module_instance_lookup: Vec<(ModuleRef, u16)>, @@ -29,6 +32,7 @@ impl Tracer { pub fn default() -> Self { Tracer { itable: ITable::default(), + imtable: IMTable::default(), etable: ETable::default(), last_jump_eid: vec![0], jtable: None, @@ -67,7 +71,16 @@ impl Tracer { } impl Tracer { - pub fn register_module_instance(&mut self, module: &Module, module_instance: &ModuleRef) { + pub(crate) fn push_init_memory(&mut self, module_instance_id: u16, offset: u32, value: &[u8]) { + self.imtable + .push(module_instance_id, offset as usize, value) + } + + pub(crate) fn register_module_instance( + &mut self, + module: &Module, + module_instance: &ModuleRef, + ) { let start_fn_idx = module.module().start_section(); { From 9799c41eb4c9b871f55b549e7635fd167fd86110 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Mon, 25 Jul 2022 21:35:19 +0800 Subject: [PATCH 037/129] fill all mem initialization in imtable --- src/module.rs | 21 +++++++++++++-------- src/tracer/imtable.rs | 16 +++++++--------- src/tracer/mod.rs | 13 +++++++++---- 3 files changed, 29 insertions(+), 21 deletions(-) diff --git a/src/module.rs b/src/module.rs index 92aaa56b97..e89e001665 100644 --- a/src/module.rs +++ b/src/module.rs @@ -475,16 +475,21 @@ impl ModuleInstance { .memory_by_index(DEFAULT_MEMORY_INDEX) .expect("Due to validation default memory should exists"); memory_inst.set(offset_val, data_segment.value())?; + } - match &tracer { - Some(tracer) => { - let t = tracer.clone(); - let module_id = { (*t).borrow().next_module_id() }; - let mut t = (*t).borrow_mut(); - t.push_init_memory(module_id, offset_val, data_segment.value()); - } - None => (), + match &tracer { + Some(tracer) => { + let t = tracer.clone(); + let module_id = { (*t).borrow().next_module_id() }; + let mut t = (*t).borrow_mut(); + t.push_init_memory( + module_id, + module_ref + .memory_by_index(DEFAULT_MEMORY_INDEX) + .expect("Due to validation default memory should exists"), + ); } + None => (), } Ok(NotStartedModuleRef { diff --git a/src/tracer/imtable.rs b/src/tracer/imtable.rs index 5b99958ef9..c41ef399ff 100644 --- a/src/tracer/imtable.rs +++ b/src/tracer/imtable.rs @@ -4,7 +4,7 @@ use specs::imtable::InitMemoryTableEntry; pub struct IMEntry { pub module_instance_index: u16, pub offset: u32, - pub value: u8, + pub value: u64, } impl Into for IMEntry { @@ -21,13 +21,11 @@ impl Into for IMEntry { pub struct IMTable(pub Vec); impl IMTable { - pub(crate) fn push(&mut self, module_instance_index: u16, offset: usize, value: &[u8]) { - for idx in 0..value.len() { - self.0.push(IMEntry { - module_instance_index, - offset: (offset + idx) as u32, - value: value[idx], - }) - } + pub(crate) fn push(&mut self, module_instance_index: u16, offset: u32, value: u64) { + self.0.push(IMEntry { + module_instance_index, + offset, + value, + }) } } diff --git a/src/tracer/mod.rs b/src/tracer/mod.rs index db9a2c31ea..aa29badc93 100644 --- a/src/tracer/mod.rs +++ b/src/tracer/mod.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use crate::{FuncRef, Module, ModuleRef}; +use crate::{FuncRef, MemoryRef, Module, ModuleRef}; use self::{ etable::ETable, @@ -71,9 +71,14 @@ impl Tracer { } impl Tracer { - pub(crate) fn push_init_memory(&mut self, module_instance_id: u16, offset: u32, value: &[u8]) { - self.imtable - .push(module_instance_id, offset as usize, value) + pub(crate) fn push_init_memory(&mut self, module_instance_id: u16, memref: MemoryRef) { + let pages = (*memref).limits().initial(); + for i in 0..(pages * 1024) { + let mut buf = [0u8; 8]; + (*memref).get_into(i * 8, &mut buf).unwrap(); + self.imtable + .push(module_instance_id, i, u64::from_le_bytes(buf)); + } } pub(crate) fn register_module_instance( From f429edbc362d534cd1fded407cac185bbe5a41d5 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Mon, 25 Jul 2022 21:42:41 +0800 Subject: [PATCH 038/129] bugfix: dont push imtable if mem inst is not exist --- src/module.rs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/module.rs b/src/module.rs index e89e001665..5c872b2b53 100644 --- a/src/module.rs +++ b/src/module.rs @@ -479,15 +479,12 @@ impl ModuleInstance { match &tracer { Some(tracer) => { - let t = tracer.clone(); - let module_id = { (*t).borrow().next_module_id() }; - let mut t = (*t).borrow_mut(); - t.push_init_memory( - module_id, - module_ref - .memory_by_index(DEFAULT_MEMORY_INDEX) - .expect("Due to validation default memory should exists"), - ); + if let Some(memory_ref) = module_ref.memory_by_index(DEFAULT_MEMORY_INDEX) { + let t = tracer.clone(); + let module_id = { (*t).borrow().next_module_id() }; + let mut t = (*t).borrow_mut(); + t.push_init_memory(module_id, memory_ref) + } } None => (), } From 44b7f41192f3186b7de504168156119ab71855ba Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Tue, 26 Jul 2022 13:30:11 +0800 Subject: [PATCH 039/129] support store/load --- src/bin/instantiate.rs | 1 + src/module.rs | 3 +-- src/runner.rs | 46 ++++++++++++++++++++++++++++++++++-------- src/tracer/etable.rs | 8 ++++++-- src/tracer/mod.rs | 23 +++++++++++++++++++-- 5 files changed, 67 insertions(+), 14 deletions(-) diff --git a/src/bin/instantiate.rs b/src/bin/instantiate.rs index 73bf10e9ea..07de6ccdc7 100644 --- a/src/bin/instantiate.rs +++ b/src/bin/instantiate.rs @@ -91,6 +91,7 @@ fn main() { .with_resolver("global.Math", &ResolveAll) .with_resolver("asm2wasm", &ResolveAll) .with_resolver("spectest", &ResolveAll), + None, ) .expect("Failed to instantiate module") .run_start(&mut NopExternals) diff --git a/src/module.rs b/src/module.rs index 5c872b2b53..ed66f0144f 100644 --- a/src/module.rs +++ b/src/module.rs @@ -481,9 +481,8 @@ impl ModuleInstance { Some(tracer) => { if let Some(memory_ref) = module_ref.memory_by_index(DEFAULT_MEMORY_INDEX) { let t = tracer.clone(); - let module_id = { (*t).borrow().next_module_id() }; let mut t = (*t).borrow_mut(); - t.push_init_memory(module_id, memory_ref) + t.push_init_memory(memory_ref) } } None => (), diff --git a/src/runner.rs b/src/runner.rs index a98b6cd3eb..69bd588fd8 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -395,6 +395,7 @@ impl Interpreter { fn run_instruction_pre( &mut self, + function_context: &FunctionContext, instructions: &isa::Instruction, ) -> Option { match *instructions { @@ -420,11 +421,24 @@ impl Interpreter { let raw_address = <_>::from_value_internal(*self.value_stack.top()); let address = effective_address(offset, raw_address).map_or(None, |addr| Some(addr)); + let mmid = self + .tracer + .clone() + .unwrap() + .borrow_mut() + .lookup_memory_instance( + &function_context + .memory + .clone() + .expect("Due to validation memory should exists"), + ); Some(RunInstructionTracePre::Load { offset, - address, + raw_address, + effective_address: address, vtype: parity_wasm::elements::ValueType::I32, + mmid: mmid as u64, }) } isa::Instruction::I32Store(offset) => { @@ -432,12 +446,20 @@ impl Interpreter { let raw_address = <_>::from_value_internal(*self.value_stack.pick(2)); let address = effective_address(offset, raw_address).map_or(None, |addr| Some(addr)); + let mmid = self + .tracer + .clone() + .unwrap() + .borrow_mut() + .lookup_memory_instance(&function_context.memory.clone().unwrap()); Some(RunInstructionTracePre::Store { offset, - address, + raw_address, + effective_address: address, value, vtype: parity_wasm::elements::ValueType::I32, + mmid: mmid as u64, }) } @@ -572,15 +594,19 @@ impl Interpreter { isa::Instruction::I32Load(..) => { if let RunInstructionTracePre::Load { offset, - address, + raw_address, + effective_address, vtype, + mmid, } = pre_status.unwrap() { StepInfo::Load { vtype: vtype.into(), offset, - address: address.unwrap(), + raw_address, + effective_address: effective_address.unwrap(), value: <_>::from_value_internal(*self.value_stack.top()), + mmid, } } else { unreachable!() @@ -589,16 +615,20 @@ impl Interpreter { isa::Instruction::I32Store(..) => { if let RunInstructionTracePre::Store { offset, - address, + raw_address, + effective_address, value, vtype, + mmid, } = pre_status.unwrap() { StepInfo::Store { vtype: vtype.into(), offset, - address: address.unwrap(), + raw_address, + effective_address: effective_address.unwrap(), value: value as u32 as u64, + mmid, } } else { unreachable!() @@ -681,7 +711,7 @@ impl Interpreter { ); let pre_status = if self.tracer.is_some() { - self.run_instruction_pre(&instruction) + self.run_instruction_pre(function_context, &instruction) } else { None }; @@ -692,7 +722,7 @@ impl Interpreter { let post_status = self.run_instruction_post(pre_status, &instruction); if let Some(tracer) = self.tracer.as_mut() { let instruction = { - let tracer = tracer.borrow(); + let tracer = tracer.borrow_mut(); instruction.into(&tracer.function_index_translation) }; diff --git a/src/tracer/etable.rs b/src/tracer/etable.rs index 486d0d3d6b..4660a78e29 100644 --- a/src/tracer/etable.rs +++ b/src/tracer/etable.rs @@ -22,14 +22,18 @@ pub enum RunInstructionTracePre { Load { offset: u32, - address: Option, // use option in case of memory out of bound + raw_address: u32, + effective_address: Option, // use option in case of memory out of bound vtype: ValueType, + mmid: u64, }, Store { offset: u32, - address: Option, + raw_address: u32, + effective_address: Option, value: i32, vtype: ValueType, + mmid: u64, }, I32BinOp { diff --git a/src/tracer/mod.rs b/src/tracer/mod.rs index aa29badc93..4ca39f4269 100644 --- a/src/tracer/mod.rs +++ b/src/tracer/mod.rs @@ -21,6 +21,7 @@ pub struct Tracer { pub etable: ETable, pub jtable: Option, module_instance_lookup: Vec<(ModuleRef, u16)>, + memory_instance_lookup: Vec<(MemoryRef, u16)>, function_lookup: Vec<(FuncRef, u16)>, last_jump_eid: Vec, function_index_allocator: u32, @@ -37,6 +38,7 @@ impl Tracer { last_jump_eid: vec![0], jtable: None, module_instance_lookup: vec![], + memory_instance_lookup: vec![], function_lookup: vec![], function_index_allocator: 1, function_index_translation: Default::default(), @@ -55,6 +57,10 @@ impl Tracer { (self.module_instance_lookup.len() as u16) + 1 } + pub fn next_memory_id(&self) -> u16 { + (self.memory_instance_lookup.len() as u16) + 1 + } + pub fn last_jump_eid(&self) -> u64 { *self.last_jump_eid.last().unwrap() } @@ -71,14 +77,17 @@ impl Tracer { } impl Tracer { - pub(crate) fn push_init_memory(&mut self, module_instance_id: u16, memref: MemoryRef) { + pub(crate) fn push_init_memory(&mut self, memref: MemoryRef) { let pages = (*memref).limits().initial(); for i in 0..(pages * 1024) { let mut buf = [0u8; 8]; (*memref).get_into(i * 8, &mut buf).unwrap(); self.imtable - .push(module_instance_id, i, u64::from_le_bytes(buf)); + .push(self.next_memory_id(), i, u64::from_le_bytes(buf)); } + + self.memory_instance_lookup + .push((memref, self.next_memory_id())); } pub(crate) fn register_module_instance( @@ -159,6 +168,16 @@ impl Tracer { unreachable!() } + pub fn lookup_memory_instance(&self, module_instance: &MemoryRef) -> u16 { + for m in &self.memory_instance_lookup { + if &m.0 == module_instance { + return m.1; + } + } + + unreachable!() + } + pub fn lookup_function(&self, function: &FuncRef) -> u16 { let pos = self .function_lookup From 6315e32f065036e637b20398c97f152cd4107e8d Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Tue, 26 Jul 2022 15:17:53 +0800 Subject: [PATCH 040/129] load block_value --- src/runner.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/runner.rs b/src/runner.rs index 69bd588fd8..c172335ff2 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -495,6 +495,7 @@ impl Interpreter { fn run_instruction_post( &mut self, pre_status: Option, + context: &FunctionContext, instructions: &isa::Instruction, ) -> StepInfo { match *instructions { @@ -600,12 +601,22 @@ impl Interpreter { mmid, } = pre_status.unwrap() { + let mut buf = [0u8; 8]; + context + .memory + .clone() + .unwrap() + .get_into(offset, &mut buf) + .unwrap(); + let block_value = u64::from_le_bytes(buf); + StepInfo::Load { vtype: vtype.into(), offset, raw_address, effective_address: effective_address.unwrap(), value: <_>::from_value_internal(*self.value_stack.top()), + block_value, mmid, } } else { @@ -719,7 +730,8 @@ impl Interpreter { macro_rules! trace_post { () => { if self.tracer.is_some() { - let post_status = self.run_instruction_post(pre_status, &instruction); + let post_status = + self.run_instruction_post(pre_status, function_context, &instruction); if let Some(tracer) = self.tracer.as_mut() { let instruction = { let tracer = tracer.borrow_mut(); From 513132da5ff4336df2abd273769e8ad25c64c754 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Wed, 27 Jul 2022 16:32:53 +0800 Subject: [PATCH 041/129] support host_function --- examples/interpret.rs | 2 +- examples/invoke.rs | 2 +- examples/tictactoe.rs | 2 +- src/isa.rs | 9 ++- src/runner.rs | 142 ++++++++++++++++++++++++------------------ src/tracer/etable.rs | 27 ++++++++ src/tracer/jtable.rs | 6 +- src/tracer/mod.rs | 71 +++++++++++++-------- src/types.rs | 13 ++++ tests/e2e/v0/host.rs | 75 +++++++++++++++------- tests/e2e/v0/wasm.rs | 20 ++++-- tests/spec/v0/run.rs | 4 +- 12 files changed, 246 insertions(+), 127 deletions(-) diff --git a/examples/interpret.rs b/examples/interpret.rs index d18fc05545..aebf6afd11 100644 --- a/examples/interpret.rs +++ b/examples/interpret.rs @@ -30,7 +30,7 @@ fn main() { // - a module declaration // - "main" module doesn't import native module(s) this is why we don't need to provide external native modules here // This test shows how to implement native module https://github.com/NikVolf/parity-wasm/blob/master/src/interpreter/tests/basics.rs#L197 - let main = ModuleInstance::new(&module, &ImportsBuilder::default()) + let main = ModuleInstance::new(&module, &ImportsBuilder::default(), None) .expect("Failed to instantiate module") .run_start(&mut NopExternals) .expect("Failed to run start function in module"); diff --git a/examples/invoke.rs b/examples/invoke.rs index 5e49c82347..b8e6184dbb 100644 --- a/examples/invoke.rs +++ b/examples/invoke.rs @@ -105,7 +105,7 @@ fn main() { // - a module declaration // - "main" module doesn't import native module(s) this is why we don't need to provide external native modules here // This test shows how to implement native module https://github.com/NikVolf/parity-wasm/blob/master/src/interpreter/tests/basics.rs#L197 - let main = ModuleInstance::new(&loaded_module, &ImportsBuilder::default()) + let main = ModuleInstance::new(&loaded_module, &ImportsBuilder::default(), None) .expect("Failed to instantiate module") .run_start(&mut NopExternals) .expect("Failed to run start function in module"); diff --git a/examples/tictactoe.rs b/examples/tictactoe.rs index 2fc9926f8c..2f9040298a 100644 --- a/examples/tictactoe.rs +++ b/examples/tictactoe.rs @@ -213,7 +213,7 @@ fn instantiate(path: &str) -> Result { let mut imports = ImportsBuilder::new(); imports.push_resolver("env", &RuntimeModuleImportResolver); - let instance = ModuleInstance::new(&module, &imports)?.assert_no_start(); + let instance = ModuleInstance::new(&module, &imports, None)?.assert_no_start(); Ok(instance) } diff --git a/src/isa.rs b/src/isa.rs index b868349aa3..3b0daf16d3 100644 --- a/src/isa.rs +++ b/src/isa.rs @@ -76,6 +76,8 @@ use specs::{ mtable::VarType, }; +use crate::tracer::FuncDesc; + /// Should we keep a value before "discarding" a stack frame? /// /// Note that this is a `enum` since Wasm doesn't support multiple return @@ -349,7 +351,7 @@ pub enum Instruction<'a> { } impl<'a> Instruction<'a> { - pub fn into(self, function_mapping: &HashMap) -> Opcode { + pub(crate) fn into(self, function_mapping: &HashMap) -> Opcode { match self { Instruction::GetLocal(offset, typ) => Opcode::LocalGet { offset: offset as u64, @@ -382,7 +384,10 @@ impl<'a> Instruction<'a> { }, }, Instruction::Call(func_index) => Opcode::Call { - index: *function_mapping.get(&func_index).unwrap(), + index: function_mapping + .get(&func_index) + .unwrap() + .index_within_jtable, }, Instruction::CallIndirect(_) => todo!(), Instruction::Drop => Opcode::Drop, diff --git a/src/runner.rs b/src/runner.rs index c172335ff2..c13a6877d3 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -328,22 +328,19 @@ impl Interpreter { FuncInstanceInternal::Internal { .. } => { let nested_context = FunctionContext::new(nested_func.clone()); - if let Some(trace) = self.tracer.as_mut() { - let eid = trace.borrow_mut().eid(); - let last_jump_eid = trace.borrow_mut().last_jump_eid(); + if let Some(tracer) = self.tracer.clone() { + let mut tracer = (*tracer).borrow_mut(); + let eid = tracer.eid(); + let last_jump_eid = tracer.last_jump_eid(); - let inst = trace.borrow_mut().lookup_ientry( + let inst = tracer.lookup_ientry( &function_context.function, function_context.position, ); - let mut trace = trace.borrow_mut(); - let jtable = trace.jtable.as_mut(); - if let Some(jtable) = jtable { - jtable.push(eid, last_jump_eid, &inst); - } + tracer.jtable.push(eid, last_jump_eid, &inst); - trace.push_frame(); + tracer.push_frame(); } self.call_stack.push(function_context); @@ -386,6 +383,15 @@ impl Interpreter { .push(return_val.into()) .map_err(Trap::from)?; } + + if let Some(return_val) = return_val { + if let Some(tracer) = self.tracer.clone() { + let mut tracer = (*tracer).borrow_mut(); + tracer.etable.resolve_host_call(<_>::from_value_internal( + return_val.into(), + )) + } + } } } } @@ -395,9 +401,12 @@ impl Interpreter { fn run_instruction_pre( &mut self, + tracer: Rc>, function_context: &FunctionContext, instructions: &isa::Instruction, ) -> Option { + let tracer = tracer.borrow(); + match *instructions { isa::Instruction::GetLocal(depth, vtype) => { let value = self.value_stack.pick(depth as usize); @@ -414,24 +423,33 @@ impl Interpreter { }), isa::Instruction::Return(..) => None, - isa::Instruction::Call(_) => None, + isa::Instruction::Call(func_idx) => { + let func = function_context + .module() + .func_by_index(func_idx) + .expect("Due to validation func should exists"); + + let mut args = vec![]; + let len = func.signature().params().len(); + + for i in 1..=len { + args.push(*self.value_stack.pick(i)); + } + + Some(RunInstructionTracePre::Call { args }) + } isa::Instruction::Drop => Some(RunInstructionTracePre::Drop), isa::Instruction::I32Load(offset) => { let raw_address = <_>::from_value_internal(*self.value_stack.top()); let address = effective_address(offset, raw_address).map_or(None, |addr| Some(addr)); - let mmid = self - .tracer - .clone() - .unwrap() - .borrow_mut() - .lookup_memory_instance( - &function_context - .memory - .clone() - .expect("Due to validation memory should exists"), - ); + let mmid = tracer.lookup_memory_instance( + &function_context + .memory + .clone() + .expect("Due to validation memory should exists"), + ); Some(RunInstructionTracePre::Load { offset, @@ -446,12 +464,7 @@ impl Interpreter { let raw_address = <_>::from_value_internal(*self.value_stack.pick(2)); let address = effective_address(offset, raw_address).map_or(None, |addr| Some(addr)); - let mmid = self - .tracer - .clone() - .unwrap() - .borrow_mut() - .lookup_memory_instance(&function_context.memory.clone().unwrap()); + let mmid = tracer.lookup_memory_instance(&function_context.memory.clone().unwrap()); Some(RunInstructionTracePre::Store { offset, @@ -579,13 +592,21 @@ impl Interpreter { } } isa::Instruction::Call(index) => { - if let Some(tracer) = self.tracer.as_deref() { + if let RunInstructionTracePre::Call { args } = pre_status.unwrap() { + let tracer = self.tracer.clone().unwrap(); + let tracer = tracer.borrow(); + + let desc = tracer.function_index_translation.get(&index).unwrap(); + StepInfo::Call { - index: *tracer - .borrow() - .function_index_translation - .get(&index) - .unwrap(), + index: desc.index_within_jtable, + ftype: desc.ftype.clone(), + signature: desc.signature.clone().into(), + args: args + .iter() + .map(|arg| <_>::from_value_internal(*arg)) + .collect(), + ret: None, } } else { unreachable!() @@ -722,44 +743,41 @@ impl Interpreter { ); let pre_status = if self.tracer.is_some() { - self.run_instruction_pre(function_context, &instruction) + self.run_instruction_pre( + self.tracer.clone().unwrap(), + function_context, + &instruction, + ) } else { None }; macro_rules! trace_post { () => { - if self.tracer.is_some() { + if let Some(tracer) = self.tracer.clone() { let post_status = self.run_instruction_post(pre_status, function_context, &instruction); - if let Some(tracer) = self.tracer.as_mut() { - let instruction = { - let tracer = tracer.borrow_mut(); - instruction.into(&tracer.function_index_translation) - }; - let mut tracer = tracer.borrow_mut(); - let module_instance = - tracer.lookup_module_instance(&function_context.module); + let mut tracer = (*tracer).borrow_mut(); - let function = tracer.lookup_function(&function_context.function); + let instruction = { instruction.into(&tracer.function_index_translation) }; - let last_jump_eid = tracer.last_jump_eid(); + let module_instance = + tracer.lookup_module_instance(&function_context.module); - Some(tracer.etable.push( - module_instance, - function, - sp as u64, - pc, - last_jump_eid, - instruction, - post_status, - )) - } else { - None - } - } else { - None + let function = tracer.lookup_function(&function_context.function); + + let last_jump_eid = tracer.last_jump_eid(); + + tracer.etable.push( + module_instance, + function, + sp as u64, + pc, + last_jump_eid, + instruction, + post_status, + ); } }; } @@ -782,8 +800,8 @@ impl Interpreter { } InstructionOutcome::Return(drop_keep) => { trace_post!(); - if let Some(trace) = self.tracer.as_mut() { - trace.borrow_mut().pop_frame(); + if let Some(tracer) = self.tracer.clone() { + (*tracer).borrow_mut().pop_frame(); } self.value_stack.drop_keep(drop_keep); diff --git a/src/tracer/etable.rs b/src/tracer/etable.rs index 4660a78e29..8128bf0ef6 100644 --- a/src/tracer/etable.rs +++ b/src/tracer/etable.rs @@ -14,6 +14,10 @@ pub enum RunInstructionTracePre { value: i32, }, + Call { + args: Vec, + }, + GetLocal { depth: u32, value: ValueInternal, @@ -137,4 +141,27 @@ impl ETable { eentry } + + pub fn resolve_host_call(&mut self, ret: u64) { + let entry = self.entries.last_mut().unwrap(); + + if let StepInfo::Call { + index, + ftype, + signature, + args, + ret: _, + } = &entry.step + { + entry.step = StepInfo::Call { + index: *index, + ftype: ftype.clone(), + signature: signature.clone(), + args: args.clone(), + ret: Some(ret), + }; + } else { + unreachable!() + } + } } diff --git a/src/tracer/jtable.rs b/src/tracer/jtable.rs index a8419fbd1f..9b73a757c3 100644 --- a/src/tracer/jtable.rs +++ b/src/tracer/jtable.rs @@ -9,14 +9,10 @@ pub struct JEntry { inst: IEntry, } -#[derive(Debug)] +#[derive(Debug, Default)] pub struct JTable(pub Vec); impl JTable { - pub fn new() -> Self { - JTable(vec![]) - } - pub fn push(&mut self, eid: u64, last_jump_eid: u64, inst: &IEntry) { self.0.push(JEntry { eid, diff --git a/src/tracer/mod.rs b/src/tracer/mod.rs index 4ca39f4269..f5649e96bc 100644 --- a/src/tracer/mod.rs +++ b/src/tracer/mod.rs @@ -1,6 +1,8 @@ use std::collections::HashMap; -use crate::{FuncRef, MemoryRef, Module, ModuleRef}; +use specs::types::FunctionType; + +use crate::{FuncRef, MemoryRef, Module, ModuleRef, Signature}; use self::{ etable::ETable, @@ -14,18 +16,25 @@ pub mod imtable; pub mod itable; pub mod jtable; +#[derive(Debug)] +pub(crate) struct FuncDesc { + pub(crate) index_within_jtable: u16, + pub(crate) ftype: FunctionType, + pub(crate) signature: Signature, +} + #[derive(Debug)] pub struct Tracer { pub itable: ITable, pub imtable: IMTable, pub etable: ETable, - pub jtable: Option, + pub jtable: JTable, module_instance_lookup: Vec<(ModuleRef, u16)>, memory_instance_lookup: Vec<(MemoryRef, u16)>, function_lookup: Vec<(FuncRef, u16)>, last_jump_eid: Vec, function_index_allocator: u32, - pub function_index_translation: HashMap, + pub(crate) function_index_translation: HashMap, } impl Tracer { @@ -36,7 +45,7 @@ impl Tracer { imtable: IMTable::default(), etable: ETable::default(), last_jump_eid: vec![0], - jtable: None, + jtable: JTable::default(), module_instance_lookup: vec![], memory_instance_lookup: vec![], function_lookup: vec![], @@ -108,10 +117,25 @@ impl Tracer { self.allocate_func_index() }; + let ftype = match *func.as_internal() { + crate::func::FuncInstanceInternal::Internal { .. } => { + FunctionType::WasmFunction + } + crate::func::FuncInstanceInternal::Host { + host_func_index, .. + } => FunctionType::HostFunction(host_func_index), + }; + self.function_lookup .push((func.clone(), func_index_in_itable as u16)); - self.function_index_translation - .insert(func_index, func_index_in_itable as u16); + self.function_index_translation.insert( + func_index, + FuncDesc { + index_within_jtable: func_index_in_itable as u16, + ftype, + signature: func.signature().clone(), + }, + ); func_index = func_index + 1; } else { break; @@ -124,26 +148,23 @@ impl Tracer { loop { if let Some(func) = module_instance.func_by_index(func_index) { - let func_index_in_itable = - self.function_index_translation.get(&func_index).unwrap(); - let body = func.body().expect("Host function is not allowed"); - let code = &body.code; - let mut iter = code.iterate_from(0); - loop { - let pc = iter.position(); - if let Some(instruction) = iter.next() { - let _ = self.itable.push( - self.next_module_id() as u32, - *func_index_in_itable, - pc, - instruction.into(&self.function_index_translation), - ); - - if self.jtable.is_none() { - self.jtable = Some(JTable::new()) + let funcdesc = self.function_index_translation.get(&func_index).unwrap(); + + if let Some(body) = func.body() { + let code = &body.code; + let mut iter = code.iterate_from(0); + loop { + let pc = iter.position(); + if let Some(instruction) = iter.next() { + let _ = self.itable.push( + self.next_module_id() as u32, + funcdesc.index_within_jtable, + pc, + instruction.into(&self.function_index_translation), + ); + } else { + break; } - } else { - break; } } diff --git a/src/types.rs b/src/types.rs index e38889ee2d..b5e152ab02 100644 --- a/src/types.rs +++ b/src/types.rs @@ -71,6 +71,19 @@ impl Signature { } } +impl Into for Signature { + fn into(self) -> specs::types::Signature { + specs::types::Signature { + params: self + .params() + .iter() + .map(|param| param.into_elements().into()) + .collect(), + return_type: self.return_type().map(|ret| ret.into_elements().into()), + } + } +} + /// Description of a global variable. /// /// Primarly used to describe imports of global variables. diff --git a/tests/e2e/v0/host.rs b/tests/e2e/v0/host.rs index d742a43444..a75ecf4243 100644 --- a/tests/e2e/v0/host.rs +++ b/tests/e2e/v0/host.rs @@ -267,9 +267,13 @@ fn call_host_func() { let mut env = TestHost::new(); - let instance = ModuleInstance::new(&module, &ImportsBuilder::new().with_resolver("env", &env)) - .expect("Failed to instantiate module") - .assert_no_start(); + let instance = ModuleInstance::new( + &module, + &ImportsBuilder::new().with_resolver("env", &env), + None, + ) + .expect("Failed to instantiate module") + .assert_no_start(); assert_eq!( instance @@ -298,9 +302,13 @@ fn resume_call_host_func() { let mut env = TestHost::new(); - let instance = ModuleInstance::new(&module, &ImportsBuilder::new().with_resolver("env", &env)) - .expect("Failed to instantiate module") - .assert_no_start(); + let instance = ModuleInstance::new( + &module, + &ImportsBuilder::new().with_resolver("env", &env), + None, + ) + .expect("Failed to instantiate module") + .assert_no_start(); let export = instance.export_by_name("test").unwrap(); let func_instance = export.as_func().unwrap(); @@ -342,10 +350,13 @@ fn resume_call_host_func_type_mismatch() { let mut env = TestHost::new(); - let instance = - ModuleInstance::new(&module, &ImportsBuilder::new().with_resolver("env", &env)) - .expect("Failed to instantiate module") - .assert_no_start(); + let instance = ModuleInstance::new( + &module, + &ImportsBuilder::new().with_resolver("env", &env), + None, + ) + .expect("Failed to instantiate module") + .assert_no_start(); let export = instance.export_by_name("test").unwrap(); let func_instance = export.as_func().unwrap(); @@ -395,9 +406,13 @@ fn host_err() { let mut env = TestHost::new(); - let instance = ModuleInstance::new(&module, &ImportsBuilder::new().with_resolver("env", &env)) - .expect("Failed to instantiate module") - .assert_no_start(); + let instance = ModuleInstance::new( + &module, + &ImportsBuilder::new().with_resolver("env", &env), + None, + ) + .expect("Failed to instantiate module") + .assert_no_start(); let error = instance .invoke_export("test", &[], &mut env) @@ -433,9 +448,13 @@ fn modify_mem_with_host_funcs() { let mut env = TestHost::new(); - let instance = ModuleInstance::new(&module, &ImportsBuilder::new().with_resolver("env", &env)) - .expect("Failed to instantiate module") - .assert_no_start(); + let instance = ModuleInstance::new( + &module, + &ImportsBuilder::new().with_resolver("env", &env), + None, + ) + .expect("Failed to instantiate module") + .assert_no_start(); instance .invoke_export("modify_mem", &[], &mut env) @@ -477,9 +496,13 @@ fn pull_internal_mem_from_module() { trap_sub_result: None, }; - let instance = ModuleInstance::new(&module, &ImportsBuilder::new().with_resolver("env", &env)) - .expect("Failed to instantiate module") - .assert_no_start(); + let instance = ModuleInstance::new( + &module, + &ImportsBuilder::new().with_resolver("env", &env), + None, + ) + .expect("Failed to instantiate module") + .assert_no_start(); // Get memory instance exported by name 'mem' from the module instance. let internal_mem = instance @@ -528,9 +551,13 @@ fn recursion() { let mut env = TestHost::new(); - let instance = ModuleInstance::new(&module, &ImportsBuilder::new().with_resolver("env", &env)) - .expect("Failed to instantiate module") - .assert_no_start(); + let instance = ModuleInstance::new( + &module, + &ImportsBuilder::new().with_resolver("env", &env), + None, + ) + .expect("Failed to instantiate module") + .assert_no_start(); // Put instance into the env, because $recurse function expects // attached module instance. @@ -638,6 +665,7 @@ fn defer_providing_externals() { let instance = ModuleInstance::new( &module, &ImportsBuilder::new().with_resolver("host", &host_import_resolver), + None, ) .expect("Failed to instantiate module") .assert_no_start(); @@ -752,6 +780,7 @@ fn two_envs_one_externals() { let trusted_instance = ModuleInstance::new( &trusted_module, &ImportsBuilder::new().with_resolver("env", &PrivilegedResolver), + None, ) .expect("Failed to instantiate module") .assert_no_start(); @@ -761,6 +790,7 @@ fn two_envs_one_externals() { &ImportsBuilder::new() .with_resolver("env", &OrdinaryResolver) .with_resolver("trusted", &trusted_instance), + None, ) .expect("Failed to instantiate module") .assert_no_start(); @@ -868,6 +898,7 @@ fn dynamically_add_host_func() { let instance = ModuleInstance::new( &module, &ImportsBuilder::new().with_resolver("env", &host_externals), + None, ) .expect("Failed to instantiate module") .assert_no_start(); diff --git a/tests/e2e/v0/wasm.rs b/tests/e2e/v0/wasm.rs index a148733463..410f187c86 100644 --- a/tests/e2e/v0/wasm.rs +++ b/tests/e2e/v0/wasm.rs @@ -113,9 +113,13 @@ fn interpreter_inc_i32() { let env = Env::new(); - let instance = ModuleInstance::new(&module, &ImportsBuilder::new().with_resolver("env", &env)) - .expect("Failed to instantiate module") - .assert_no_start(); + let instance = ModuleInstance::new( + &module, + &ImportsBuilder::new().with_resolver("env", &env), + None, + ) + .expect("Failed to instantiate module") + .assert_no_start(); let i32_val = 42; // the functions expects a single i32 parameter @@ -141,9 +145,13 @@ fn interpreter_accumulate_u8() { let module = load_from_file(WASM_FILE); let env = Env::new(); - let instance = ModuleInstance::new(&module, &ImportsBuilder::new().with_resolver("env", &env)) - .expect("Failed to instantiate module") - .assert_no_start(); + let instance = ModuleInstance::new( + &module, + &ImportsBuilder::new().with_resolver("env", &env), + None, + ) + .expect("Failed to instantiate module") + .assert_no_start(); let env_memory = env.memory; diff --git a/tests/spec/v0/run.rs b/tests/spec/v0/run.rs index c29aead5de..39e962f40a 100644 --- a/tests/spec/v0/run.rs +++ b/tests/spec/v0/run.rs @@ -283,7 +283,7 @@ fn try_load_module(wasm: &[u8]) -> Result { fn try_load(wasm: &[u8], spec_driver: &mut SpecDriver) -> Result<(), Error> { let module = try_load_module(wasm)?; - let instance = ModuleInstance::new(&module, &ImportsBuilder::default())?; + let instance = ModuleInstance::new(&module, &ImportsBuilder::default(), None)?; instance .run_start(spec_driver.spec_module()) .map_err(Error::Start)?; @@ -296,7 +296,7 @@ fn load_module( spec_driver: &mut SpecDriver, ) -> Result { let module = try_load_module(wasm)?; - let instance = ModuleInstance::new(&module, spec_driver) + let instance = ModuleInstance::new(&module, spec_driver, None) .map_err(|e| Error::Load(e.to_string()))? .run_start(spec_driver.spec_module()) .map_err(Error::Start)?; From 1f92d8846aaee0507a07cf76810426ed2942b639 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Wed, 27 Jul 2022 20:02:08 +0800 Subject: [PATCH 042/129] seperate host call from wasm call --- src/isa.rs | 25 +++++++++++++++++++------ src/runner.rs | 22 ++++++++++++---------- src/tracer/etable.rs | 23 ++++++----------------- src/tracer/mod.rs | 8 ++++---- src/types.rs | 6 +++--- 5 files changed, 44 insertions(+), 40 deletions(-) diff --git a/src/isa.rs b/src/isa.rs index 3b0daf16d3..1c23700101 100644 --- a/src/isa.rs +++ b/src/isa.rs @@ -72,6 +72,7 @@ use std::collections::HashMap; use alloc::vec::Vec; use parity_wasm::elements::ValueType; use specs::{ + host_function::TIME_FUNC_INDEX, itable::{BinOp, BitOp, Opcode, RelOp}, mtable::VarType, }; @@ -383,12 +384,24 @@ impl<'a> Instruction<'a> { vec![] }, }, - Instruction::Call(func_index) => Opcode::Call { - index: function_mapping - .get(&func_index) - .unwrap() - .index_within_jtable, - }, + Instruction::Call(func_index) => { + let func_desc = function_mapping.get(&func_index).unwrap(); + + match func_desc.ftype { + specs::types::FunctionType::WasmFunction => Opcode::Call { + index: function_mapping + .get(&func_index) + .unwrap() + .index_within_jtable, + }, + specs::types::FunctionType::HostFunction(host_function_idx) => { + match host_function_idx { + TIME_FUNC_INDEX => Opcode::CallHostTime, + _ => unreachable!(), + } + } + } + } Instruction::CallIndirect(_) => todo!(), Instruction::Drop => Opcode::Drop, Instruction::Select => todo!(), diff --git a/src/runner.rs b/src/runner.rs index c13a6877d3..4c1c7b06a4 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -29,6 +29,7 @@ use alloc::{boxed::Box, vec::Vec}; use core::{cell::RefCell, fmt, ops, u32, usize}; use parity_wasm::elements::Local; use specs::{ + host_function::TIME_FUNC_INDEX, itable::{BinOp, BitOp, RelOp}, step::StepInfo, types::Value, @@ -592,21 +593,22 @@ impl Interpreter { } } isa::Instruction::Call(index) => { - if let RunInstructionTracePre::Call { args } = pre_status.unwrap() { + if let RunInstructionTracePre::Call { args: _ } = pre_status.unwrap() { let tracer = self.tracer.clone().unwrap(); let tracer = tracer.borrow(); let desc = tracer.function_index_translation.get(&index).unwrap(); - StepInfo::Call { - index: desc.index_within_jtable, - ftype: desc.ftype.clone(), - signature: desc.signature.clone().into(), - args: args - .iter() - .map(|arg| <_>::from_value_internal(*arg)) - .collect(), - ret: None, + match desc.ftype { + specs::types::FunctionType::WasmFunction => StepInfo::Call { + index: desc.index_within_jtable, + }, + specs::types::FunctionType::HostFunction(host_function_idx) => { + match host_function_idx { + TIME_FUNC_INDEX => StepInfo::CallHostTime { ret_val: None }, + _ => unreachable!(), + } + } } } else { unreachable!() diff --git a/src/tracer/etable.rs b/src/tracer/etable.rs index 8128bf0ef6..faf913c736 100644 --- a/src/tracer/etable.rs +++ b/src/tracer/etable.rs @@ -145,23 +145,12 @@ impl ETable { pub fn resolve_host_call(&mut self, ret: u64) { let entry = self.entries.last_mut().unwrap(); - if let StepInfo::Call { - index, - ftype, - signature, - args, - ret: _, - } = &entry.step - { - entry.step = StepInfo::Call { - index: *index, - ftype: ftype.clone(), - signature: signature.clone(), - args: args.clone(), - ret: Some(ret), - }; - } else { - unreachable!() + match entry.step { + StepInfo::CallHostTime { ret_val } => { + assert!(ret_val.is_none()); + entry.step = StepInfo::CallHostTime { ret_val: Some(ret) } + } + _ => unreachable!(), } } } diff --git a/src/tracer/mod.rs b/src/tracer/mod.rs index f5649e96bc..0bfa034599 100644 --- a/src/tracer/mod.rs +++ b/src/tracer/mod.rs @@ -17,10 +17,10 @@ pub mod itable; pub mod jtable; #[derive(Debug)] -pub(crate) struct FuncDesc { - pub(crate) index_within_jtable: u16, - pub(crate) ftype: FunctionType, - pub(crate) signature: Signature, +pub struct FuncDesc { + pub index_within_jtable: u16, + pub ftype: FunctionType, + pub signature: Signature, } #[derive(Debug)] diff --git a/src/types.rs b/src/types.rs index b5e152ab02..cc9a2bb3d3 100644 --- a/src/types.rs +++ b/src/types.rs @@ -71,9 +71,9 @@ impl Signature { } } -impl Into for Signature { - fn into(self) -> specs::types::Signature { - specs::types::Signature { +impl Into for Signature { + fn into(self) -> specs::host_function::Signature { + specs::host_function::Signature { params: self .params() .iter() From c0760619e657d0191adbe4e570a3ed6c9df3d79c Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Thu, 28 Jul 2022 09:34:30 +0800 Subject: [PATCH 043/129] update callhosttime stepinfo --- src/tracer/etable.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/tracer/etable.rs b/src/tracer/etable.rs index faf913c736..16acc48a90 100644 --- a/src/tracer/etable.rs +++ b/src/tracer/etable.rs @@ -142,13 +142,15 @@ impl ETable { eentry } - pub fn resolve_host_call(&mut self, ret: u64) { + pub fn resolve_host_call(&mut self, ret: i64) { let entry = self.entries.last_mut().unwrap(); match entry.step { StepInfo::CallHostTime { ret_val } => { assert!(ret_val.is_none()); - entry.step = StepInfo::CallHostTime { ret_val: Some(ret) } + entry.step = StepInfo::CallHostTime { + ret_val: Some(ret as u64), + } } _ => unreachable!(), } From a30296827b5ec3fd5a0f74dec862fa17413ecfbc Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Thu, 28 Jul 2022 09:45:07 +0800 Subject: [PATCH 044/129] give type of time function to u64 --- src/runner.rs | 17 ++++++++++++++--- src/tracer/etable.rs | 16 +--------------- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/src/runner.rs b/src/runner.rs index 4c1c7b06a4..3bbb60d5ba 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -388,9 +388,20 @@ impl Interpreter { if let Some(return_val) = return_val { if let Some(tracer) = self.tracer.clone() { let mut tracer = (*tracer).borrow_mut(); - tracer.etable.resolve_host_call(<_>::from_value_internal( - return_val.into(), - )) + + let entry = tracer.etable.entries.last_mut().unwrap(); + + match entry.step { + StepInfo::CallHostTime { ret_val } => { + assert!(ret_val.is_none()); + entry.step = StepInfo::CallHostTime { + ret_val: Some(<_>::from_value_internal( + return_val.into(), + )), + } + } + _ => unreachable!(), + } } } } diff --git a/src/tracer/etable.rs b/src/tracer/etable.rs index 16acc48a90..8f16aa85ff 100644 --- a/src/tracer/etable.rs +++ b/src/tracer/etable.rs @@ -87,7 +87,7 @@ impl Into for EEntry { #[derive(Debug)] pub struct ETable { eid: u64, - entries: Vec, + pub(crate) entries: Vec, } impl Default for ETable { @@ -141,18 +141,4 @@ impl ETable { eentry } - - pub fn resolve_host_call(&mut self, ret: i64) { - let entry = self.entries.last_mut().unwrap(); - - match entry.step { - StepInfo::CallHostTime { ret_val } => { - assert!(ret_val.is_none()); - entry.step = StepInfo::CallHostTime { - ret_val: Some(ret as u64), - } - } - _ => unreachable!(), - } - } } From ffdcef91a0c04fade126eda90182799f5ee2a544 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Fri, 29 Jul 2022 11:30:11 +0800 Subject: [PATCH 045/129] support store --- src/runner.rs | 44 ++++++++++++++++++++++++++++++++++++-------- src/tracer/etable.rs | 1 + 2 files changed, 37 insertions(+), 8 deletions(-) diff --git a/src/runner.rs b/src/runner.rs index 3bbb60d5ba..cefa7e4ba3 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -478,6 +478,17 @@ impl Interpreter { effective_address(offset, raw_address).map_or(None, |addr| Some(addr)); let mmid = tracer.lookup_memory_instance(&function_context.memory.clone().unwrap()); + let pre_block_value = address.map(|address| { + let mut buf = [0u8; 8]; + function_context + .memory + .clone() + .unwrap() + .get_into(address / 8 * 8, &mut buf) + .unwrap(); + u64::from_le_bytes(buf) + }); + Some(RunInstructionTracePre::Store { offset, raw_address, @@ -485,6 +496,7 @@ impl Interpreter { value, vtype: parity_wasm::elements::ValueType::I32, mmid: mmid as u64, + pre_block_value, }) } @@ -635,14 +647,16 @@ impl Interpreter { mmid, } = pre_status.unwrap() { - let mut buf = [0u8; 8]; - context - .memory - .clone() - .unwrap() - .get_into(offset, &mut buf) - .unwrap(); - let block_value = u64::from_le_bytes(buf); + let block_value = { + let mut buf = [0u8; 8]; + context + .memory + .clone() + .unwrap() + .get_into(effective_address.unwrap() / 8 * 8, &mut buf) + .unwrap(); + u64::from_le_bytes(buf) + }; StepInfo::Load { vtype: vtype.into(), @@ -665,8 +679,20 @@ impl Interpreter { value, vtype, mmid, + pre_block_value, } = pre_status.unwrap() { + let updated_block_value = { + let mut buf = [0u8; 8]; + context + .memory + .clone() + .unwrap() + .get_into(effective_address.unwrap() / 8 * 8, &mut buf) + .unwrap(); + u64::from_le_bytes(buf) + }; + StepInfo::Store { vtype: vtype.into(), offset, @@ -674,6 +700,8 @@ impl Interpreter { effective_address: effective_address.unwrap(), value: value as u32 as u64, mmid, + pre_block_value: pre_block_value.unwrap(), + updated_block_value, } } else { unreachable!() diff --git a/src/tracer/etable.rs b/src/tracer/etable.rs index 8f16aa85ff..e6e127efb8 100644 --- a/src/tracer/etable.rs +++ b/src/tracer/etable.rs @@ -38,6 +38,7 @@ pub enum RunInstructionTracePre { value: i32, vtype: ValueType, mmid: u64, + pre_block_value: Option, }, I32BinOp { From 590153234125333044b46de90051a7a21151be80 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Mon, 1 Aug 2022 15:49:34 +0800 Subject: [PATCH 046/129] support ge gt --- src/isa.rs | 20 +++++++++++++---- src/runner.rs | 59 ++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 70 insertions(+), 9 deletions(-) diff --git a/src/isa.rs b/src/isa.rs index 1c23700101..69cdd1258b 100644 --- a/src/isa.rs +++ b/src/isa.rs @@ -459,12 +459,24 @@ impl<'a> Instruction<'a> { }, Instruction::I32LtS => todo!(), Instruction::I32LtU => todo!(), - Instruction::I32GtS => todo!(), - Instruction::I32GtU => todo!(), + Instruction::I32GtS => Opcode::Rel { + class: RelOp::SignedGt, + vtype: VarType::I32, + }, + Instruction::I32GtU => Opcode::Rel { + class: RelOp::UnsignedGt, + vtype: VarType::I32, + }, Instruction::I32LeS => todo!(), Instruction::I32LeU => todo!(), - Instruction::I32GeS => todo!(), - Instruction::I32GeU => todo!(), + Instruction::I32GeS => Opcode::Rel { + class: RelOp::SignedGe, + vtype: VarType::I32, + }, + Instruction::I32GeU => Opcode::Rel { + class: RelOp::UnsignedGe, + vtype: VarType::I32, + }, Instruction::I64Eqz => todo!(), Instruction::I64Eq => todo!(), Instruction::I64Ne => todo!(), diff --git a/src/runner.rs b/src/runner.rs index cefa7e4ba3..7fb9ad7bf7 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -502,11 +502,12 @@ impl Interpreter { isa::Instruction::I32Const(_) => None, - isa::Instruction::I32Eq => Some(RunInstructionTracePre::I32Comp { - left: <_>::from_value_internal(*self.value_stack.pick(2)), - right: <_>::from_value_internal(*self.value_stack.pick(1)), - }), - isa::Instruction::I32Ne => Some(RunInstructionTracePre::I32Comp { + isa::Instruction::I32Eq + | isa::Instruction::I32Ne + | isa::Instruction::I32GtS + | isa::Instruction::I32GtU + | isa::Instruction::I32GeS + | isa::Instruction::I32GeU => Some(RunInstructionTracePre::I32Comp { left: <_>::from_value_internal(*self.value_stack.pick(2)), right: <_>::from_value_internal(*self.value_stack.pick(1)), }), @@ -734,6 +735,54 @@ impl Interpreter { unreachable!() } } + isa::Instruction::I32GtS => { + if let RunInstructionTracePre::I32Comp { left, right } = pre_status.unwrap() { + StepInfo::I32Comp { + class: RelOp::SignedGt, + left, + right, + value: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } + isa::Instruction::I32GtU => { + if let RunInstructionTracePre::I32Comp { left, right } = pre_status.unwrap() { + StepInfo::I32Comp { + class: RelOp::UnsignedGt, + left, + right, + value: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } + isa::Instruction::I32GeS => { + if let RunInstructionTracePre::I32Comp { left, right } = pre_status.unwrap() { + StepInfo::I32Comp { + class: RelOp::SignedGe, + left, + right, + value: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } + isa::Instruction::I32GeU => { + if let RunInstructionTracePre::I32Comp { left, right } = pre_status.unwrap() { + StepInfo::I32Comp { + class: RelOp::UnsignedGe, + left, + right, + value: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } isa::Instruction::I32Add => { if let RunInstructionTracePre::I32BinOp { class, left, right } = pre_status.unwrap() From f5f8966ab97878944517f41a488230a3a6172f2e Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Mon, 1 Aug 2022 17:16:03 +0800 Subject: [PATCH 047/129] support shl, shr_u --- src/isa.rs | 12 ++++++++--- src/runner.rs | 48 ++++++++++++++++++++++++++++++-------------- src/tracer/etable.rs | 14 ++++--------- 3 files changed, 46 insertions(+), 28 deletions(-) diff --git a/src/isa.rs b/src/isa.rs index 69cdd1258b..c399dd1c81 100644 --- a/src/isa.rs +++ b/src/isa.rs @@ -73,7 +73,7 @@ use alloc::vec::Vec; use parity_wasm::elements::ValueType; use specs::{ host_function::TIME_FUNC_INDEX, - itable::{BinOp, BitOp, Opcode, RelOp}, + itable::{BinOp, BitOp, Opcode, RelOp, ShiftOp}, mtable::VarType, }; @@ -519,9 +519,15 @@ impl<'a> Instruction<'a> { vtype: VarType::I32, }, Instruction::I32Xor => todo!(), - Instruction::I32Shl => todo!(), + Instruction::I32Shl => Opcode::BinShift { + class: ShiftOp::Shl, + vtype: VarType::I32, + }, Instruction::I32ShrS => todo!(), - Instruction::I32ShrU => todo!(), + Instruction::I32ShrU => Opcode::BinShift { + class: ShiftOp::UnsignedShr, + vtype: VarType::I32, + }, Instruction::I32Rotl => todo!(), Instruction::I32Rotr => todo!(), Instruction::I64Clz => todo!(), diff --git a/src/runner.rs b/src/runner.rs index 7fb9ad7bf7..b3d9cceee2 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -30,7 +30,7 @@ use core::{cell::RefCell, fmt, ops, u32, usize}; use parity_wasm::elements::Local; use specs::{ host_function::TIME_FUNC_INDEX, - itable::{BinOp, BitOp, RelOp}, + itable::{BinOp, BitOp, RelOp, ShiftOp}, step::StepInfo, types::Value, }; @@ -512,13 +512,10 @@ impl Interpreter { right: <_>::from_value_internal(*self.value_stack.pick(1)), }), - isa::Instruction::I32Add => Some(RunInstructionTracePre::I32BinOp { - class: BinOp::Add, - left: <_>::from_value_internal(*self.value_stack.pick(2)), - right: <_>::from_value_internal(*self.value_stack.pick(1)), - }), - isa::Instruction::I32Or => Some(RunInstructionTracePre::I32BinBitOp { - class: BitOp::Or, + isa::Instruction::I32Add + | isa::Instruction::I32Shl + | isa::Instruction::I32ShrU + | isa::Instruction::I32Or => Some(RunInstructionTracePre::I32BinOp { left: <_>::from_value_internal(*self.value_stack.pick(2)), right: <_>::from_value_internal(*self.value_stack.pick(1)), }), @@ -785,10 +782,9 @@ impl Interpreter { } isa::Instruction::I32Add => { - if let RunInstructionTracePre::I32BinOp { class, left, right } = pre_status.unwrap() - { + if let RunInstructionTracePre::I32BinOp { left, right } = pre_status.unwrap() { StepInfo::I32BinOp { - class, + class: BinOp::Add, left, right, value: <_>::from_value_internal(*self.value_stack.top()), @@ -798,11 +794,33 @@ impl Interpreter { } } isa::Instruction::I32Or => { - if let RunInstructionTracePre::I32BinBitOp { class, left, right } = - pre_status.unwrap() - { + if let RunInstructionTracePre::I32BinOp { left, right } = pre_status.unwrap() { StepInfo::I32BinBitOp { - class, + class: BitOp::Or, + left, + right, + value: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } + isa::Instruction::I32Shl => { + if let RunInstructionTracePre::I32BinOp { left, right } = pre_status.unwrap() { + StepInfo::I32BinShiftOp { + class: ShiftOp::Shl, + left, + right, + value: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } + isa::Instruction::I32ShrU => { + if let RunInstructionTracePre::I32BinOp { left, right } = pre_status.unwrap() { + StepInfo::I32BinShiftOp { + class: ShiftOp::UnsignedShr, left, right, value: <_>::from_value_internal(*self.value_stack.top()), diff --git a/src/tracer/etable.rs b/src/tracer/etable.rs index e6e127efb8..034d96d434 100644 --- a/src/tracer/etable.rs +++ b/src/tracer/etable.rs @@ -1,9 +1,5 @@ use parity_wasm::elements::ValueType; -use specs::{ - etable::EventTableEntry, - itable::{BinOp, BitOp, Opcode}, - step::StepInfo, -}; +use specs::{etable::EventTableEntry, itable::Opcode, step::StepInfo}; use crate::{runner::ValueInternal, DEFAULT_VALUE_STACK_LIMIT}; @@ -42,14 +38,12 @@ pub enum RunInstructionTracePre { }, I32BinOp { - class: BinOp, left: i32, right: i32, }, - I32BinBitOp { - class: BitOp, - left: i32, - right: i32, + I32BinShiftOp { + left: u64, + right: u64, }, I32Comp { From 71dc455cdcfea939ff6dfb3d62b6a286fc14eb27 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Tue, 2 Aug 2022 13:26:59 +0800 Subject: [PATCH 048/129] support br and setlocal --- src/isa.rs | 15 +++++++++++++-- src/runner.rs | 39 ++++++++++++++++++++++++++------------- src/tracer/etable.rs | 2 +- 3 files changed, 40 insertions(+), 16 deletions(-) diff --git a/src/isa.rs b/src/isa.rs index c399dd1c81..6752802aba 100644 --- a/src/isa.rs +++ b/src/isa.rs @@ -358,12 +358,23 @@ impl<'a> Instruction<'a> { offset: offset as u64, vtype: typ.into(), }, - Instruction::SetLocal(..) => todo!(), + Instruction::SetLocal(offset, typ) => Opcode::LocalSet { + offset: offset as u64, + vtype: typ.into(), + }, Instruction::TeeLocal(offset, typ) => Opcode::LocalTee { offset: offset as u64, vtype: typ.into(), }, - Instruction::Br(_) => todo!(), + Instruction::Br(Target { dst_pc, drop_keep }) => Opcode::Br { + drop: drop_keep.drop, + keep: if let Keep::Single(t) = drop_keep.keep { + vec![t.into()] + } else { + vec![] + }, + dst_pc, + }, Instruction::BrIfEqz(_) => todo!(), Instruction::BrIfNez(Target { dst_pc, drop_keep }) => Opcode::BrIf { drop: drop_keep.drop, diff --git a/src/runner.rs b/src/runner.rs index b3d9cceee2..41dbde9df4 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -420,9 +420,10 @@ impl Interpreter { let tracer = tracer.borrow(); match *instructions { - isa::Instruction::GetLocal(depth, vtype) => { - let value = self.value_stack.pick(depth as usize); - Some(RunInstructionTracePre::GetLocal { + isa::Instruction::GetLocal(..) => None, + isa::Instruction::SetLocal(depth, vtype) => { + let value = self.value_stack.top(); + Some(RunInstructionTracePre::SetLocal { depth, value: value.clone(), vtype, @@ -430,6 +431,7 @@ impl Interpreter { } isa::Instruction::TeeLocal(..) => None, + isa::Instruction::Br(_) => None, isa::Instruction::BrIfNez(_) => Some(RunInstructionTracePre::BrIfNez { value: <_>::from_value_internal(*self.value_stack.top()), }), @@ -534,14 +536,19 @@ impl Interpreter { instructions: &isa::Instruction, ) -> StepInfo { match *instructions { - isa::Instruction::GetLocal(..) => { - if let RunInstructionTracePre::GetLocal { + isa::Instruction::GetLocal(depth, vtype) => StepInfo::GetLocal { + depth, + value: <_>::from_value_internal(*self.value_stack.top()), + vtype: vtype.into(), + }, + isa::Instruction::SetLocal(..) => { + if let RunInstructionTracePre::SetLocal { depth, value, vtype, } = pre_status.unwrap() { - StepInfo::GetLocal { + StepInfo::SetLocal { depth, value: <_>::from_value_internal(value), vtype: vtype.into(), @@ -556,14 +563,21 @@ impl Interpreter { vtype: vtype.into(), }, + isa::Instruction::Br(target) => StepInfo::Br { + dst_pc: target.dst_pc, + drop: target.drop_keep.drop, + keep: if let Keep::Single(t) = target.drop_keep.keep { + vec![t.into()] + } else { + vec![] + }, + keep_values: match target.drop_keep.keep { + Keep::Single(_) => vec![(*self.value_stack.top()).0], + Keep::None => vec![], + }, + }, isa::Instruction::BrIfNez(target) => { if let RunInstructionTracePre::BrIfNez { value } = pre_status.unwrap() { - let mut drop_values = vec![]; - - for i in 1..=target.drop_keep.drop { - drop_values.push(*self.value_stack.pick(i as usize)); - } - StepInfo::BrIfNez { condition: value, dst_pc: target.dst_pc, @@ -573,7 +587,6 @@ impl Interpreter { } else { vec![] }, - drop_values: drop_values.iter().map(|v| v.0).collect::>(), keep_values: match target.drop_keep.keep { Keep::Single(_) => vec![(*self.value_stack.top()).0], Keep::None => vec![], diff --git a/src/tracer/etable.rs b/src/tracer/etable.rs index 034d96d434..079f72c688 100644 --- a/src/tracer/etable.rs +++ b/src/tracer/etable.rs @@ -14,7 +14,7 @@ pub enum RunInstructionTracePre { args: Vec, }, - GetLocal { + SetLocal { depth: u32, value: ValueInternal, vtype: ValueType, From d39ed0770403778834c95523cf95db40c4e7e81e Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Wed, 3 Aug 2022 12:12:43 +0800 Subject: [PATCH 049/129] support le_u and lt_u --- src/isa.rs | 10 ++++++++-- src/runner.rs | 28 +++++++++++++++++++++++++++- src/tracer/mod.rs | 3 ++- 3 files changed, 37 insertions(+), 4 deletions(-) diff --git a/src/isa.rs b/src/isa.rs index 6752802aba..fd17fe5ae1 100644 --- a/src/isa.rs +++ b/src/isa.rs @@ -469,7 +469,10 @@ impl<'a> Instruction<'a> { vtype: VarType::I32, }, Instruction::I32LtS => todo!(), - Instruction::I32LtU => todo!(), + Instruction::I32LtU => Opcode::Rel { + class: RelOp::UnsignedLt, + vtype: VarType::I32, + }, Instruction::I32GtS => Opcode::Rel { class: RelOp::SignedGt, vtype: VarType::I32, @@ -479,7 +482,10 @@ impl<'a> Instruction<'a> { vtype: VarType::I32, }, Instruction::I32LeS => todo!(), - Instruction::I32LeU => todo!(), + Instruction::I32LeU => Opcode::Rel { + class: RelOp::UnsignedLe, + vtype: VarType::I32, + }, Instruction::I32GeS => Opcode::Rel { class: RelOp::SignedGe, vtype: VarType::I32, diff --git a/src/runner.rs b/src/runner.rs index 41dbde9df4..33b12f3c03 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -509,7 +509,9 @@ impl Interpreter { | isa::Instruction::I32GtS | isa::Instruction::I32GtU | isa::Instruction::I32GeS - | isa::Instruction::I32GeU => Some(RunInstructionTracePre::I32Comp { + | isa::Instruction::I32GeU + | isa::Instruction::I32LtU + | isa::Instruction::I32LeU => Some(RunInstructionTracePre::I32Comp { left: <_>::from_value_internal(*self.value_stack.pick(2)), right: <_>::from_value_internal(*self.value_stack.pick(1)), }), @@ -793,6 +795,30 @@ impl Interpreter { unreachable!() } } + isa::Instruction::I32LtU => { + if let RunInstructionTracePre::I32Comp { left, right } = pre_status.unwrap() { + StepInfo::I32Comp { + class: RelOp::UnsignedLt, + left, + right, + value: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } + isa::Instruction::I32LeU => { + if let RunInstructionTracePre::I32Comp { left, right } = pre_status.unwrap() { + StepInfo::I32Comp { + class: RelOp::UnsignedLe, + left, + right, + value: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } isa::Instruction::I32Add => { if let RunInstructionTracePre::I32BinOp { left, right } = pre_status.unwrap() { diff --git a/src/tracer/mod.rs b/src/tracer/mod.rs index 0bfa034599..6a07680d66 100644 --- a/src/tracer/mod.rs +++ b/src/tracer/mod.rs @@ -88,7 +88,8 @@ impl Tracer { impl Tracer { pub(crate) fn push_init_memory(&mut self, memref: MemoryRef) { let pages = (*memref).limits().initial(); - for i in 0..(pages * 1024) { + // one page contains 64KB*1024/8=8192 u64 entries + for i in 0..(pages * 8192) { let mut buf = [0u8; 8]; (*memref).get_into(i * 8, &mut buf).unwrap(); self.imtable From 41e5377ba9602d237e5127e05b167a5ab3c00821 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Mon, 22 Aug 2022 21:47:16 +0800 Subject: [PATCH 050/129] support some i64 insts --- src/isa.rs | 15 ++++++++--- src/runner.rs | 63 ++++++++++++++++++++++++++++++++++++++++++-- src/tracer/etable.rs | 4 +++ 3 files changed, 77 insertions(+), 5 deletions(-) diff --git a/src/isa.rs b/src/isa.rs index fd17fe5ae1..d49f6fb113 100644 --- a/src/isa.rs +++ b/src/isa.rs @@ -422,7 +422,10 @@ impl<'a> Instruction<'a> { offset, vtype: VarType::I32, }, - Instruction::I64Load(_) => todo!(), + Instruction::I64Load(offset) => Opcode::Load { + offset, + vtype: VarType::I64, + }, Instruction::F32Load(_) => todo!(), Instruction::F64Load(_) => todo!(), Instruction::I32Load8S(_) => todo!(), @@ -498,11 +501,17 @@ impl<'a> Instruction<'a> { Instruction::I64Eq => todo!(), Instruction::I64Ne => todo!(), Instruction::I64LtS => todo!(), - Instruction::I64LtU => todo!(), + Instruction::I64LtU => Opcode::Rel { + class: RelOp::UnsignedLt, + vtype: VarType::I64, + }, Instruction::I64GtS => todo!(), Instruction::I64GtU => todo!(), Instruction::I64LeS => todo!(), - Instruction::I64LeU => todo!(), + Instruction::I64LeU => Opcode::Rel { + class: RelOp::UnsignedLe, + vtype: VarType::I64, + }, Instruction::I64GeS => todo!(), Instruction::I64GeU => todo!(), Instruction::F32Eq => todo!(), diff --git a/src/runner.rs b/src/runner.rs index 33b12f3c03..e790325f00 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -473,6 +473,25 @@ impl Interpreter { mmid: mmid as u64, }) } + isa::Instruction::I64Load(offset) => { + let raw_address = <_>::from_value_internal(*self.value_stack.top()); + let address = + effective_address(offset, raw_address).map_or(None, |addr| Some(addr)); + let mmid = tracer.lookup_memory_instance( + &function_context + .memory + .clone() + .expect("Due to validation memory should exists"), + ); + + Some(RunInstructionTracePre::Load { + offset, + raw_address, + effective_address: address, + vtype: parity_wasm::elements::ValueType::I64, + mmid: mmid as u64, + }) + } isa::Instruction::I32Store(offset) => { let value = <_>::from_value_internal(*self.value_stack.pick(1)); let raw_address = <_>::from_value_internal(*self.value_stack.pick(2)); @@ -516,6 +535,18 @@ impl Interpreter { right: <_>::from_value_internal(*self.value_stack.pick(1)), }), + isa::Instruction::I64Eq + | isa::Instruction::I64Ne + | isa::Instruction::I64GtS + | isa::Instruction::I64GtU + | isa::Instruction::I64GeS + | isa::Instruction::I64GeU + | isa::Instruction::I64LtU + | isa::Instruction::I64LeU => Some(RunInstructionTracePre::I64Comp { + left: <_>::from_value_internal(*self.value_stack.pick(2)), + right: <_>::from_value_internal(*self.value_stack.pick(1)), + }), + isa::Instruction::I32Add | isa::Instruction::I32Shl | isa::Instruction::I32ShrU @@ -651,7 +682,7 @@ impl Interpreter { } } - isa::Instruction::I32Load(..) => { + isa::Instruction::I32Load(..) | isa::Instruction::I64Load(..) => { if let RunInstructionTracePre::Load { offset, raw_address, @@ -820,6 +851,31 @@ impl Interpreter { } } + isa::Instruction::I64LtU => { + if let RunInstructionTracePre::I64Comp { left, right } = pre_status.unwrap() { + StepInfo::I64Comp { + class: RelOp::UnsignedLt, + left, + right, + value: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } + isa::Instruction::I64LeU => { + if let RunInstructionTracePre::I64Comp { left, right } = pre_status.unwrap() { + StepInfo::I64Comp { + class: RelOp::UnsignedLe, + left, + right, + value: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } + isa::Instruction::I32Add => { if let RunInstructionTracePre::I32BinOp { left, right } = pre_status.unwrap() { StepInfo::I32BinOp { @@ -868,7 +924,10 @@ impl Interpreter { unreachable!() } } - _ => unimplemented!(), + _ => { + println!("{:?}", instructions); + unimplemented!() + } } } diff --git a/src/tracer/etable.rs b/src/tracer/etable.rs index 079f72c688..92d187abf7 100644 --- a/src/tracer/etable.rs +++ b/src/tracer/etable.rs @@ -50,6 +50,10 @@ pub enum RunInstructionTracePre { left: i32, right: i32, }, + I64Comp { + left: i64, + right: i64, + }, Drop, } From e3e54ac69052630e728b7062d5b81465b67ba15c Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Mon, 22 Aug 2022 22:21:40 +0800 Subject: [PATCH 051/129] support i64const --- src/runner.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/runner.rs b/src/runner.rs index e790325f00..fc1fd14842 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -522,6 +522,7 @@ impl Interpreter { } isa::Instruction::I32Const(_) => None, + isa::Instruction::I64Const(_) => None, isa::Instruction::I32Eq | isa::Instruction::I32Ne @@ -753,6 +754,7 @@ impl Interpreter { } isa::Instruction::I32Const(value) => StepInfo::I32Const { value }, + isa::Instruction::I64Const(value) => StepInfo::I64Const { value }, isa::Instruction::I32Eq => { if let RunInstructionTracePre::I32Comp { left, right } = pre_status.unwrap() { From 682edb8a873976140cbbd043eb543f6e85b00c24 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Wed, 24 Aug 2022 15:26:29 +0800 Subject: [PATCH 052/129] support insts for sha --- src/isa.rs | 94 ++++++++++++---- src/module.rs | 5 + src/runner.rs | 255 +++++++++++++++++++++++++++++++++++++++++-- src/tracer/etable.rs | 27 ++++- src/tracer/mod.rs | 27 +++++ 5 files changed, 378 insertions(+), 30 deletions(-) diff --git a/src/isa.rs b/src/isa.rs index d49f6fb113..0a20b52cd2 100644 --- a/src/isa.rs +++ b/src/isa.rs @@ -73,8 +73,8 @@ use alloc::vec::Vec; use parity_wasm::elements::ValueType; use specs::{ host_function::TIME_FUNC_INDEX, - itable::{BinOp, BitOp, Opcode, RelOp, ShiftOp}, - mtable::VarType, + itable::{BinOp, BitOp, Opcode, RelOp, ShiftOp, TestOp}, + mtable::{MemoryReadSize, MemoryStoreSize, VarType}, }; use crate::tracer::FuncDesc; @@ -375,7 +375,15 @@ impl<'a> Instruction<'a> { }, dst_pc, }, - Instruction::BrIfEqz(_) => todo!(), + Instruction::BrIfEqz(Target { dst_pc, drop_keep }) => Opcode::BrIfEqz { + drop: drop_keep.drop, + keep: if let Keep::Single(t) = drop_keep.keep { + vec![t.into()] + } else { + vec![] + }, + dst_pc, + }, Instruction::BrIfNez(Target { dst_pc, drop_keep }) => Opcode::BrIf { drop: drop_keep.drop, keep: if let Keep::Single(t) = drop_keep.keep { @@ -386,7 +394,7 @@ impl<'a> Instruction<'a> { dst_pc, }, Instruction::BrTable(_) => todo!(), - Instruction::Unreachable => todo!(), + Instruction::Unreachable => Opcode::Unreachable, Instruction::Return(drop_keep) => Opcode::Return { drop: drop_keep.drop, keep: if let Keep::Single(t) = drop_keep.keep { @@ -415,25 +423,35 @@ impl<'a> Instruction<'a> { } Instruction::CallIndirect(_) => todo!(), Instruction::Drop => Opcode::Drop, - Instruction::Select => todo!(), + Instruction::Select => Opcode::Select, Instruction::GetGlobal(_) => todo!(), Instruction::SetGlobal(_) => todo!(), Instruction::I32Load(offset) => Opcode::Load { offset, vtype: VarType::I32, + size: MemoryReadSize::U32, }, Instruction::I64Load(offset) => Opcode::Load { offset, vtype: VarType::I64, + size: MemoryReadSize::I64, }, Instruction::F32Load(_) => todo!(), Instruction::F64Load(_) => todo!(), Instruction::I32Load8S(_) => todo!(), - Instruction::I32Load8U(_) => todo!(), + Instruction::I32Load8U(offset) => Opcode::Load { + offset, + vtype: VarType::I32, + size: MemoryReadSize::U8, + }, Instruction::I32Load16S(_) => todo!(), Instruction::I32Load16U(_) => todo!(), Instruction::I64Load8S(_) => todo!(), - Instruction::I64Load8U(_) => todo!(), + Instruction::I64Load8U(offset) => Opcode::Load { + offset, + vtype: VarType::I64, + size: MemoryReadSize::U8, + }, Instruction::I64Load16S(_) => todo!(), Instruction::I64Load16U(_) => todo!(), Instruction::I64Load32S(_) => todo!(), @@ -441,11 +459,20 @@ impl<'a> Instruction<'a> { Instruction::I32Store(offset) => Opcode::Store { offset, vtype: VarType::I32, + size: MemoryStoreSize::Byte32, + }, + Instruction::I64Store(offset) => Opcode::Store { + offset, + vtype: VarType::I64, + size: MemoryStoreSize::Byte64, }, - Instruction::I64Store(_) => todo!(), Instruction::F32Store(_) => todo!(), Instruction::F64Store(_) => todo!(), - Instruction::I32Store8(_) => todo!(), + Instruction::I32Store8(offset) => Opcode::Store { + offset, + vtype: VarType::I32, + size: MemoryStoreSize::Byte8, + }, Instruction::I32Store16(_) => todo!(), Instruction::I64Store8(_) => todo!(), Instruction::I64Store16(_) => todo!(), @@ -462,7 +489,10 @@ impl<'a> Instruction<'a> { }, Instruction::F32Const(_) => todo!(), Instruction::F64Const(_) => todo!(), - Instruction::I32Eqz => todo!(), + Instruction::I32Eqz => Opcode::Test { + class: TestOp::Eqz, + vtype: VarType::I32, + }, Instruction::I32Eq => Opcode::Rel { class: RelOp::Eq, vtype: VarType::I32, @@ -533,18 +563,27 @@ impl<'a> Instruction<'a> { class: BinOp::Add, vtype: VarType::I32, }, - Instruction::I32Sub => todo!(), + Instruction::I32Sub => Opcode::Bin { + class: BinOp::Sub, + vtype: VarType::I32, + }, Instruction::I32Mul => todo!(), Instruction::I32DivS => todo!(), Instruction::I32DivU => todo!(), Instruction::I32RemS => todo!(), Instruction::I32RemU => todo!(), - Instruction::I32And => todo!(), + Instruction::I32And => Opcode::BinBit { + class: BitOp::And, + vtype: VarType::I32, + }, Instruction::I32Or => Opcode::BinBit { class: BitOp::Or, vtype: VarType::I32, }, - Instruction::I32Xor => todo!(), + Instruction::I32Xor => Opcode::BinBit { + class: BitOp::Xor, + vtype: VarType::I32, + }, Instruction::I32Shl => Opcode::BinShift { class: ShiftOp::Shl, vtype: VarType::I32, @@ -554,12 +593,18 @@ impl<'a> Instruction<'a> { class: ShiftOp::UnsignedShr, vtype: VarType::I32, }, - Instruction::I32Rotl => todo!(), + Instruction::I32Rotl => Opcode::BinShift { + class: ShiftOp::Rotl, + vtype: VarType::I32, + }, Instruction::I32Rotr => todo!(), Instruction::I64Clz => todo!(), Instruction::I64Ctz => todo!(), Instruction::I64Popcnt => todo!(), - Instruction::I64Add => todo!(), + Instruction::I64Add => Opcode::Bin { + class: BinOp::Add, + vtype: VarType::I64, + }, Instruction::I64Sub => todo!(), Instruction::I64Mul => todo!(), Instruction::I64DivS => todo!(), @@ -567,11 +612,20 @@ impl<'a> Instruction<'a> { Instruction::I64RemS => todo!(), Instruction::I64RemU => todo!(), Instruction::I64And => todo!(), - Instruction::I64Or => todo!(), + Instruction::I64Or => Opcode::BinBit { + class: BitOp::Or, + vtype: VarType::I64, + }, Instruction::I64Xor => todo!(), - Instruction::I64Shl => todo!(), + Instruction::I64Shl => Opcode::BinShift { + class: ShiftOp::Shl, + vtype: VarType::I64, + }, Instruction::I64ShrS => todo!(), - Instruction::I64ShrU => todo!(), + Instruction::I64ShrU => Opcode::BinShift { + class: ShiftOp::UnsignedShr, + vtype: VarType::I64, + }, Instruction::I64Rotl => todo!(), Instruction::I64Rotr => todo!(), Instruction::F32Abs => todo!(), @@ -602,13 +656,13 @@ impl<'a> Instruction<'a> { Instruction::F64Min => todo!(), Instruction::F64Max => todo!(), Instruction::F64Copysign => todo!(), - Instruction::I32WrapI64 => todo!(), + Instruction::I32WrapI64 => Opcode::I32WrapI64, Instruction::I32TruncSF32 => todo!(), Instruction::I32TruncUF32 => todo!(), Instruction::I32TruncSF64 => todo!(), Instruction::I32TruncUF64 => todo!(), Instruction::I64ExtendSI32 => todo!(), - Instruction::I64ExtendUI32 => todo!(), + Instruction::I64ExtendUI32 => Opcode::I64ExtendUI32, Instruction::I64TruncSF32 => todo!(), Instruction::I64TruncUF32 => todo!(), Instruction::I64TruncSF64 => todo!(), diff --git a/src/module.rs b/src/module.rs index ed66f0144f..5e90b7820d 100644 --- a/src/module.rs +++ b/src/module.rs @@ -603,6 +603,11 @@ impl ModuleInstance { let module = module_ref.loaded_module; match tracer { Some(tracer) => { + /* + (*tracer) + .borrow_mut() + .statistics_instructions(&module_ref.instance); + */ (*tracer) .borrow_mut() .register_module_instance(module, &module_ref.instance); diff --git a/src/runner.rs b/src/runner.rs index fc1fd14842..59cda348ec 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -31,6 +31,7 @@ use parity_wasm::elements::Local; use specs::{ host_function::TIME_FUNC_INDEX, itable::{BinOp, BitOp, RelOp, ShiftOp}, + mtable::{MemoryReadSize, MemoryStoreSize}, step::StepInfo, types::Value, }; @@ -432,6 +433,9 @@ impl Interpreter { isa::Instruction::TeeLocal(..) => None, isa::Instruction::Br(_) => None, + isa::Instruction::BrIfEqz(_) => Some(RunInstructionTracePre::BrIfEqz { + value: <_>::from_value_internal(*self.value_stack.top()), + }), isa::Instruction::BrIfNez(_) => Some(RunInstructionTracePre::BrIfNez { value: <_>::from_value_internal(*self.value_stack.top()), }), @@ -454,7 +458,13 @@ impl Interpreter { } isa::Instruction::Drop => Some(RunInstructionTracePre::Drop), - isa::Instruction::I32Load(offset) => { + isa::Instruction::I32Load(offset) | isa::Instruction::I32Load8U(offset) => { + let load_size = match *instructions { + isa::Instruction::I32Load(..) => MemoryReadSize::S32, + isa::Instruction::I32Load8U(..) => MemoryReadSize::U8, + _ => unreachable!(), + }; + let raw_address = <_>::from_value_internal(*self.value_stack.top()); let address = effective_address(offset, raw_address).map_or(None, |addr| Some(addr)); @@ -470,10 +480,16 @@ impl Interpreter { raw_address, effective_address: address, vtype: parity_wasm::elements::ValueType::I32, + load_size, mmid: mmid as u64, }) } - isa::Instruction::I64Load(offset) => { + isa::Instruction::I64Load(offset) | isa::Instruction::I64Load8U(offset) => { + let load_size = match *instructions { + isa::Instruction::I64Load(..) => MemoryReadSize::I64, + isa::Instruction::I64Load8U(..) => MemoryReadSize::U8, + _ => unreachable!(), + }; let raw_address = <_>::from_value_internal(*self.value_stack.top()); let address = effective_address(offset, raw_address).map_or(None, |addr| Some(addr)); @@ -489,10 +505,51 @@ impl Interpreter { raw_address, effective_address: address, vtype: parity_wasm::elements::ValueType::I64, + load_size, mmid: mmid as u64, }) } - isa::Instruction::I32Store(offset) => { + isa::Instruction::I32Store(offset) | isa::Instruction::I32Store8(offset) => { + let store_size = match *instructions { + isa::Instruction::I32Store8(_) => MemoryStoreSize::Byte8, + isa::Instruction::I32Store(_) => MemoryStoreSize::Byte32, + _ => unreachable!(), + }; + + let value: u32 = <_>::from_value_internal(*self.value_stack.pick(1)); + let raw_address = <_>::from_value_internal(*self.value_stack.pick(2)); + let address = + effective_address(offset, raw_address).map_or(None, |addr| Some(addr)); + let mmid = tracer.lookup_memory_instance(&function_context.memory.clone().unwrap()); + + let pre_block_value = address.map(|address| { + let mut buf = [0u8; 8]; + function_context + .memory + .clone() + .unwrap() + .get_into(address / 8 * 8, &mut buf) + .unwrap(); + u64::from_le_bytes(buf) + }); + + Some(RunInstructionTracePre::Store { + offset, + raw_address, + effective_address: address, + value: value as u64, + vtype: parity_wasm::elements::ValueType::I32, + store_size, + mmid: mmid as u64, + pre_block_value, + }) + } + isa::Instruction::I64Store(offset) => { + let store_size = match *instructions { + isa::Instruction::I64Store(..) => MemoryStoreSize::Byte64, + _ => unreachable!(), + }; + let value = <_>::from_value_internal(*self.value_stack.pick(1)); let raw_address = <_>::from_value_internal(*self.value_stack.pick(2)); let address = @@ -515,7 +572,8 @@ impl Interpreter { raw_address, effective_address: address, value, - vtype: parity_wasm::elements::ValueType::I32, + vtype: parity_wasm::elements::ValueType::I64, + store_size, mmid: mmid as u64, pre_block_value, }) @@ -524,6 +582,10 @@ impl Interpreter { isa::Instruction::I32Const(_) => None, isa::Instruction::I64Const(_) => None, + isa::Instruction::I32Eqz => Some(RunInstructionTracePre::I32Single( + <_>::from_value_internal(*self.value_stack.pick(1)), + )), + isa::Instruction::I32Eq | isa::Instruction::I32Ne | isa::Instruction::I32GtS @@ -549,13 +611,32 @@ impl Interpreter { }), isa::Instruction::I32Add + | isa::Instruction::I32Sub | isa::Instruction::I32Shl | isa::Instruction::I32ShrU - | isa::Instruction::I32Or => Some(RunInstructionTracePre::I32BinOp { + | isa::Instruction::I32And + | isa::Instruction::I32Or + | isa::Instruction::I32Xor + | isa::Instruction::I32Rotl => Some(RunInstructionTracePre::I32BinOp { + left: <_>::from_value_internal(*self.value_stack.pick(2)), + right: <_>::from_value_internal(*self.value_stack.pick(1)), + }), + + isa::Instruction::I64Add + | isa::Instruction::I64Shl + | isa::Instruction::I64ShrU + | isa::Instruction::I64Or => Some(RunInstructionTracePre::I64BinOp { left: <_>::from_value_internal(*self.value_stack.pick(2)), right: <_>::from_value_internal(*self.value_stack.pick(1)), }), + isa::Instruction::I32WrapI64 => Some(RunInstructionTracePre::I32WrapI64 { + value: <_>::from_value_internal(*self.value_stack.pick(1)), + }), + isa::Instruction::I64ExtendUI32 => Some(RunInstructionTracePre::I64ExtendUI32 { + value: <_>::from_value_internal(*self.value_stack.pick(1)), + }), + _ => { println!("{:?}", *instructions); unimplemented!() @@ -610,6 +691,26 @@ impl Interpreter { Keep::None => vec![], }, }, + isa::Instruction::BrIfEqz(target) => { + if let RunInstructionTracePre::BrIfEqz { value } = pre_status.unwrap() { + StepInfo::BrIfEqz { + condition: value, + dst_pc: target.dst_pc, + drop: target.drop_keep.drop, + keep: if let Keep::Single(t) = target.drop_keep.keep { + vec![t.into()] + } else { + vec![] + }, + keep_values: match target.drop_keep.keep { + Keep::Single(_) => vec![(*self.value_stack.top()).0], + Keep::None => vec![], + }, + } + } else { + unreachable!() + } + } isa::Instruction::BrIfNez(target) => { if let RunInstructionTracePre::BrIfNez { value } = pre_status.unwrap() { StepInfo::BrIfNez { @@ -683,12 +784,16 @@ impl Interpreter { } } - isa::Instruction::I32Load(..) | isa::Instruction::I64Load(..) => { + isa::Instruction::I32Load(..) + | isa::Instruction::I32Load8U(..) + | isa::Instruction::I64Load(..) + | isa::Instruction::I64Load8U(..) => { if let RunInstructionTracePre::Load { offset, raw_address, effective_address, vtype, + load_size, mmid, } = pre_status.unwrap() { @@ -705,6 +810,7 @@ impl Interpreter { StepInfo::Load { vtype: vtype.into(), + load_size, offset, raw_address, effective_address: effective_address.unwrap(), @@ -716,13 +822,16 @@ impl Interpreter { unreachable!() } } - isa::Instruction::I32Store(..) => { + isa::Instruction::I32Store(..) + | isa::Instruction::I32Store8(..) + | isa::Instruction::I64Store(..) => { if let RunInstructionTracePre::Store { offset, raw_address, effective_address, value, vtype, + store_size, mmid, pre_block_value, } = pre_status.unwrap() @@ -740,10 +849,11 @@ impl Interpreter { StepInfo::Store { vtype: vtype.into(), + store_size, offset, raw_address, effective_address: effective_address.unwrap(), - value: value as u32 as u64, + value: value as u64, mmid, pre_block_value: pre_block_value.unwrap(), updated_block_value, @@ -756,6 +866,16 @@ impl Interpreter { isa::Instruction::I32Const(value) => StepInfo::I32Const { value }, isa::Instruction::I64Const(value) => StepInfo::I64Const { value }, + isa::Instruction::I32Eqz => { + if let RunInstructionTracePre::I32Single(value) = pre_status.unwrap() { + StepInfo::I32Eqz { + value, + result: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } isa::Instruction::I32Eq => { if let RunInstructionTracePre::I32Comp { left, right } = pre_status.unwrap() { StepInfo::I32Comp { @@ -890,6 +1010,30 @@ impl Interpreter { unreachable!() } } + isa::Instruction::I32Sub => { + if let RunInstructionTracePre::I32BinOp { left, right } = pre_status.unwrap() { + StepInfo::I32BinOp { + class: BinOp::Sub, + left, + right, + value: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } + isa::Instruction::I32And => { + if let RunInstructionTracePre::I32BinOp { left, right } = pre_status.unwrap() { + StepInfo::I32BinBitOp { + class: BitOp::And, + left, + right, + value: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } isa::Instruction::I32Or => { if let RunInstructionTracePre::I32BinOp { left, right } = pre_status.unwrap() { StepInfo::I32BinBitOp { @@ -902,6 +1046,18 @@ impl Interpreter { unreachable!() } } + isa::Instruction::I32Xor => { + if let RunInstructionTracePre::I32BinOp { left, right } = pre_status.unwrap() { + StepInfo::I32BinBitOp { + class: BitOp::Xor, + left, + right, + value: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } isa::Instruction::I32Shl => { if let RunInstructionTracePre::I32BinOp { left, right } = pre_status.unwrap() { StepInfo::I32BinShiftOp { @@ -926,6 +1082,89 @@ impl Interpreter { unreachable!() } } + isa::Instruction::I32Rotl => { + if let RunInstructionTracePre::I32BinOp { left, right } = pre_status.unwrap() { + StepInfo::I32BinShiftOp { + class: ShiftOp::Rotl, + left, + right, + value: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } + + isa::Instruction::I64Add => { + if let RunInstructionTracePre::I64BinOp { left, right } = pre_status.unwrap() { + StepInfo::I64BinOp { + class: BinOp::Add, + left, + right, + value: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } + isa::Instruction::I64Or => { + if let RunInstructionTracePre::I64BinOp { left, right } = pre_status.unwrap() { + StepInfo::I64BinBitOp { + class: BitOp::Or, + left, + right, + value: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } + isa::Instruction::I64Shl => { + if let RunInstructionTracePre::I64BinOp { left, right } = pre_status.unwrap() { + StepInfo::I64BinShiftOp { + class: ShiftOp::Shl, + left, + right, + value: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } + isa::Instruction::I64ShrU => { + if let RunInstructionTracePre::I64BinOp { left, right } = pre_status.unwrap() { + StepInfo::I64BinShiftOp { + class: ShiftOp::UnsignedShr, + left, + right, + value: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } + + isa::Instruction::I32WrapI64 => { + if let RunInstructionTracePre::I32WrapI64 { value } = pre_status.unwrap() { + StepInfo::I32WrapI64 { + value, + result: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } + isa::Instruction::I64ExtendUI32 => { + if let RunInstructionTracePre::I64ExtendUI32 { value } = pre_status.unwrap() { + StepInfo::I64ExtendUI32 { + value, + result: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } + _ => { println!("{:?}", instructions); unimplemented!() diff --git a/src/tracer/etable.rs b/src/tracer/etable.rs index 92d187abf7..354b383456 100644 --- a/src/tracer/etable.rs +++ b/src/tracer/etable.rs @@ -1,11 +1,19 @@ use parity_wasm::elements::ValueType; -use specs::{etable::EventTableEntry, itable::Opcode, step::StepInfo}; +use specs::{ + etable::EventTableEntry, + itable::Opcode, + mtable::{MemoryReadSize, MemoryStoreSize}, + step::StepInfo, +}; use crate::{runner::ValueInternal, DEFAULT_VALUE_STACK_LIMIT}; use super::itable::IEntry; pub enum RunInstructionTracePre { + BrIfEqz { + value: i32, + }, BrIfNez { value: i32, }, @@ -25,14 +33,16 @@ pub enum RunInstructionTracePre { raw_address: u32, effective_address: Option, // use option in case of memory out of bound vtype: ValueType, + load_size: MemoryReadSize, mmid: u64, }, Store { offset: u32, raw_address: u32, effective_address: Option, - value: i32, + value: u64, vtype: ValueType, + store_size: MemoryStoreSize, mmid: u64, pre_block_value: Option, }, @@ -46,6 +56,12 @@ pub enum RunInstructionTracePre { right: u64, }, + I64BinOp { + left: i64, + right: i64, + }, + + I32Single(i32), I32Comp { left: i32, right: i32, @@ -55,6 +71,13 @@ pub enum RunInstructionTracePre { right: i64, }, + I32WrapI64 { + value: i64, + }, + I64ExtendUI32 { + value: i32, + }, + Drop, } diff --git a/src/tracer/mod.rs b/src/tracer/mod.rs index 6a07680d66..82f05a70ff 100644 --- a/src/tracer/mod.rs +++ b/src/tracer/mod.rs @@ -100,6 +100,33 @@ impl Tracer { .push((memref, self.next_memory_id())); } + pub(crate) fn statistics_instructions<'a>(&mut self, module_instance: &ModuleRef) { + let mut func_index = 0; + let mut insts = vec![]; + + loop { + if let Some(func) = module_instance.func_by_index(func_index) { + let body = func.body().unwrap(); + + let code = &body.code.vec; + + for inst in code { + if insts.iter().position(|i| i == inst).is_none() { + insts.push(inst.clone()) + } + } + } else { + break; + } + + func_index = func_index + 1; + } + + for inst in insts { + println!("{:?}", inst); + } + } + pub(crate) fn register_module_instance( &mut self, module: &Module, From 88c6597f097ab0b0de36c2d523cff4b7501b8be8 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Thu, 25 Aug 2022 14:22:40 +0800 Subject: [PATCH 053/129] support i64.sub --- src/isa.rs | 5 ++++- src/runner.rs | 13 +++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/isa.rs b/src/isa.rs index 0a20b52cd2..9a916aa9f6 100644 --- a/src/isa.rs +++ b/src/isa.rs @@ -605,7 +605,10 @@ impl<'a> Instruction<'a> { class: BinOp::Add, vtype: VarType::I64, }, - Instruction::I64Sub => todo!(), + Instruction::I64Sub => Opcode::Bin { + class: BinOp::Sub, + vtype: VarType::I64, + }, Instruction::I64Mul => todo!(), Instruction::I64DivS => todo!(), Instruction::I64DivU => todo!(), diff --git a/src/runner.rs b/src/runner.rs index 59cda348ec..de3fc03ff8 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -623,6 +623,7 @@ impl Interpreter { }), isa::Instruction::I64Add + | isa::Instruction::I64Sub | isa::Instruction::I64Shl | isa::Instruction::I64ShrU | isa::Instruction::I64Or => Some(RunInstructionTracePre::I64BinOp { @@ -1107,6 +1108,18 @@ impl Interpreter { unreachable!() } } + isa::Instruction::I64Sub => { + if let RunInstructionTracePre::I64BinOp { left, right } = pre_status.unwrap() { + StepInfo::I64BinOp { + class: BinOp::Sub, + left, + right, + value: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } isa::Instruction::I64Or => { if let RunInstructionTracePre::I64BinOp { left, right } = pre_status.unwrap() { StepInfo::I64BinBitOp { From bcf87e3bc6d3e752b3d5863e8fcd4fe6ad70c94a Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Thu, 25 Aug 2022 15:18:10 +0800 Subject: [PATCH 054/129] group eqz into test --- src/runner.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/runner.rs b/src/runner.rs index de3fc03ff8..4fb1cf54f7 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -31,7 +31,7 @@ use parity_wasm::elements::Local; use specs::{ host_function::TIME_FUNC_INDEX, itable::{BinOp, BitOp, RelOp, ShiftOp}, - mtable::{MemoryReadSize, MemoryStoreSize}, + mtable::{MemoryReadSize, MemoryStoreSize, VarType}, step::StepInfo, types::Value, }; @@ -869,8 +869,9 @@ impl Interpreter { isa::Instruction::I32Eqz => { if let RunInstructionTracePre::I32Single(value) = pre_status.unwrap() { - StepInfo::I32Eqz { - value, + StepInfo::Test { + vtype: VarType::I32, + value: value as u32 as u64, result: <_>::from_value_internal(*self.value_stack.top()), } } else { From 524b14ddba59135e3fcd086f132be40b400e0e18 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Thu, 25 Aug 2022 16:43:03 +0800 Subject: [PATCH 055/129] group wrap and extend --- src/isa.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/isa.rs b/src/isa.rs index 9a916aa9f6..01a4f5e3e5 100644 --- a/src/isa.rs +++ b/src/isa.rs @@ -73,7 +73,7 @@ use alloc::vec::Vec; use parity_wasm::elements::ValueType; use specs::{ host_function::TIME_FUNC_INDEX, - itable::{BinOp, BitOp, Opcode, RelOp, ShiftOp, TestOp}, + itable::{BinOp, BitOp, ConversionOp, Opcode, RelOp, ShiftOp, TestOp}, mtable::{MemoryReadSize, MemoryStoreSize, VarType}, }; @@ -659,13 +659,17 @@ impl<'a> Instruction<'a> { Instruction::F64Min => todo!(), Instruction::F64Max => todo!(), Instruction::F64Copysign => todo!(), - Instruction::I32WrapI64 => Opcode::I32WrapI64, + Instruction::I32WrapI64 => Opcode::Conversion { + class: ConversionOp::I32WrapI64, + }, Instruction::I32TruncSF32 => todo!(), Instruction::I32TruncUF32 => todo!(), Instruction::I32TruncSF64 => todo!(), Instruction::I32TruncUF64 => todo!(), Instruction::I64ExtendSI32 => todo!(), - Instruction::I64ExtendUI32 => Opcode::I64ExtendUI32, + Instruction::I64ExtendUI32 => Opcode::Conversion { + class: ConversionOp::I64ExtendUI32, + }, Instruction::I64TruncSF32 => todo!(), Instruction::I64TruncUF32 => todo!(), Instruction::I64TruncSF64 => todo!(), From 058c6f6a50a82b14982bde472e4201ba8db4d279 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Fri, 26 Aug 2022 14:11:22 +0800 Subject: [PATCH 056/129] support select and call host --- src/isa.rs | 6 +----- src/runner.rs | 39 +++++++++++++++++++++++++++++++++------ src/tracer/etable.rs | 5 +++++ 3 files changed, 39 insertions(+), 11 deletions(-) diff --git a/src/isa.rs b/src/isa.rs index 01a4f5e3e5..3088eeab1d 100644 --- a/src/isa.rs +++ b/src/isa.rs @@ -72,7 +72,6 @@ use std::collections::HashMap; use alloc::vec::Vec; use parity_wasm::elements::ValueType; use specs::{ - host_function::TIME_FUNC_INDEX, itable::{BinOp, BitOp, ConversionOp, Opcode, RelOp, ShiftOp, TestOp}, mtable::{MemoryReadSize, MemoryStoreSize, VarType}, }; @@ -414,10 +413,7 @@ impl<'a> Instruction<'a> { .index_within_jtable, }, specs::types::FunctionType::HostFunction(host_function_idx) => { - match host_function_idx { - TIME_FUNC_INDEX => Opcode::CallHostTime, - _ => unreachable!(), - } + Opcode::CallHost(host_function_idx) } } } diff --git a/src/runner.rs b/src/runner.rs index 4fb1cf54f7..99eba5bd9a 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -29,7 +29,6 @@ use alloc::{boxed::Box, vec::Vec}; use core::{cell::RefCell, fmt, ops, u32, usize}; use parity_wasm::elements::Local; use specs::{ - host_function::TIME_FUNC_INDEX, itable::{BinOp, BitOp, RelOp, ShiftOp}, mtable::{MemoryReadSize, MemoryStoreSize, VarType}, step::StepInfo, @@ -393,9 +392,13 @@ impl Interpreter { let entry = tracer.etable.entries.last_mut().unwrap(); match entry.step { - StepInfo::CallHostTime { ret_val } => { + StepInfo::CallHost { + host_function_idx, + ret_val, + } => { assert!(ret_val.is_none()); - entry.step = StepInfo::CallHostTime { + entry.step = StepInfo::CallHost { + host_function_idx, ret_val: Some(<_>::from_value_internal( return_val.into(), )), @@ -456,7 +459,13 @@ impl Interpreter { Some(RunInstructionTracePre::Call { args }) } + isa::Instruction::Drop => Some(RunInstructionTracePre::Drop), + isa::Instruction::Select => Some(RunInstructionTracePre::Select { + first: <_>::from_value_internal(*self.value_stack.pick(1)), + second: <_>::from_value_internal(*self.value_stack.pick(2)), + cond: <_>::from_value_internal(*self.value_stack.pick(3)), + }), isa::Instruction::I32Load(offset) | isa::Instruction::I32Load8U(offset) => { let load_size = match *instructions { @@ -762,6 +771,24 @@ impl Interpreter { unreachable!() } } + isa::Instruction::Select => { + if let RunInstructionTracePre::Select { + first, + second, + cond, + } = pre_status.unwrap() + { + StepInfo::Select { + first, + second, + cond, + result: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } + isa::Instruction::Call(index) => { if let RunInstructionTracePre::Call { args: _ } = pre_status.unwrap() { let tracer = self.tracer.clone().unwrap(); @@ -774,9 +801,9 @@ impl Interpreter { index: desc.index_within_jtable, }, specs::types::FunctionType::HostFunction(host_function_idx) => { - match host_function_idx { - TIME_FUNC_INDEX => StepInfo::CallHostTime { ret_val: None }, - _ => unreachable!(), + StepInfo::CallHost { + host_function_idx, + ret_val: None, } } } diff --git a/src/tracer/etable.rs b/src/tracer/etable.rs index 354b383456..04c6b1758e 100644 --- a/src/tracer/etable.rs +++ b/src/tracer/etable.rs @@ -79,6 +79,11 @@ pub enum RunInstructionTracePre { }, Drop, + Select { + first: u64, + second: u64, + cond: u64, + } } #[derive(Debug, Clone)] From 0df0adbd84a444ae9cea22b328798460df795883 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Mon, 29 Aug 2022 17:39:10 +0800 Subject: [PATCH 057/129] save args for host call --- src/runner.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/runner.rs b/src/runner.rs index 99eba5bd9a..0cbf706043 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -391,14 +391,16 @@ impl Interpreter { let entry = tracer.etable.entries.last_mut().unwrap(); - match entry.step { + match &entry.step { StepInfo::CallHost { host_function_idx, + args, ret_val, } => { assert!(ret_val.is_none()); entry.step = StepInfo::CallHost { - host_function_idx, + host_function_idx: *host_function_idx, + args: args.clone(), ret_val: Some(<_>::from_value_internal( return_val.into(), )), @@ -801,8 +803,15 @@ impl Interpreter { index: desc.index_within_jtable, }, specs::types::FunctionType::HostFunction(host_function_idx) => { + let params_len = desc.signature.params().len(); + let mut args: Vec = vec![]; + for i in 0..params_len { + args.push(<_>::from_value_internal(*self.value_stack.pick(1 + i))); + } + StepInfo::CallHost { host_function_idx, + args, ret_val: None, } } From 16fb283bc5a4af32c4a9872d0f73ac8599f666b6 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Mon, 29 Aug 2022 22:39:38 +0800 Subject: [PATCH 058/129] export signature for host function --- src/runner.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/runner.rs b/src/runner.rs index 0cbf706043..30a31e3554 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -396,6 +396,7 @@ impl Interpreter { host_function_idx, args, ret_val, + signature, } => { assert!(ret_val.is_none()); entry.step = StepInfo::CallHost { @@ -404,6 +405,7 @@ impl Interpreter { ret_val: Some(<_>::from_value_internal( return_val.into(), )), + signature: signature.clone(), } } _ => unreachable!(), @@ -813,6 +815,7 @@ impl Interpreter { host_function_idx, args, ret_val: None, + signature: desc.signature.clone().into(), } } } From 2e7046bdc947ba8d7ae71b502054fe119a45cdf7 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Wed, 31 Aug 2022 11:08:42 +0800 Subject: [PATCH 059/129] bugfix: i32.load should use type u32 --- src/runner.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runner.rs b/src/runner.rs index 30a31e3554..cdc2ae6a7c 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -473,7 +473,7 @@ impl Interpreter { isa::Instruction::I32Load(offset) | isa::Instruction::I32Load8U(offset) => { let load_size = match *instructions { - isa::Instruction::I32Load(..) => MemoryReadSize::S32, + isa::Instruction::I32Load(..) => MemoryReadSize::U32, isa::Instruction::I32Load8U(..) => MemoryReadSize::U8, _ => unreachable!(), }; From 0f9328796b3e81ef9de025503844afda5bab109b Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Wed, 31 Aug 2022 11:35:01 +0800 Subject: [PATCH 060/129] remove primitive type u64 and u32 --- src/runner.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/runner.rs b/src/runner.rs index cdc2ae6a7c..b57531db07 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -74,8 +74,6 @@ impl ValueInternal { match ty { specs::types::ValueType::I32 => Value::I32(<_>::from_value_internal(self)), specs::types::ValueType::I64 => Value::I64(<_>::from_value_internal(self)), - specs::types::ValueType::U32 => Value::U32(<_>::from_value_internal(self)), - specs::types::ValueType::U64 => Value::U64(<_>::from_value_internal(self)), } } } From 14cabb948867ef88faf4dd1d2cf6383cafaa58da Mon Sep 17 00:00:00 2001 From: sinka Date: Thu, 8 Sep 2022 19:06:44 +1000 Subject: [PATCH 061/129] support I32Sub/Mul --- src/isa.rs | 5 ++++- src/runner.rs | 13 +++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/isa.rs b/src/isa.rs index 3088eeab1d..06fa73a500 100644 --- a/src/isa.rs +++ b/src/isa.rs @@ -563,7 +563,10 @@ impl<'a> Instruction<'a> { class: BinOp::Sub, vtype: VarType::I32, }, - Instruction::I32Mul => todo!(), + Instruction::I32Mul => Opcode::Bin { + class: BinOp::Mul, + vtype: VarType::I32, + }, Instruction::I32DivS => todo!(), Instruction::I32DivU => todo!(), Instruction::I32RemS => todo!(), diff --git a/src/runner.rs b/src/runner.rs index b57531db07..c64a6660bc 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -623,6 +623,7 @@ impl Interpreter { isa::Instruction::I32Add | isa::Instruction::I32Sub + | isa::Instruction::I32Mul | isa::Instruction::I32Shl | isa::Instruction::I32ShrU | isa::Instruction::I32And @@ -1061,6 +1062,18 @@ impl Interpreter { unreachable!() } } + isa::Instruction::I32Mul => { + if let RunInstructionTracePre::I32BinOp { left, right } = pre_status.unwrap() { + StepInfo::I32BinOp { + class: BinOp::Mul, + left, + right, + value: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } isa::Instruction::I32And => { if let RunInstructionTracePre::I32BinOp { left, right } = pre_status.unwrap() { StepInfo::I32BinBitOp { From 16481df733f83f69a02f2ec5af45833f05e1ec1d Mon Sep 17 00:00:00 2001 From: Heng Zhang Date: Tue, 4 Oct 2022 17:31:28 +0800 Subject: [PATCH 062/129] Add I32Load8S --- src/isa.rs | 6 +++++- src/runner.rs | 4 +++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/isa.rs b/src/isa.rs index 06fa73a500..94d619504e 100644 --- a/src/isa.rs +++ b/src/isa.rs @@ -434,7 +434,11 @@ impl<'a> Instruction<'a> { }, Instruction::F32Load(_) => todo!(), Instruction::F64Load(_) => todo!(), - Instruction::I32Load8S(_) => todo!(), + Instruction::I32Load8S(offset) => Opcode::Load { + offset, + vtype: VarType::I32, + size: MemoryReadSize::S8, + }, Instruction::I32Load8U(offset) => Opcode::Load { offset, vtype: VarType::I32, diff --git a/src/runner.rs b/src/runner.rs index c64a6660bc..6677a005c3 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -469,10 +469,11 @@ impl Interpreter { cond: <_>::from_value_internal(*self.value_stack.pick(3)), }), - isa::Instruction::I32Load(offset) | isa::Instruction::I32Load8U(offset) => { + isa::Instruction::I32Load(offset) | isa::Instruction::I32Load8U(offset) | isa::Instruction::I32Load8S(offset) => { let load_size = match *instructions { isa::Instruction::I32Load(..) => MemoryReadSize::U32, isa::Instruction::I32Load8U(..) => MemoryReadSize::U8, + isa::Instruction::I32Load8S(..) => MemoryReadSize::S8, _ => unreachable!(), }; @@ -825,6 +826,7 @@ impl Interpreter { isa::Instruction::I32Load(..) | isa::Instruction::I32Load8U(..) + | isa::Instruction::I32Load8S(..) | isa::Instruction::I64Load(..) | isa::Instruction::I64Load8U(..) => { if let RunInstructionTracePre::Load { From 723de9c3d681b889781a35c36991b3dddc455b3f Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Tue, 4 Oct 2022 22:42:34 +0800 Subject: [PATCH 063/129] support select --- src/isa.rs | 10 +++++----- src/prepare/compile.rs | 6 +++++- src/runner.rs | 24 ++++++++++-------------- src/tracer/etable.rs | 4 ++-- 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/isa.rs b/src/isa.rs index 94d619504e..a97490cfe5 100644 --- a/src/isa.rs +++ b/src/isa.rs @@ -181,7 +181,7 @@ pub enum Instruction<'a> { CallIndirect(u32), Drop, - Select, + Select(ValueType), GetGlobal(u32), SetGlobal(u32), @@ -419,7 +419,7 @@ impl<'a> Instruction<'a> { } Instruction::CallIndirect(_) => todo!(), Instruction::Drop => Opcode::Drop, - Instruction::Select => Opcode::Select, + Instruction::Select(_) => Opcode::Select, Instruction::GetGlobal(_) => todo!(), Instruction::SetGlobal(_) => todo!(), Instruction::I32Load(offset) => Opcode::Load { @@ -710,7 +710,7 @@ impl<'a> Into for Instruction<'a> { Instruction::Call(_) => 9, Instruction::CallIndirect(_) => 10, Instruction::Drop => 11, - Instruction::Select => 12, + Instruction::Select(..) => 12, Instruction::GetGlobal(_) => 13, Instruction::SetGlobal(_) => 14, Instruction::I32Load(_) => 15, @@ -897,7 +897,7 @@ pub(crate) enum InstructionInternal { CallIndirect(u32), Drop, - Select, + Select(ValueType), GetGlobal(u32), SetGlobal(u32), @@ -1153,7 +1153,7 @@ impl<'a> Iterator for InstructionIter<'a> { InstructionInternal::CallIndirect(x) => Instruction::CallIndirect(x), InstructionInternal::Drop => Instruction::Drop, - InstructionInternal::Select => Instruction::Select, + InstructionInternal::Select(vtype) => Instruction::Select(vtype), InstructionInternal::GetGlobal(x) => Instruction::GetGlobal(x), InstructionInternal::SetGlobal(x) => Instruction::SetGlobal(x), diff --git a/src/prepare/compile.rs b/src/prepare/compile.rs index 831b45535a..b91edcd6f7 100644 --- a/src/prepare/compile.rs +++ b/src/prepare/compile.rs @@ -327,7 +327,11 @@ impl Compiler { } Select => { context.step(instruction)?; - self.sink.emit(isa::InstructionInternal::Select); + if let StackValueType::Specific(t) = context.value_stack.top()? { + self.sink.emit(isa::InstructionInternal::Select(*t)); + } else { + unreachable!() + } } GetLocal(index) => { diff --git a/src/runner.rs b/src/runner.rs index 6677a005c3..4573f5fc88 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -463,10 +463,10 @@ impl Interpreter { } isa::Instruction::Drop => Some(RunInstructionTracePre::Drop), - isa::Instruction::Select => Some(RunInstructionTracePre::Select { - first: <_>::from_value_internal(*self.value_stack.pick(1)), - second: <_>::from_value_internal(*self.value_stack.pick(2)), - cond: <_>::from_value_internal(*self.value_stack.pick(3)), + isa::Instruction::Select(_) => Some(RunInstructionTracePre::Select { + cond: <_>::from_value_internal(*self.value_stack.pick(1)), + val2: <_>::from_value_internal(*self.value_stack.pick(2)), + val1: <_>::from_value_internal(*self.value_stack.pick(3)), }), isa::Instruction::I32Load(offset) | isa::Instruction::I32Load8U(offset) | isa::Instruction::I32Load8S(offset) => { @@ -775,18 +775,14 @@ impl Interpreter { unreachable!() } } - isa::Instruction::Select => { - if let RunInstructionTracePre::Select { - first, - second, - cond, - } = pre_status.unwrap() - { + isa::Instruction::Select(vtype) => { + if let RunInstructionTracePre::Select { val1, val2, cond } = pre_status.unwrap() { StepInfo::Select { - first, - second, + val1, + val2, cond, result: <_>::from_value_internal(*self.value_stack.top()), + vtype: vtype.into(), } } else { unreachable!() @@ -1345,7 +1341,7 @@ impl Interpreter { isa::Instruction::CallIndirect(index) => self.run_call_indirect(context, *index), isa::Instruction::Drop => self.run_drop(), - isa::Instruction::Select => self.run_select(), + isa::Instruction::Select(_) => self.run_select(), isa::Instruction::GetLocal(depth, ..) => self.run_get_local(*depth), isa::Instruction::SetLocal(depth, ..) => self.run_set_local(*depth), diff --git a/src/tracer/etable.rs b/src/tracer/etable.rs index 04c6b1758e..3afcf660f4 100644 --- a/src/tracer/etable.rs +++ b/src/tracer/etable.rs @@ -80,8 +80,8 @@ pub enum RunInstructionTracePre { Drop, Select { - first: u64, - second: u64, + val1: u64, + val2: u64, cond: u64, } } From b340d6dd0b1191d4e7a320f9a79d1496ac11fe59 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Mon, 3 Oct 2022 23:20:25 +0800 Subject: [PATCH 064/129] dump more info for foreign call --- src/isa.rs | 14 ++++++++++---- src/runner.rs | 16 +++++++++++++--- src/tracer/mod.rs | 23 ++++++++++++++++++++--- 3 files changed, 43 insertions(+), 10 deletions(-) diff --git a/src/isa.rs b/src/isa.rs index a97490cfe5..3dafd7380c 100644 --- a/src/isa.rs +++ b/src/isa.rs @@ -405,16 +405,22 @@ impl<'a> Instruction<'a> { Instruction::Call(func_index) => { let func_desc = function_mapping.get(&func_index).unwrap(); - match func_desc.ftype { + match &func_desc.ftype { specs::types::FunctionType::WasmFunction => Opcode::Call { index: function_mapping .get(&func_index) .unwrap() .index_within_jtable, }, - specs::types::FunctionType::HostFunction(host_function_idx) => { - Opcode::CallHost(host_function_idx) - } + specs::types::FunctionType::HostFunction { + plugin, + function_index, + function_name, + } => Opcode::CallHost { + plugin: *plugin, + function_index: *function_index, + function_name: function_name.clone(), + }, } } Instruction::CallIndirect(_) => todo!(), diff --git a/src/runner.rs b/src/runner.rs index 4573f5fc88..68920246aa 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -391,14 +391,18 @@ impl Interpreter { match &entry.step { StepInfo::CallHost { + plugin, host_function_idx, + function_name, args, ret_val, signature, } => { assert!(ret_val.is_none()); entry.step = StepInfo::CallHost { + plugin: *plugin, host_function_idx: *host_function_idx, + function_name: function_name.clone(), args: args.clone(), ret_val: Some(<_>::from_value_internal( return_val.into(), @@ -796,11 +800,15 @@ impl Interpreter { let desc = tracer.function_index_translation.get(&index).unwrap(); - match desc.ftype { + match &desc.ftype { specs::types::FunctionType::WasmFunction => StepInfo::Call { index: desc.index_within_jtable, }, - specs::types::FunctionType::HostFunction(host_function_idx) => { + specs::types::FunctionType::HostFunction { + plugin, + function_index: host_function_idx, + function_name, + } => { let params_len = desc.signature.params().len(); let mut args: Vec = vec![]; for i in 0..params_len { @@ -808,7 +816,9 @@ impl Interpreter { } StepInfo::CallHost { - host_function_idx, + plugin: *plugin, + host_function_idx: *host_function_idx, + function_name: function_name.clone(), args, ret_val: None, signature: desc.signature.clone().into(), diff --git a/src/tracer/mod.rs b/src/tracer/mod.rs index 82f05a70ff..b1669bac0f 100644 --- a/src/tracer/mod.rs +++ b/src/tracer/mod.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use specs::types::FunctionType; +use specs::{host_function::HostFunctionDesc, types::FunctionType}; use crate::{FuncRef, MemoryRef, Module, ModuleRef, Signature}; @@ -35,11 +35,12 @@ pub struct Tracer { last_jump_eid: Vec, function_index_allocator: u32, pub(crate) function_index_translation: HashMap, + pub host_function_index_lookup: HashMap, } impl Tracer { /// Create an empty tracer - pub fn default() -> Self { + pub fn new(host_plugin_lookup: HashMap) -> Self { Tracer { itable: ITable::default(), imtable: IMTable::default(), @@ -51,6 +52,7 @@ impl Tracer { function_lookup: vec![], function_index_allocator: 1, function_index_translation: Default::default(), + host_function_index_lookup: host_plugin_lookup, } } @@ -83,6 +85,13 @@ impl Tracer { self.function_index_allocator = r + 1; r } + + fn lookup_host_plugin(&self, function_index: usize) -> HostFunctionDesc { + self.host_function_index_lookup + .get(&function_index) + .unwrap() + .clone() + } } impl Tracer { @@ -151,7 +160,15 @@ impl Tracer { } crate::func::FuncInstanceInternal::Host { host_func_index, .. - } => FunctionType::HostFunction(host_func_index), + } => { + let plugin_desc = self.lookup_host_plugin(host_func_index); + + FunctionType::HostFunction { + plugin: plugin_desc.plugin, + function_index: host_func_index, + function_name: plugin_desc.name, + } + } }; self.function_lookup From 22f737846b15ed271f02a85214c6af61fb979cd3 Mon Sep 17 00:00:00 2001 From: Heng Zhang Date: Wed, 5 Oct 2022 18:00:27 +0800 Subject: [PATCH 065/129] Add more I64BinShiftOp --- src/isa.rs | 25 +++++++++++++---- src/runner.rs | 75 ++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 92 insertions(+), 8 deletions(-) diff --git a/src/isa.rs b/src/isa.rs index 3dafd7380c..9dfa3fde45 100644 --- a/src/isa.rs +++ b/src/isa.rs @@ -597,7 +597,10 @@ impl<'a> Instruction<'a> { class: ShiftOp::Shl, vtype: VarType::I32, }, - Instruction::I32ShrS => todo!(), + Instruction::I32ShrS => Opcode::BinShift { + class: ShiftOp::SignedShr, + vtype: VarType::I32, + }, Instruction::I32ShrU => Opcode::BinShift { class: ShiftOp::UnsignedShr, vtype: VarType::I32, @@ -606,7 +609,10 @@ impl<'a> Instruction<'a> { class: ShiftOp::Rotl, vtype: VarType::I32, }, - Instruction::I32Rotr => todo!(), + Instruction::I32Rotr => Opcode::BinShift { + class: ShiftOp::Rotr, + vtype: VarType::I32, + }, Instruction::I64Clz => todo!(), Instruction::I64Ctz => todo!(), Instruction::I64Popcnt => todo!(), @@ -633,13 +639,22 @@ impl<'a> Instruction<'a> { class: ShiftOp::Shl, vtype: VarType::I64, }, - Instruction::I64ShrS => todo!(), + Instruction::I64ShrS => Opcode::BinShift { + class: ShiftOp::SignedShr, + vtype: VarType::I64, + }, Instruction::I64ShrU => Opcode::BinShift { class: ShiftOp::UnsignedShr, vtype: VarType::I64, }, - Instruction::I64Rotl => todo!(), - Instruction::I64Rotr => todo!(), + Instruction::I64Rotl => Opcode::BinShift { + class: ShiftOp::Rotl, + vtype: VarType::I64, + }, + Instruction::I64Rotr => Opcode::BinShift { + class: ShiftOp::Rotr, + vtype: VarType::I64, + }, Instruction::F32Abs => todo!(), Instruction::F32Neg => todo!(), Instruction::F32Ceil => todo!(), diff --git a/src/runner.rs b/src/runner.rs index 68920246aa..b21d5f3f90 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -473,7 +473,9 @@ impl Interpreter { val1: <_>::from_value_internal(*self.value_stack.pick(3)), }), - isa::Instruction::I32Load(offset) | isa::Instruction::I32Load8U(offset) | isa::Instruction::I32Load8S(offset) => { + isa::Instruction::I32Load(offset) + | isa::Instruction::I32Load8U(offset) + | isa::Instruction::I32Load8S(offset) => { let load_size = match *instructions { isa::Instruction::I32Load(..) => MemoryReadSize::U32, isa::Instruction::I32Load8U(..) => MemoryReadSize::U8, @@ -631,10 +633,12 @@ impl Interpreter { | isa::Instruction::I32Mul | isa::Instruction::I32Shl | isa::Instruction::I32ShrU + | isa::Instruction::I32ShrS | isa::Instruction::I32And | isa::Instruction::I32Or | isa::Instruction::I32Xor - | isa::Instruction::I32Rotl => Some(RunInstructionTracePre::I32BinOp { + | isa::Instruction::I32Rotl + | isa::Instruction::I32Rotr => Some(RunInstructionTracePre::I32BinOp { left: <_>::from_value_internal(*self.value_stack.pick(2)), right: <_>::from_value_internal(*self.value_stack.pick(1)), }), @@ -643,7 +647,12 @@ impl Interpreter { | isa::Instruction::I64Sub | isa::Instruction::I64Shl | isa::Instruction::I64ShrU - | isa::Instruction::I64Or => Some(RunInstructionTracePre::I64BinOp { + | isa::Instruction::I64ShrS + | isa::Instruction::I64And + | isa::Instruction::I64Or + | isa::Instruction::I64Xor + | isa::Instruction::I64Rotl + | isa::Instruction::I64Rotr => Some(RunInstructionTracePre::I64BinOp { left: <_>::from_value_internal(*self.value_stack.pick(2)), right: <_>::from_value_internal(*self.value_stack.pick(1)), }), @@ -1142,6 +1151,18 @@ impl Interpreter { unreachable!() } } + isa::Instruction::I32ShrS => { + if let RunInstructionTracePre::I32BinOp { left, right } = pre_status.unwrap() { + StepInfo::I32BinShiftOp { + class: ShiftOp::SignedShr, + left, + right, + value: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } isa::Instruction::I32Rotl => { if let RunInstructionTracePre::I32BinOp { left, right } = pre_status.unwrap() { StepInfo::I32BinShiftOp { @@ -1154,6 +1175,18 @@ impl Interpreter { unreachable!() } } + isa::Instruction::I32Rotr => { + if let RunInstructionTracePre::I32BinOp { left, right } = pre_status.unwrap() { + StepInfo::I32BinShiftOp { + class: ShiftOp::Rotr, + left, + right, + value: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } isa::Instruction::I64Add => { if let RunInstructionTracePre::I64BinOp { left, right } = pre_status.unwrap() { @@ -1215,6 +1248,42 @@ impl Interpreter { unreachable!() } } + isa::Instruction::I64ShrS => { + if let RunInstructionTracePre::I64BinOp { left, right } = pre_status.unwrap() { + StepInfo::I64BinShiftOp { + class: ShiftOp::SignedShr, + left, + right, + value: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } + isa::Instruction::I64Rotl => { + if let RunInstructionTracePre::I64BinOp { left, right } = pre_status.unwrap() { + StepInfo::I64BinShiftOp { + class: ShiftOp::Rotl, + left, + right, + value: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } + isa::Instruction::I64Rotr => { + if let RunInstructionTracePre::I64BinOp { left, right } = pre_status.unwrap() { + StepInfo::I64BinShiftOp { + class: ShiftOp::Rotr, + left, + right, + value: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } isa::Instruction::I32WrapI64 => { if let RunInstructionTracePre::I32WrapI64 { value } = pre_status.unwrap() { From a3b39e4822c9cc47a0528af496ad263817095d26 Mon Sep 17 00:00:00 2001 From: Heng Zhang Date: Wed, 5 Oct 2022 21:39:24 +0800 Subject: [PATCH 066/129] Add more BinBitOp --- src/isa.rs | 10 ++++++++-- src/runner.rs | 24 ++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/isa.rs b/src/isa.rs index 9dfa3fde45..4b0f2bb8e5 100644 --- a/src/isa.rs +++ b/src/isa.rs @@ -629,12 +629,18 @@ impl<'a> Instruction<'a> { Instruction::I64DivU => todo!(), Instruction::I64RemS => todo!(), Instruction::I64RemU => todo!(), - Instruction::I64And => todo!(), + Instruction::I64And => Opcode::BinBit { + class: BitOp::And, + vtype: VarType::I64, + }, Instruction::I64Or => Opcode::BinBit { class: BitOp::Or, vtype: VarType::I64, }, - Instruction::I64Xor => todo!(), + Instruction::I64Xor => Opcode::BinBit { + class: BitOp::Xor, + vtype: VarType::I64, + }, Instruction::I64Shl => Opcode::BinShift { class: ShiftOp::Shl, vtype: VarType::I64, diff --git a/src/runner.rs b/src/runner.rs index b21d5f3f90..0fcc501b60 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -1212,6 +1212,18 @@ impl Interpreter { unreachable!() } } + isa::Instruction::I64And => { + if let RunInstructionTracePre::I64BinOp { left, right } = pre_status.unwrap() { + StepInfo::I64BinBitOp { + class: BitOp::And, + left, + right, + value: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } isa::Instruction::I64Or => { if let RunInstructionTracePre::I64BinOp { left, right } = pre_status.unwrap() { StepInfo::I64BinBitOp { @@ -1224,6 +1236,18 @@ impl Interpreter { unreachable!() } } + isa::Instruction::I64Xor => { + if let RunInstructionTracePre::I64BinOp { left, right } = pre_status.unwrap() { + StepInfo::I64BinBitOp { + class: BitOp::Xor, + left, + right, + value: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } isa::Instruction::I64Shl => { if let RunInstructionTracePre::I64BinOp { left, right } = pre_status.unwrap() { StepInfo::I64BinShiftOp { From 226e26f240d19ae1793089501e9cefefdf21dce4 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Thu, 6 Oct 2022 11:43:18 +0800 Subject: [PATCH 067/129] support i64.extend_i32_s --- src/isa.rs | 6 ++++-- src/runner.rs | 14 ++++++++++---- src/tracer/etable.rs | 3 ++- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/isa.rs b/src/isa.rs index 4b0f2bb8e5..3d17b7797c 100644 --- a/src/isa.rs +++ b/src/isa.rs @@ -696,9 +696,11 @@ impl<'a> Instruction<'a> { Instruction::I32TruncUF32 => todo!(), Instruction::I32TruncSF64 => todo!(), Instruction::I32TruncUF64 => todo!(), - Instruction::I64ExtendSI32 => todo!(), + Instruction::I64ExtendSI32 => Opcode::Conversion { + class: ConversionOp::I64ExtendI32s, + }, Instruction::I64ExtendUI32 => Opcode::Conversion { - class: ConversionOp::I64ExtendUI32, + class: ConversionOp::I64ExtendI32u, }, Instruction::I64TruncSF32 => todo!(), Instruction::I64TruncUF32 => todo!(), diff --git a/src/runner.rs b/src/runner.rs index 0fcc501b60..da386d6360 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -660,8 +660,13 @@ impl Interpreter { isa::Instruction::I32WrapI64 => Some(RunInstructionTracePre::I32WrapI64 { value: <_>::from_value_internal(*self.value_stack.pick(1)), }), - isa::Instruction::I64ExtendUI32 => Some(RunInstructionTracePre::I64ExtendUI32 { + isa::Instruction::I64ExtendUI32 => Some(RunInstructionTracePre::I64ExtendI32 { value: <_>::from_value_internal(*self.value_stack.pick(1)), + sign: false, + }), + isa::Instruction::I64ExtendSI32 => Some(RunInstructionTracePre::I64ExtendI32 { + value: <_>::from_value_internal(*self.value_stack.pick(1)), + sign: true, }), _ => { @@ -1319,11 +1324,12 @@ impl Interpreter { unreachable!() } } - isa::Instruction::I64ExtendUI32 => { - if let RunInstructionTracePre::I64ExtendUI32 { value } = pre_status.unwrap() { - StepInfo::I64ExtendUI32 { + isa::Instruction::I64ExtendSI32 | isa::Instruction::I64ExtendUI32 => { + if let RunInstructionTracePre::I64ExtendI32 { value, sign } = pre_status.unwrap() { + StepInfo::I64ExtendI32 { value, result: <_>::from_value_internal(*self.value_stack.top()), + sign, } } else { unreachable!() diff --git a/src/tracer/etable.rs b/src/tracer/etable.rs index 3afcf660f4..9273fcf802 100644 --- a/src/tracer/etable.rs +++ b/src/tracer/etable.rs @@ -74,8 +74,9 @@ pub enum RunInstructionTracePre { I32WrapI64 { value: i64, }, - I64ExtendUI32 { + I64ExtendI32 { value: i32, + sign: bool, }, Drop, From 33f48da6f87b94a04827664d23f9d2f06418645a Mon Sep 17 00:00:00 2001 From: Heng Zhang Date: Mon, 10 Oct 2022 14:01:02 +0800 Subject: [PATCH 068/129] fix value cast according to its vtype --- src/runner.rs | 53 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 21 deletions(-) diff --git a/src/runner.rs b/src/runner.rs index da386d6360..7e4b1c369f 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -69,15 +69,6 @@ impl ValueInternal { } } -impl ValueInternal { - pub fn value_with_type(self, ty: specs::types::ValueType) -> Value { - match ty { - specs::types::ValueType::I32 => Value::I32(<_>::from_value_internal(self)), - specs::types::ValueType::I64 => Value::I64(<_>::from_value_internal(self)), - } - } -} - trait FromValueInternal where Self: Sized, @@ -128,6 +119,13 @@ macro_rules! impl_from_value_internal_float { impl_from_value_internal!(i8, u8, i16, u16, i32, u32, i64, u64); impl_from_value_internal_float!(f32, f64, F32, F64); +pub fn from_value_internal_to_u64_with_typ(vtype: VarType, val: ValueInternal) -> u64 { + match vtype { + VarType::I32 => val.0 as u32 as u64, + VarType::I64 => val.0 as u64, + } +} + impl From for ValueInternal { fn from(other: bool) -> Self { (if other { 1 } else { 0 }).into() @@ -404,7 +402,8 @@ impl Interpreter { host_function_idx: *host_function_idx, function_name: function_name.clone(), args: args.clone(), - ret_val: Some(<_>::from_value_internal( + ret_val: Some(from_value_internal_to_u64_with_typ( + signature.return_type.unwrap().into(), return_val.into(), )), signature: signature.clone(), @@ -467,10 +466,10 @@ impl Interpreter { } isa::Instruction::Drop => Some(RunInstructionTracePre::Drop), - isa::Instruction::Select(_) => Some(RunInstructionTracePre::Select { - cond: <_>::from_value_internal(*self.value_stack.pick(1)), - val2: <_>::from_value_internal(*self.value_stack.pick(2)), - val1: <_>::from_value_internal(*self.value_stack.pick(3)), + isa::Instruction::Select(vtype) => Some(RunInstructionTracePre::Select { + cond: from_value_internal_to_u64_with_typ(VarType::I32, *self.value_stack.pick(1)), + val2: from_value_internal_to_u64_with_typ(vtype.into(), *self.value_stack.pick(2)), + val1: from_value_internal_to_u64_with_typ(vtype.into(), *self.value_stack.pick(3)), }), isa::Instruction::I32Load(offset) @@ -685,7 +684,7 @@ impl Interpreter { match *instructions { isa::Instruction::GetLocal(depth, vtype) => StepInfo::GetLocal { depth, - value: <_>::from_value_internal(*self.value_stack.top()), + value: from_value_internal_to_u64_with_typ(vtype.into(), *self.value_stack.top()), vtype: vtype.into(), }, isa::Instruction::SetLocal(..) => { @@ -697,7 +696,7 @@ impl Interpreter { { StepInfo::SetLocal { depth, - value: <_>::from_value_internal(value), + value: from_value_internal_to_u64_with_typ(vtype.into(), value), vtype: vtype.into(), } } else { @@ -706,7 +705,7 @@ impl Interpreter { } isa::Instruction::TeeLocal(depth, vtype) => StepInfo::TeeLocal { depth, - value: <_>::from_value_internal(*self.value_stack.top()), + value: from_value_internal_to_u64_with_typ(vtype.into(), *self.value_stack.top()), vtype: vtype.into(), }, @@ -799,7 +798,10 @@ impl Interpreter { val1, val2, cond, - result: <_>::from_value_internal(*self.value_stack.top()), + result: from_value_internal_to_u64_with_typ( + vtype.into(), + *self.value_stack.top(), + ), vtype: vtype.into(), } } else { @@ -825,8 +827,14 @@ impl Interpreter { } => { let params_len = desc.signature.params().len(); let mut args: Vec = vec![]; + let signature: specs::host_function::Signature = + desc.signature.clone().into(); + let params = signature.params.clone(); for i in 0..params_len { - args.push(<_>::from_value_internal(*self.value_stack.pick(1 + i))); + args.push(from_value_internal_to_u64_with_typ( + (params[i]).into(), + *self.value_stack.pick(1 + i), + )); } StepInfo::CallHost { @@ -835,7 +843,7 @@ impl Interpreter { function_name: function_name.clone(), args, ret_val: None, - signature: desc.signature.clone().into(), + signature, } } } @@ -875,7 +883,10 @@ impl Interpreter { offset, raw_address, effective_address: effective_address.unwrap(), - value: <_>::from_value_internal(*self.value_stack.top()), + value: from_value_internal_to_u64_with_typ( + vtype.into(), + *self.value_stack.top(), + ), block_value, mmid, } From 9cea473cf552e4bee066699f04be3f4b11d835e3 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Mon, 10 Oct 2022 20:21:31 +0800 Subject: [PATCH 069/129] explicitly push local var --- src/prepare/compile.rs | 13 ++++++++++++- src/prepare/tests.rs | 6 ++++-- src/runner.rs | 11 ++++++++--- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/prepare/compile.rs b/src/prepare/compile.rs index b91edcd6f7..0cac67a956 100644 --- a/src/prepare/compile.rs +++ b/src/prepare/compile.rs @@ -2,7 +2,7 @@ use alloc::{string::String, vec::Vec}; use parity_wasm::elements::{BlockType, FuncBody, Instruction, ValueType}; -use crate::isa::{self}; +use crate::isa::{self, InstructionInternal}; use validation::{ func::{ require_label, @@ -89,6 +89,17 @@ impl FuncValidator for Compiler { .label_stack .push(BlockFrameType::Block { end_label }); + for local_group in body.locals() { + for _ in 0..local_group.count() { + match local_group.value_type() { + ValueType::I32 => compiler.sink.emit(InstructionInternal::I32Const(0)), + ValueType::I64 => compiler.sink.emit(InstructionInternal::I64Const(0)), + ValueType::F32 => compiler.sink.emit(InstructionInternal::F32Const(0)), + ValueType::F64 => compiler.sink.emit(InstructionInternal::F64Const(0)), + } + } + } + compiler } fn next_instruction( diff --git a/src/prepare/tests.rs b/src/prepare/tests.rs index 36afa25ec3..5ba1c3d5ea 100644 --- a/src/prepare/tests.rs +++ b/src/prepare/tests.rs @@ -241,6 +241,7 @@ fn drop_locals() { assert_eq!( code, vec![ + isa::Instruction::I32Const(0), isa::Instruction::GetLocal(2, ValueType::I32), isa::Instruction::SetLocal(1, ValueType::I32), isa::Instruction::Return(isa::DropKeep { @@ -316,9 +317,10 @@ fn if_else() { assert_eq!( code, vec![ + isa::Instruction::I32Const(0), isa::Instruction::I32Const(1), isa::Instruction::BrIfEqz(isa::Target { - dst_pc: pcs[5], + dst_pc: pcs[6], drop_keep: isa::DropKeep { drop: 0, keep: isa::Keep::None, @@ -327,7 +329,7 @@ fn if_else() { isa::Instruction::I32Const(2), isa::Instruction::SetLocal(1, ValueType::I32), isa::Instruction::Br(isa::Target { - dst_pc: pcs[7], + dst_pc: pcs[8], drop_keep: isa::DropKeep { drop: 0, keep: isa::Keep::None, diff --git a/src/runner.rs b/src/runner.rs index 7e4b1c369f..1d1b0fffb2 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -2361,9 +2361,14 @@ impl FunctionContext { ) -> Result<(), TrapCode> { debug_assert!(!self.is_initialized); - let num_locals = locals.iter().map(|l| l.count() as usize).sum(); - - value_stack.extend(num_locals)?; + { + /* + * Since we have explicitly pushed local variables via T.const instruction, + * we bypass extendind value_stack here. + */ + // let num_locals = locals.iter().map(|l| l.count() as usize).sum(); + // value_stack.extend(num_locals)?; + } self.is_initialized = true; Ok(()) From d8e0f5c11782855472d4b6492135863d8bb738a8 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Mon, 10 Oct 2022 20:34:04 +0800 Subject: [PATCH 070/129] add op_index_in_plugin for callhost --- src/isa.rs | 2 ++ src/runner.rs | 4 ++++ src/tracer/mod.rs | 1 + 3 files changed, 7 insertions(+) diff --git a/src/isa.rs b/src/isa.rs index 3d17b7797c..146ec0e497 100644 --- a/src/isa.rs +++ b/src/isa.rs @@ -416,10 +416,12 @@ impl<'a> Instruction<'a> { plugin, function_index, function_name, + op_index_in_plugin, } => Opcode::CallHost { plugin: *plugin, function_index: *function_index, function_name: function_name.clone(), + op_index_in_plugin: *op_index_in_plugin, }, } } diff --git a/src/runner.rs b/src/runner.rs index 1d1b0fffb2..b74e96b919 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -395,6 +395,7 @@ impl Interpreter { args, ret_val, signature, + op_index_in_plugin, } => { assert!(ret_val.is_none()); entry.step = StepInfo::CallHost { @@ -407,6 +408,7 @@ impl Interpreter { return_val.into(), )), signature: signature.clone(), + op_index_in_plugin: *op_index_in_plugin, } } _ => unreachable!(), @@ -824,6 +826,7 @@ impl Interpreter { plugin, function_index: host_function_idx, function_name, + op_index_in_plugin, } => { let params_len = desc.signature.params().len(); let mut args: Vec = vec![]; @@ -844,6 +847,7 @@ impl Interpreter { args, ret_val: None, signature, + op_index_in_plugin: *op_index_in_plugin, } } } diff --git a/src/tracer/mod.rs b/src/tracer/mod.rs index b1669bac0f..4c72b97390 100644 --- a/src/tracer/mod.rs +++ b/src/tracer/mod.rs @@ -167,6 +167,7 @@ impl Tracer { plugin: plugin_desc.plugin, function_index: host_func_index, function_name: plugin_desc.name, + op_index_in_plugin: plugin_desc.op_index_in_plugin, } } }; From 23b328b4b3c3972a6d4852ba194977e34840b77e Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Thu, 13 Oct 2022 13:16:26 +0800 Subject: [PATCH 071/129] feat: support I64GeU --- src/isa.rs | 5 ++++- src/runner.rs | 12 ++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/isa.rs b/src/isa.rs index 146ec0e497..f5c1ae845e 100644 --- a/src/isa.rs +++ b/src/isa.rs @@ -551,7 +551,10 @@ impl<'a> Instruction<'a> { vtype: VarType::I64, }, Instruction::I64GeS => todo!(), - Instruction::I64GeU => todo!(), + Instruction::I64GeU => Opcode::Rel { + class: RelOp::UnsignedGe, + vtype: VarType::I64, + }, Instruction::F32Eq => todo!(), Instruction::F32Ne => todo!(), Instruction::F32Lt => todo!(), diff --git a/src/runner.rs b/src/runner.rs index b74e96b919..e83141a962 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -1074,6 +1074,18 @@ impl Interpreter { unreachable!() } } + isa::Instruction::I64GeU => { + if let RunInstructionTracePre::I64Comp { left, right } = pre_status.unwrap() { + StepInfo::I64Comp { + class: RelOp::UnsignedGe, + left, + right, + value: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } isa::Instruction::I32Add => { if let RunInstructionTracePre::I32BinOp { left, right } = pre_status.unwrap() { From 64e83c897f4da273586f71e36c811b7b170c4b8c Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Thu, 13 Oct 2022 18:54:43 +0800 Subject: [PATCH 072/129] feat: add a batch of rel insts --- src/isa.rs | 25 ++++++++++++++++----- src/runner.rs | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 5 deletions(-) diff --git a/src/isa.rs b/src/isa.rs index f5c1ae845e..e2f1ff481f 100644 --- a/src/isa.rs +++ b/src/isa.rs @@ -536,21 +536,36 @@ impl<'a> Instruction<'a> { vtype: VarType::I32, }, Instruction::I64Eqz => todo!(), - Instruction::I64Eq => todo!(), - Instruction::I64Ne => todo!(), + Instruction::I64Eq => Opcode::Rel { + class: RelOp::Eq, + vtype: VarType::I64, + }, + Instruction::I64Ne => Opcode::Rel { + class: RelOp::Ne, + vtype: VarType::I64, + }, Instruction::I64LtS => todo!(), Instruction::I64LtU => Opcode::Rel { class: RelOp::UnsignedLt, vtype: VarType::I64, }, - Instruction::I64GtS => todo!(), - Instruction::I64GtU => todo!(), + Instruction::I64GtS => Opcode::Rel { + class: RelOp::SignedGt, + vtype: VarType::I64, + }, + Instruction::I64GtU => Opcode::Rel { + class: RelOp::UnsignedGt, + vtype: VarType::I64, + }, Instruction::I64LeS => todo!(), Instruction::I64LeU => Opcode::Rel { class: RelOp::UnsignedLe, vtype: VarType::I64, }, - Instruction::I64GeS => todo!(), + Instruction::I64GeS => Opcode::Rel { + class: RelOp::SignedGe, + vtype: VarType::I64, + }, Instruction::I64GeU => Opcode::Rel { class: RelOp::UnsignedGe, vtype: VarType::I64, diff --git a/src/runner.rs b/src/runner.rs index e83141a962..41f63dba0c 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -1050,6 +1050,54 @@ impl Interpreter { } } + isa::Instruction::I64Eq => { + if let RunInstructionTracePre::I64Comp { left, right } = pre_status.unwrap() { + StepInfo::I64Comp { + class: RelOp::Eq, + left, + right, + value: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } + isa::Instruction::I64Ne => { + if let RunInstructionTracePre::I64Comp { left, right } = pre_status.unwrap() { + StepInfo::I64Comp { + class: RelOp::Ne, + left, + right, + value: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } + isa::Instruction::I64GtS => { + if let RunInstructionTracePre::I64Comp { left, right } = pre_status.unwrap() { + StepInfo::I64Comp { + class: RelOp::SignedGt, + left, + right, + value: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } + isa::Instruction::I64GtU => { + if let RunInstructionTracePre::I64Comp { left, right } = pre_status.unwrap() { + StepInfo::I64Comp { + class: RelOp::UnsignedGt, + left, + right, + value: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } isa::Instruction::I64LtU => { if let RunInstructionTracePre::I64Comp { left, right } = pre_status.unwrap() { StepInfo::I64Comp { @@ -1086,6 +1134,18 @@ impl Interpreter { unreachable!() } } + isa::Instruction::I64GeS => { + if let RunInstructionTracePre::I64Comp { left, right } = pre_status.unwrap() { + StepInfo::I64Comp { + class: RelOp::SignedGe, + left, + right, + value: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } isa::Instruction::I32Add => { if let RunInstructionTracePre::I32BinOp { left, right } = pre_status.unwrap() { From a47f71bfdde6d2c9f255d7704cf5a1f48f32f824 Mon Sep 17 00:00:00 2001 From: Heng Zhang Date: Tue, 18 Oct 2022 16:16:44 +0800 Subject: [PATCH 073/129] add support for global --- src/tracer/imtable.rs | 21 +++++++++++++++++++-- src/tracer/mod.rs | 9 +++++++-- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/tracer/imtable.rs b/src/tracer/imtable.rs index c41ef399ff..cdea2e09e2 100644 --- a/src/tracer/imtable.rs +++ b/src/tracer/imtable.rs @@ -1,7 +1,9 @@ -use specs::imtable::InitMemoryTableEntry; +use specs::{imtable::InitMemoryTableEntry, mtable::LocationType}; #[derive(Debug, Clone)] pub struct IMEntry { + pub is_global: bool, + pub is_mutable: bool, pub module_instance_index: u16, pub offset: u32, pub value: u64, @@ -10,6 +12,12 @@ pub struct IMEntry { impl Into for IMEntry { fn into(self) -> InitMemoryTableEntry { InitMemoryTableEntry { + is_mutable: self.is_mutable, + ltype: if self.is_global { + LocationType::Global + } else { + LocationType::Heap + }, mmid: self.module_instance_index as u64, offset: self.offset as u64, value: self.value, @@ -21,8 +29,17 @@ impl Into for IMEntry { pub struct IMTable(pub Vec); impl IMTable { - pub(crate) fn push(&mut self, module_instance_index: u16, offset: u32, value: u64) { + pub(crate) fn push( + &mut self, + is_global: bool, + is_mutable: bool, + module_instance_index: u16, + offset: u32, + value: u64, + ) { self.0.push(IMEntry { + is_mutable, + is_global, module_instance_index, offset, value, diff --git a/src/tracer/mod.rs b/src/tracer/mod.rs index 4c72b97390..bbf2d9b739 100644 --- a/src/tracer/mod.rs +++ b/src/tracer/mod.rs @@ -101,8 +101,13 @@ impl Tracer { for i in 0..(pages * 8192) { let mut buf = [0u8; 8]; (*memref).get_into(i * 8, &mut buf).unwrap(); - self.imtable - .push(self.next_memory_id(), i, u64::from_le_bytes(buf)); + self.imtable.push( + false, + true, + self.next_memory_id(), + i, + u64::from_le_bytes(buf), + ); } self.memory_instance_lookup From 64693c7585b6bf78e2d0d8b76ef49a7dcbfac6c9 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Wed, 19 Oct 2022 17:01:36 +0800 Subject: [PATCH 074/129] feat: Load more info for global var --- src/isa.rs | 4 +-- src/module.rs | 16 ++++++++--- src/runner.rs | 66 +++++++++++++++++++++++++++++++++++++++++++ src/tracer/etable.rs | 6 +++- src/tracer/imtable.rs | 9 +++++- src/tracer/mod.rs | 48 +++++++++++++++++++++++++++++-- 6 files changed, 138 insertions(+), 11 deletions(-) diff --git a/src/isa.rs b/src/isa.rs index e2f1ff481f..8c83e53e0d 100644 --- a/src/isa.rs +++ b/src/isa.rs @@ -428,8 +428,8 @@ impl<'a> Instruction<'a> { Instruction::CallIndirect(_) => todo!(), Instruction::Drop => Opcode::Drop, Instruction::Select(_) => Opcode::Select, - Instruction::GetGlobal(_) => todo!(), - Instruction::SetGlobal(_) => todo!(), + Instruction::GetGlobal(idx) => Opcode::GlobalGet { idx: idx as u64 }, + Instruction::SetGlobal(idx) => Opcode::GlobalSet { idx: idx as u64 }, Instruction::I32Load(offset) => Opcode::Load { offset, vtype: VarType::I32, diff --git a/src/module.rs b/src/module.rs index 5e90b7820d..bc0b14bca9 100644 --- a/src/module.rs +++ b/src/module.rs @@ -479,10 +479,18 @@ impl ModuleInstance { match &tracer { Some(tracer) => { - if let Some(memory_ref) = module_ref.memory_by_index(DEFAULT_MEMORY_INDEX) { - let t = tracer.clone(); - let mut t = (*t).borrow_mut(); - t.push_init_memory(memory_ref) + let current_module_id = { tracer.borrow().next_module_id() }; + + { + let mut tracer = tracer.borrow_mut(); + + for (globalidx, globalref) in module_ref.globals().iter().enumerate() { + tracer.push_global(current_module_id, globalidx as u32, globalref); + } + + if let Some(memory_ref) = module_ref.memory_by_index(DEFAULT_MEMORY_INDEX) { + tracer.push_init_memory(memory_ref) + } } } None => (), diff --git a/src/runner.rs b/src/runner.rs index 41f63dba0c..6943694d08 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -441,6 +441,14 @@ impl Interpreter { }) } isa::Instruction::TeeLocal(..) => None, + isa::Instruction::GetGlobal(..) => None, + isa::Instruction::SetGlobal(idx) => { + let value = self.value_stack.top(); + Some(RunInstructionTracePre::SetGlobal { + idx, + value: value.clone(), + }) + } isa::Instruction::Br(_) => None, isa::Instruction::BrIfEqz(_) => Some(RunInstructionTracePre::BrIfEqz { @@ -710,6 +718,64 @@ impl Interpreter { value: from_value_internal_to_u64_with_typ(vtype.into(), *self.value_stack.top()), vtype: vtype.into(), }, + isa::Instruction::GetGlobal(idx) => { + let tracer = self.tracer.as_ref().unwrap().borrow(); + + let global_ref = context.module().global_by_index(idx).unwrap(); + let is_mutable = global_ref.is_mutable(); + let vtype: VarType = global_ref.value_type().into_elements().into(); + let value = from_value_internal_to_u64_with_typ( + vtype.into(), + ValueInternal::from(global_ref.get()), + ); + + let (origin_module, origin_idx) = + tracer.lookup_global_instance(&global_ref).unwrap(); + let moid = tracer.lookup_module_instance(&context.module); + /* + * TODO: imported global is not support yet. + */ + assert_eq!(origin_module, moid); + assert_eq!(origin_idx, idx as u16); + + StepInfo::GetGlobal { + idx, + origin_module: moid, + origin_idx: idx as u16, + vtype, + is_mutable, + value, + } + } + isa::Instruction::SetGlobal(idx) => { + let tracer = self.tracer.as_ref().unwrap().borrow(); + + let global_ref = context.module().global_by_index(idx).unwrap(); + let is_mutable = global_ref.is_mutable(); + let vtype: VarType = global_ref.value_type().into_elements().into(); + let value = from_value_internal_to_u64_with_typ( + vtype.into(), + ValueInternal::from(global_ref.get()), + ); + + let (origin_module, origin_idx) = + tracer.lookup_global_instance(&global_ref).unwrap(); + let moid = tracer.lookup_module_instance(&context.module); + /* + * TODO: imported global is not support yet. + */ + assert_eq!(origin_module, moid); + assert_eq!(origin_idx, idx as u16); + + StepInfo::SetGlobal { + idx, + origin_module: moid, + origin_idx: idx as u16, + vtype, + is_mutable, + value, + } + } isa::Instruction::Br(target) => StepInfo::Br { dst_pc: target.dst_pc, diff --git a/src/tracer/etable.rs b/src/tracer/etable.rs index 9273fcf802..93bf2461bc 100644 --- a/src/tracer/etable.rs +++ b/src/tracer/etable.rs @@ -27,6 +27,10 @@ pub enum RunInstructionTracePre { value: ValueInternal, vtype: ValueType, }, + SetGlobal { + idx: u32, + value: ValueInternal, + }, Load { offset: u32, @@ -84,7 +88,7 @@ pub enum RunInstructionTracePre { val1: u64, val2: u64, cond: u64, - } + }, } #[derive(Debug, Clone)] diff --git a/src/tracer/imtable.rs b/src/tracer/imtable.rs index cdea2e09e2..87e6b5d5ef 100644 --- a/src/tracer/imtable.rs +++ b/src/tracer/imtable.rs @@ -1,4 +1,7 @@ -use specs::{imtable::InitMemoryTableEntry, mtable::LocationType}; +use specs::{ + imtable::InitMemoryTableEntry, + mtable::{LocationType, VarType}, +}; #[derive(Debug, Clone)] pub struct IMEntry { @@ -6,6 +9,7 @@ pub struct IMEntry { pub is_mutable: bool, pub module_instance_index: u16, pub offset: u32, + pub vtype: VarType, pub value: u64, } @@ -20,6 +24,7 @@ impl Into for IMEntry { }, mmid: self.module_instance_index as u64, offset: self.offset as u64, + vtype: self.vtype, value: self.value, } } @@ -35,6 +40,7 @@ impl IMTable { is_mutable: bool, module_instance_index: u16, offset: u32, + vtype: VarType, value: u64, ) { self.0.push(IMEntry { @@ -42,6 +48,7 @@ impl IMTable { is_global, module_instance_index, offset, + vtype, value, }) } diff --git a/src/tracer/mod.rs b/src/tracer/mod.rs index bbf2d9b739..a082efbdb6 100644 --- a/src/tracer/mod.rs +++ b/src/tracer/mod.rs @@ -1,8 +1,16 @@ use std::collections::HashMap; -use specs::{host_function::HostFunctionDesc, types::FunctionType}; - -use crate::{FuncRef, MemoryRef, Module, ModuleRef, Signature}; +use specs::{host_function::HostFunctionDesc, mtable::VarType, types::FunctionType}; + +use crate::{ + runner::{from_value_internal_to_u64_with_typ, ValueInternal}, + FuncRef, + GlobalRef, + MemoryRef, + Module, + ModuleRef, + Signature, +}; use self::{ etable::ETable, @@ -31,6 +39,7 @@ pub struct Tracer { pub jtable: JTable, module_instance_lookup: Vec<(ModuleRef, u16)>, memory_instance_lookup: Vec<(MemoryRef, u16)>, + global_instance_lookup: Vec<(GlobalRef, (u16, u16))>, function_lookup: Vec<(FuncRef, u16)>, last_jump_eid: Vec, function_index_allocator: u32, @@ -49,6 +58,7 @@ impl Tracer { jtable: JTable::default(), module_instance_lookup: vec![], memory_instance_lookup: vec![], + global_instance_lookup: vec![], function_lookup: vec![], function_index_allocator: 1, function_index_translation: Default::default(), @@ -106,6 +116,7 @@ impl Tracer { true, self.next_memory_id(), i, + VarType::I64, u64::from_le_bytes(buf), ); } @@ -114,6 +125,27 @@ impl Tracer { .push((memref, self.next_memory_id())); } + pub(crate) fn push_global(&mut self, moid: u16, globalidx: u32, globalref: &GlobalRef) { + let vtype = globalref.elements_value_type().into(); + + if let Some((_origin_moid, _origin_idx)) = self.lookup_global_instance(globalref) { + // Import global does not support yet. + todo!() + } else { + self.global_instance_lookup + .push((globalref.clone(), (moid, globalidx as u16))); + + self.imtable.push( + true, + globalref.is_mutable(), + moid, + globalidx, + vtype, + from_value_internal_to_u64_with_typ(vtype, ValueInternal::from(globalref.get())), + ) + } + } + pub(crate) fn statistics_instructions<'a>(&mut self, module_instance: &ModuleRef) { let mut func_index = 0; let mut insts = vec![]; @@ -250,6 +282,16 @@ impl Tracer { unreachable!() } + pub fn lookup_global_instance(&self, global_instance: &GlobalRef) -> Option<(u16, u16)> { + for m in &self.global_instance_lookup { + if &m.0 == global_instance { + return Some(m.1); + } + } + + None + } + pub fn lookup_function(&self, function: &FuncRef) -> u16 { let pos = self .function_lookup From d734baab5a830c06064d505a4a50e65b3cba7ac2 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Wed, 19 Oct 2022 21:07:26 +0800 Subject: [PATCH 075/129] feat: Enable I64Store8 inst --- src/isa.rs | 6 +++++- src/runner.rs | 8 ++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/isa.rs b/src/isa.rs index 8c83e53e0d..01833cf4bf 100644 --- a/src/isa.rs +++ b/src/isa.rs @@ -482,7 +482,11 @@ impl<'a> Instruction<'a> { size: MemoryStoreSize::Byte8, }, Instruction::I32Store16(_) => todo!(), - Instruction::I64Store8(_) => todo!(), + Instruction::I64Store8(offset) => Opcode::Store { + offset, + vtype: VarType::I64, + size: MemoryStoreSize::Byte8, + }, Instruction::I64Store16(_) => todo!(), Instruction::I64Store32(_) => todo!(), Instruction::CurrentMemory => todo!(), diff --git a/src/runner.rs b/src/runner.rs index 6943694d08..34901a5eb7 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -457,6 +457,8 @@ impl Interpreter { isa::Instruction::BrIfNez(_) => Some(RunInstructionTracePre::BrIfNez { value: <_>::from_value_internal(*self.value_stack.top()), }), + + isa::Instruction::Unreachable => None, isa::Instruction::Return(..) => None, isa::Instruction::Call(func_idx) => { @@ -571,9 +573,10 @@ impl Interpreter { pre_block_value, }) } - isa::Instruction::I64Store(offset) => { + isa::Instruction::I64Store(offset) | isa::Instruction::I64Store8(offset) => { let store_size = match *instructions { isa::Instruction::I64Store(..) => MemoryStoreSize::Byte64, + isa::Instruction::I64Store8(..) => MemoryStoreSize::Byte8, _ => unreachable!(), }; @@ -966,7 +969,8 @@ impl Interpreter { } isa::Instruction::I32Store(..) | isa::Instruction::I32Store8(..) - | isa::Instruction::I64Store(..) => { + | isa::Instruction::I64Store(..) + | isa::Instruction::I64Store8(..) => { if let RunInstructionTracePre::Store { offset, raw_address, From 26d2881f975c7a1cac9811c3218a8beed3d2bb77 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Tue, 25 Oct 2022 15:57:48 +0800 Subject: [PATCH 076/129] fix: fix compile warning --- src/runner.rs | 6 +++--- src/tracer/mod.rs | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/runner.rs b/src/runner.rs index 34901a5eb7..ab59d694ba 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -32,7 +32,6 @@ use specs::{ itable::{BinOp, BitOp, RelOp, ShiftOp}, mtable::{MemoryReadSize, MemoryStoreSize, VarType}, step::StepInfo, - types::Value, }; use std::rc::Rc; use validation::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX}; @@ -2502,8 +2501,8 @@ impl FunctionContext { pub fn initialize( &mut self, - locals: &[Local], - value_stack: &mut ValueStack, + _locals: &[Local], + _value_stack: &mut ValueStack, ) -> Result<(), TrapCode> { debug_assert!(!self.is_initialized); @@ -2659,6 +2658,7 @@ impl ValueStack { Ok(()) } + #[allow(dead_code)] fn extend(&mut self, len: usize) -> Result<(), TrapCode> { let cells = self .buf diff --git a/src/tracer/mod.rs b/src/tracer/mod.rs index a082efbdb6..f6ee1c1a59 100644 --- a/src/tracer/mod.rs +++ b/src/tracer/mod.rs @@ -146,6 +146,7 @@ impl Tracer { } } + #[allow(dead_code)] pub(crate) fn statistics_instructions<'a>(&mut self, module_instance: &ModuleRef) { let mut func_index = 0; let mut insts = vec![]; From ef0d0a67ac8105b66d9bae59a0f3bae5f7b2070f Mon Sep 17 00:00:00 2001 From: Heng Zhang Date: Thu, 3 Nov 2022 00:50:23 +0800 Subject: [PATCH 077/129] feat: impl more bin ops --- src/isa.rs | 45 +++++++++++++++---- src/runner.rs | 117 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 153 insertions(+), 9 deletions(-) diff --git a/src/isa.rs b/src/isa.rs index 01833cf4bf..e02d113da1 100644 --- a/src/isa.rs +++ b/src/isa.rs @@ -601,10 +601,22 @@ impl<'a> Instruction<'a> { class: BinOp::Mul, vtype: VarType::I32, }, - Instruction::I32DivS => todo!(), - Instruction::I32DivU => todo!(), - Instruction::I32RemS => todo!(), - Instruction::I32RemU => todo!(), + Instruction::I32DivS => Opcode::Bin { + class: BinOp::SignedDiv, + vtype: VarType::I32, + }, + Instruction::I32DivU => Opcode::Bin { + class: BinOp::UnsignedDiv, + vtype: VarType::I32, + }, + Instruction::I32RemS => Opcode::Bin { + class: BinOp::SignedRem, + vtype: VarType::I32, + }, + Instruction::I32RemU => Opcode::Bin { + class: BinOp::UnsignedRem, + vtype: VarType::I32, + }, Instruction::I32And => Opcode::BinBit { class: BitOp::And, vtype: VarType::I32, @@ -648,11 +660,26 @@ impl<'a> Instruction<'a> { class: BinOp::Sub, vtype: VarType::I64, }, - Instruction::I64Mul => todo!(), - Instruction::I64DivS => todo!(), - Instruction::I64DivU => todo!(), - Instruction::I64RemS => todo!(), - Instruction::I64RemU => todo!(), + Instruction::I64Mul => Opcode::Bin { + class: BinOp::Mul, + vtype: VarType::I64, + }, + Instruction::I64DivS => Opcode::Bin { + class: BinOp::SignedDiv, + vtype: VarType::I64, + }, + Instruction::I64DivU => Opcode::Bin { + class: BinOp::UnsignedDiv, + vtype: VarType::I64, + }, + Instruction::I64RemS => Opcode::Bin { + class: BinOp::SignedRem, + vtype: VarType::I64, + }, + Instruction::I64RemU => Opcode::Bin { + class: BinOp::UnsignedRem, + vtype: VarType::I64, + }, Instruction::I64And => Opcode::BinBit { class: BitOp::And, vtype: VarType::I64, diff --git a/src/runner.rs b/src/runner.rs index ab59d694ba..8d98abdb36 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -642,6 +642,10 @@ impl Interpreter { isa::Instruction::I32Add | isa::Instruction::I32Sub | isa::Instruction::I32Mul + | isa::Instruction::I32DivS + | isa::Instruction::I32DivU + | isa::Instruction::I32RemS + | isa::Instruction::I32RemU | isa::Instruction::I32Shl | isa::Instruction::I32ShrU | isa::Instruction::I32ShrS @@ -656,6 +660,11 @@ impl Interpreter { isa::Instruction::I64Add | isa::Instruction::I64Sub + | isa::Instruction::I64Mul + | isa::Instruction::I64DivS + | isa::Instruction::I64DivU + | isa::Instruction::I64RemS + | isa::Instruction::I64RemU | isa::Instruction::I64Shl | isa::Instruction::I64ShrU | isa::Instruction::I64ShrS @@ -1252,6 +1261,54 @@ impl Interpreter { unreachable!() } } + isa::Instruction::I32DivU => { + if let RunInstructionTracePre::I32BinOp { left, right } = pre_status.unwrap() { + StepInfo::I32BinOp { + class: BinOp::UnsignedDiv, + left, + right, + value: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } + isa::Instruction::I32RemU => { + if let RunInstructionTracePre::I32BinOp { left, right } = pre_status.unwrap() { + StepInfo::I32BinOp { + class: BinOp::UnsignedRem, + left, + right, + value: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } + isa::Instruction::I32DivS => { + if let RunInstructionTracePre::I32BinOp { left, right } = pre_status.unwrap() { + StepInfo::I32BinOp { + class: BinOp::SignedDiv, + left, + right, + value: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } + isa::Instruction::I32RemS => { + if let RunInstructionTracePre::I32BinOp { left, right } = pre_status.unwrap() { + StepInfo::I32BinOp { + class: BinOp::SignedRem, + left, + right, + value: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } isa::Instruction::I32And => { if let RunInstructionTracePre::I32BinOp { left, right } = pre_status.unwrap() { StepInfo::I32BinBitOp { @@ -1373,6 +1430,66 @@ impl Interpreter { unreachable!() } } + isa::Instruction::I64Mul => { + if let RunInstructionTracePre::I64BinOp { left, right } = pre_status.unwrap() { + StepInfo::I64BinOp { + class: BinOp::Mul, + left, + right, + value: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } + isa::Instruction::I64DivU => { + if let RunInstructionTracePre::I64BinOp { left, right } = pre_status.unwrap() { + StepInfo::I64BinOp { + class: BinOp::UnsignedDiv, + left, + right, + value: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } + isa::Instruction::I64RemU => { + if let RunInstructionTracePre::I64BinOp { left, right } = pre_status.unwrap() { + StepInfo::I64BinOp { + class: BinOp::UnsignedRem, + left, + right, + value: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } + isa::Instruction::I64DivS => { + if let RunInstructionTracePre::I64BinOp { left, right } = pre_status.unwrap() { + StepInfo::I64BinOp { + class: BinOp::SignedDiv, + left, + right, + value: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } + isa::Instruction::I64RemS => { + if let RunInstructionTracePre::I64BinOp { left, right } = pre_status.unwrap() { + StepInfo::I64BinOp { + class: BinOp::SignedRem, + left, + right, + value: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } isa::Instruction::I64And => { if let RunInstructionTracePre::I64BinOp { left, right } = pre_status.unwrap() { StepInfo::I64BinBitOp { From 1b895425017e7e7d03ad0ebc3df0f5835c980837 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Sat, 26 Nov 2022 15:09:59 +0000 Subject: [PATCH 078/129] fix: fix dump args --- src/runner.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/runner.rs b/src/runner.rs index 8d98abdb36..66c9f6538a 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -910,13 +910,13 @@ impl Interpreter { let signature: specs::host_function::Signature = desc.signature.clone().into(); let params = signature.params.clone(); + for i in 0..params_len { args.push(from_value_internal_to_u64_with_typ( (params[i]).into(), - *self.value_stack.pick(1 + i), + *self.value_stack.pick(params_len - i), )); } - StepInfo::CallHost { plugin: *plugin, host_function_idx: *host_function_idx, From c1c4c0276257381e39d857f479536bb1b6271b29 Mon Sep 17 00:00:00 2001 From: hzx Date: Thu, 1 Dec 2022 15:37:27 +0800 Subject: [PATCH 079/129] fix: fill signed instruction --- src/isa.rs | 20 ++++++++++++++---- src/runner.rs | 56 +++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 70 insertions(+), 6 deletions(-) diff --git a/src/isa.rs b/src/isa.rs index e02d113da1..798851d21c 100644 --- a/src/isa.rs +++ b/src/isa.rs @@ -513,7 +513,10 @@ impl<'a> Instruction<'a> { class: RelOp::Ne, vtype: VarType::I32, }, - Instruction::I32LtS => todo!(), + Instruction::I32LtS => Opcode::Rel { + class: RelOp::SignedLt, + vtype: VarType::I32, + }, Instruction::I32LtU => Opcode::Rel { class: RelOp::UnsignedLt, vtype: VarType::I32, @@ -526,7 +529,10 @@ impl<'a> Instruction<'a> { class: RelOp::UnsignedGt, vtype: VarType::I32, }, - Instruction::I32LeS => todo!(), + Instruction::I32LeS => Opcode::Rel { + class: RelOp::SignedLe, + vtype: VarType::I32, + }, Instruction::I32LeU => Opcode::Rel { class: RelOp::UnsignedLe, vtype: VarType::I32, @@ -548,7 +554,10 @@ impl<'a> Instruction<'a> { class: RelOp::Ne, vtype: VarType::I64, }, - Instruction::I64LtS => todo!(), + Instruction::I64LtS => Opcode::Rel { + class: RelOp::SignedLt, + vtype: VarType::I64, + }, Instruction::I64LtU => Opcode::Rel { class: RelOp::UnsignedLt, vtype: VarType::I64, @@ -561,7 +570,10 @@ impl<'a> Instruction<'a> { class: RelOp::UnsignedGt, vtype: VarType::I64, }, - Instruction::I64LeS => todo!(), + Instruction::I64LeS => Opcode::Rel { + class: RelOp::SignedLe, + vtype: VarType::I64, + }, Instruction::I64LeU => Opcode::Rel { class: RelOp::UnsignedLe, vtype: VarType::I64, diff --git a/src/runner.rs b/src/runner.rs index 66c9f6538a..d7f29fc940 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -622,7 +622,9 @@ impl Interpreter { | isa::Instruction::I32GeS | isa::Instruction::I32GeU | isa::Instruction::I32LtU - | isa::Instruction::I32LeU => Some(RunInstructionTracePre::I32Comp { + | isa::Instruction::I32LeU + | isa::Instruction::I32LtS + | isa::Instruction::I32LeS => Some(RunInstructionTracePre::I32Comp { left: <_>::from_value_internal(*self.value_stack.pick(2)), right: <_>::from_value_internal(*self.value_stack.pick(1)), }), @@ -634,7 +636,9 @@ impl Interpreter { | isa::Instruction::I64GeS | isa::Instruction::I64GeU | isa::Instruction::I64LtU - | isa::Instruction::I64LeU => Some(RunInstructionTracePre::I64Comp { + | isa::Instruction::I64LeU + | isa::Instruction::I64LtS + | isa::Instruction::I64LeS => Some(RunInstructionTracePre::I64Comp { left: <_>::from_value_internal(*self.value_stack.pick(2)), right: <_>::from_value_internal(*self.value_stack.pick(1)), }), @@ -1103,6 +1107,18 @@ impl Interpreter { unreachable!() } } + isa::Instruction::I32LtS => { + if let RunInstructionTracePre::I32Comp { left, right } = pre_status.unwrap() { + StepInfo::I32Comp { + class: RelOp::SignedLt, + left, + right, + value: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } isa::Instruction::I32LtU => { if let RunInstructionTracePre::I32Comp { left, right } = pre_status.unwrap() { StepInfo::I32Comp { @@ -1115,6 +1131,18 @@ impl Interpreter { unreachable!() } } + isa::Instruction::I32LeS => { + if let RunInstructionTracePre::I32Comp { left, right } = pre_status.unwrap() { + StepInfo::I32Comp { + class: RelOp::SignedLe, + left, + right, + value: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } isa::Instruction::I32LeU => { if let RunInstructionTracePre::I32Comp { left, right } = pre_status.unwrap() { StepInfo::I32Comp { @@ -1188,6 +1216,18 @@ impl Interpreter { unreachable!() } } + isa::Instruction::I64LtS => { + if let RunInstructionTracePre::I64Comp { left, right } = pre_status.unwrap() { + StepInfo::I64Comp { + class: RelOp::SignedLt, + left, + right, + value: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } isa::Instruction::I64LeU => { if let RunInstructionTracePre::I64Comp { left, right } = pre_status.unwrap() { StepInfo::I64Comp { @@ -1200,6 +1240,18 @@ impl Interpreter { unreachable!() } } + isa::Instruction::I64LeS => { + if let RunInstructionTracePre::I64Comp { left, right } = pre_status.unwrap() { + StepInfo::I64Comp { + class: RelOp::SignedLe, + left, + right, + value: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } isa::Instruction::I64GeU => { if let RunInstructionTracePre::I64Comp { left, right } = pre_status.unwrap() { StepInfo::I64Comp { From 62ab65cede43548c7c0fcf5a522fea7fb89c603b Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Wed, 7 Dec 2022 08:42:45 +0000 Subject: [PATCH 080/129] feat: support clz/ctz instruction --- src/isa.rs | 43 ++++++++++++++++++++++++++++++++++++------- src/runner.rs | 39 ++++++++++++++++++++++++++++++++++++++- src/tracer/etable.rs | 7 ++++++- 3 files changed, 80 insertions(+), 9 deletions(-) diff --git a/src/isa.rs b/src/isa.rs index 798851d21c..056c0d0db2 100644 --- a/src/isa.rs +++ b/src/isa.rs @@ -72,7 +72,7 @@ use std::collections::HashMap; use alloc::vec::Vec; use parity_wasm::elements::ValueType; use specs::{ - itable::{BinOp, BitOp, ConversionOp, Opcode, RelOp, ShiftOp, TestOp}, + itable::{BinOp, BitOp, ConversionOp, Opcode, RelOp, ShiftOp, TestOp, UnaryOp}, mtable::{MemoryReadSize, MemoryStoreSize, VarType}, }; @@ -350,6 +350,17 @@ pub enum Instruction<'a> { F64ReinterpretI64, } +impl<'a> From> for UnaryOp { + fn from(value: Instruction<'a>) -> Self { + match value { + Instruction::I32Clz | Instruction::I64Clz => UnaryOp::Clz, + Instruction::I32Ctz | Instruction::I64Ctz => UnaryOp::Ctz, + Instruction::I32Popcnt | Instruction::I64Popcnt => UnaryOp::Popcnt, + _ => unreachable!(), + } + } +} + impl<'a> Instruction<'a> { pub(crate) fn into(self, function_mapping: &HashMap) -> Opcode { match self { @@ -598,9 +609,18 @@ impl<'a> Instruction<'a> { Instruction::F64Gt => todo!(), Instruction::F64Le => todo!(), Instruction::F64Ge => todo!(), - Instruction::I32Clz => todo!(), - Instruction::I32Ctz => todo!(), - Instruction::I32Popcnt => todo!(), + Instruction::I32Clz => Opcode::Unary { + class: UnaryOp::Clz, + vtype: VarType::I32, + }, + Instruction::I32Ctz => Opcode::Unary { + class: UnaryOp::Ctz, + vtype: VarType::I32, + }, + Instruction::I32Popcnt => Opcode::Unary { + class: UnaryOp::Popcnt, + vtype: VarType::I32, + }, Instruction::I32Add => Opcode::Bin { class: BinOp::Add, vtype: VarType::I32, @@ -661,9 +681,18 @@ impl<'a> Instruction<'a> { class: ShiftOp::Rotr, vtype: VarType::I32, }, - Instruction::I64Clz => todo!(), - Instruction::I64Ctz => todo!(), - Instruction::I64Popcnt => todo!(), + Instruction::I64Clz => Opcode::Unary { + class: UnaryOp::Clz, + vtype: VarType::I64, + }, + Instruction::I64Ctz => Opcode::Unary { + class: UnaryOp::Ctz, + vtype: VarType::I64, + }, + Instruction::I64Popcnt => Opcode::Unary { + class: UnaryOp::Popcnt, + vtype: VarType::I64, + }, Instruction::I64Add => Opcode::Bin { class: BinOp::Add, vtype: VarType::I64, diff --git a/src/runner.rs b/src/runner.rs index d7f29fc940..1174e7f555 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -29,7 +29,7 @@ use alloc::{boxed::Box, vec::Vec}; use core::{cell::RefCell, fmt, ops, u32, usize}; use parity_wasm::elements::Local; use specs::{ - itable::{BinOp, BitOp, RelOp, ShiftOp}, + itable::{BinOp, BitOp, RelOp, ShiftOp, UnaryOp}, mtable::{MemoryReadSize, MemoryStoreSize, VarType}, step::StepInfo, }; @@ -681,6 +681,25 @@ impl Interpreter { right: <_>::from_value_internal(*self.value_stack.pick(1)), }), + isa::Instruction::I32Ctz | isa::Instruction::I32Clz | isa::Instruction::I32Popcnt => { + Some(RunInstructionTracePre::UnaryOp { + operand: from_value_internal_to_u64_with_typ( + VarType::I32, + *self.value_stack.pick(1), + ), + vtype: VarType::I32, + }) + } + isa::Instruction::I64Ctz | isa::Instruction::I64Clz | isa::Instruction::I64Popcnt => { + Some(RunInstructionTracePre::UnaryOp { + operand: from_value_internal_to_u64_with_typ( + VarType::I64, + *self.value_stack.pick(1), + ), + vtype: VarType::I64, + }) + } + isa::Instruction::I32WrapI64 => Some(RunInstructionTracePre::I32WrapI64 { value: <_>::from_value_internal(*self.value_stack.pick(1)), }), @@ -1639,6 +1658,24 @@ impl Interpreter { } } + isa::Instruction::I32Ctz + | isa::Instruction::I32Clz + | isa::Instruction::I32Popcnt + | isa::Instruction::I64Ctz + | isa::Instruction::I64Clz + | isa::Instruction::I64Popcnt => { + if let RunInstructionTracePre::UnaryOp { operand, vtype } = pre_status.unwrap() { + StepInfo::UnaryOp { + class: UnaryOp::from(instructions.clone()), + vtype, + operand, + result: from_value_internal_to_u64_with_typ(vtype, *self.value_stack.top()), + } + } else { + unreachable!() + } + } + isa::Instruction::I32WrapI64 => { if let RunInstructionTracePre::I32WrapI64 { value } = pre_status.unwrap() { StepInfo::I32WrapI64 { diff --git a/src/tracer/etable.rs b/src/tracer/etable.rs index 93bf2461bc..dcb47c8af3 100644 --- a/src/tracer/etable.rs +++ b/src/tracer/etable.rs @@ -2,7 +2,7 @@ use parity_wasm::elements::ValueType; use specs::{ etable::EventTableEntry, itable::Opcode, - mtable::{MemoryReadSize, MemoryStoreSize}, + mtable::{MemoryReadSize, MemoryStoreSize, VarType}, step::StepInfo, }; @@ -83,6 +83,11 @@ pub enum RunInstructionTracePre { sign: bool, }, + UnaryOp { + operand: u64, + vtype: VarType, + }, + Drop, Select { val1: u64, From 42444f7c4e5c88d74f087b5353ec73d01f5e7229 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Mon, 12 Dec 2022 07:58:56 +0000 Subject: [PATCH 081/129] feat: support br_table instruction --- src/isa.rs | 25 +++++++++++++++++++++++-- src/runner.rs | 23 +++++++++++++++++++++++ src/tracer/etable.rs | 3 +++ 3 files changed, 49 insertions(+), 2 deletions(-) diff --git a/src/isa.rs b/src/isa.rs index 056c0d0db2..dc4e94c9e6 100644 --- a/src/isa.rs +++ b/src/isa.rs @@ -72,7 +72,7 @@ use std::collections::HashMap; use alloc::vec::Vec; use parity_wasm::elements::ValueType; use specs::{ - itable::{BinOp, BitOp, ConversionOp, Opcode, RelOp, ShiftOp, TestOp, UnaryOp}, + itable::{BinOp, BitOp, BrTarget, ConversionOp, Opcode, RelOp, ShiftOp, TestOp, UnaryOp}, mtable::{MemoryReadSize, MemoryStoreSize, VarType}, }; @@ -403,7 +403,28 @@ impl<'a> Instruction<'a> { }, dst_pc, }, - Instruction::BrTable(_) => todo!(), + Instruction::BrTable(targets) => Opcode::BrTable { + targets: targets + .stream + .iter() + .map(|t| { + if let InstructionInternal::BrTableTarget(target) = t { + let keep_type = match target.drop_keep.keep { + Keep::None => vec![], + Keep::Single(t) => vec![t.into()], + }; + + BrTarget { + drop: target.drop_keep.drop, + keep: keep_type, + dst_pc: target.dst_pc, + } + } else { + unreachable!() + } + }) + .collect(), + }, Instruction::Unreachable => Opcode::Unreachable, Instruction::Return(drop_keep) => Opcode::Return { drop: drop_keep.drop, diff --git a/src/runner.rs b/src/runner.rs index 1174e7f555..795f672cd3 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -456,6 +456,9 @@ impl Interpreter { isa::Instruction::BrIfNez(_) => Some(RunInstructionTracePre::BrIfNez { value: <_>::from_value_internal(*self.value_stack.top()), }), + isa::Instruction::BrTable(_) => Some(RunInstructionTracePre::BrTable { + index: <_>::from_value_internal(*self.value_stack.top()), + }), isa::Instruction::Unreachable => None, isa::Instruction::Return(..) => None, @@ -864,6 +867,26 @@ impl Interpreter { unreachable!() } } + isa::Instruction::BrTable(targets) => { + if let RunInstructionTracePre::BrTable { index } = pre_status.unwrap() { + StepInfo::BrTable { + index, + dst_pc: targets.get(index as u32).dst_pc, + drop: targets.get(index as u32).drop_keep.drop, + keep: if let Keep::Single(t) = targets.get(index as u32).drop_keep.keep { + vec![t.into()] + } else { + vec![] + }, + keep_values: match targets.get(index as u32).drop_keep.keep { + Keep::Single(_) => vec![(*self.value_stack.top()).0], + Keep::None => vec![], + }, + } + } else { + unreachable!() + } + } isa::Instruction::Return(DropKeep { drop, keep }) => { let mut drop_values = vec![]; diff --git a/src/tracer/etable.rs b/src/tracer/etable.rs index dcb47c8af3..c426f2e0bf 100644 --- a/src/tracer/etable.rs +++ b/src/tracer/etable.rs @@ -17,6 +17,9 @@ pub enum RunInstructionTracePre { BrIfNez { value: i32, }, + BrTable { + index: i32, + }, Call { args: Vec, From b5eb0e8c74de689155b94b1fa511276877fa4bf5 Mon Sep 17 00:00:00 2001 From: Heng Zhang Date: Fri, 16 Dec 2022 12:08:27 +0800 Subject: [PATCH 082/129] impl all load case --- src/isa.rs | 42 +++++++++++++++++++++++++++++++++++------- src/runner.rs | 27 +++++++++++++++++++++++---- 2 files changed, 58 insertions(+), 11 deletions(-) diff --git a/src/isa.rs b/src/isa.rs index dc4e94c9e6..7ab1c5f88d 100644 --- a/src/isa.rs +++ b/src/isa.rs @@ -484,18 +484,46 @@ impl<'a> Instruction<'a> { vtype: VarType::I32, size: MemoryReadSize::U8, }, - Instruction::I32Load16S(_) => todo!(), - Instruction::I32Load16U(_) => todo!(), - Instruction::I64Load8S(_) => todo!(), + Instruction::I32Load16S(offset) => Opcode::Load { + offset, + vtype: VarType::I32, + size: MemoryReadSize::S16, + }, + Instruction::I32Load16U(offset) => Opcode::Load { + offset, + vtype: VarType::I32, + size: MemoryReadSize::U16, + }, + Instruction::I64Load8S(offset) => Opcode::Load { + offset, + vtype: VarType::I64, + size: MemoryReadSize::S8, + }, Instruction::I64Load8U(offset) => Opcode::Load { offset, vtype: VarType::I64, size: MemoryReadSize::U8, }, - Instruction::I64Load16S(_) => todo!(), - Instruction::I64Load16U(_) => todo!(), - Instruction::I64Load32S(_) => todo!(), - Instruction::I64Load32U(_) => todo!(), + Instruction::I64Load16S(offset) => Opcode::Load { + offset, + vtype: VarType::I64, + size: MemoryReadSize::S16, + }, + Instruction::I64Load16U(offset) => Opcode::Load { + offset, + vtype: VarType::I64, + size: MemoryReadSize::U16, + }, + Instruction::I64Load32S(offset) => Opcode::Load { + offset, + vtype: VarType::I64, + size: MemoryReadSize::S32, + }, + Instruction::I64Load32U(offset) => Opcode::Load { + offset, + vtype: VarType::I64, + size: MemoryReadSize::U32, + }, Instruction::I32Store(offset) => Opcode::Store { offset, vtype: VarType::I32, diff --git a/src/runner.rs b/src/runner.rs index 795f672cd3..b2a985bafa 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -487,8 +487,10 @@ impl Interpreter { }), isa::Instruction::I32Load(offset) + | isa::Instruction::I32Load8S(offset) | isa::Instruction::I32Load8U(offset) - | isa::Instruction::I32Load8S(offset) => { + | isa::Instruction::I32Load16S(offset) + | isa::Instruction::I32Load16U(offset) => { let load_size = match *instructions { isa::Instruction::I32Load(..) => MemoryReadSize::U32, isa::Instruction::I32Load8U(..) => MemoryReadSize::U8, @@ -515,10 +517,21 @@ impl Interpreter { mmid: mmid as u64, }) } - isa::Instruction::I64Load(offset) | isa::Instruction::I64Load8U(offset) => { + isa::Instruction::I64Load(offset) + | isa::Instruction::I64Load8S(offset) + | isa::Instruction::I64Load8U(offset) + | isa::Instruction::I64Load16S(offset) + | isa::Instruction::I64Load16U(offset) + | isa::Instruction::I64Load32S(offset) + | isa::Instruction::I64Load32U(offset) => { let load_size = match *instructions { isa::Instruction::I64Load(..) => MemoryReadSize::I64, + isa::Instruction::I64Load8S(..) => MemoryReadSize::S8, isa::Instruction::I64Load8U(..) => MemoryReadSize::U8, + isa::Instruction::I64Load16S(..) => MemoryReadSize::S16, + isa::Instruction::I64Load16U(..) => MemoryReadSize::U16, + isa::Instruction::I64Load32S(..) => MemoryReadSize::S32, + isa::Instruction::I64Load32U(..) => MemoryReadSize::U32, _ => unreachable!(), }; let raw_address = <_>::from_value_internal(*self.value_stack.top()); @@ -982,8 +995,15 @@ impl Interpreter { isa::Instruction::I32Load(..) | isa::Instruction::I32Load8U(..) | isa::Instruction::I32Load8S(..) + | isa::Instruction::I32Load16U(..) + | isa::Instruction::I32Load16S(..) | isa::Instruction::I64Load(..) - | isa::Instruction::I64Load8U(..) => { + | isa::Instruction::I64Load8U(..) + | isa::Instruction::I64Load8S(..) + | isa::Instruction::I64Load16U(..) + | isa::Instruction::I64Load16S(..) + | isa::Instruction::I64Load32U(..) + | isa::Instruction::I64Load32S(..) => { if let RunInstructionTracePre::Load { offset, raw_address, @@ -1499,7 +1519,6 @@ impl Interpreter { unreachable!() } } - isa::Instruction::I64Add => { if let RunInstructionTracePre::I64BinOp { left, right } = pre_status.unwrap() { StepInfo::I64BinOp { From 273ad49f513f2cdfe1d479bb999e16d418778199 Mon Sep 17 00:00:00 2001 From: Heng Zhang Date: Fri, 16 Dec 2022 12:19:13 +0800 Subject: [PATCH 083/129] impl all store case --- src/isa.rs | 18 +++++++++++++++--- src/runner.rs | 17 ++++++++++++++--- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/src/isa.rs b/src/isa.rs index 7ab1c5f88d..27d2046645 100644 --- a/src/isa.rs +++ b/src/isa.rs @@ -541,14 +541,26 @@ impl<'a> Instruction<'a> { vtype: VarType::I32, size: MemoryStoreSize::Byte8, }, - Instruction::I32Store16(_) => todo!(), + Instruction::I32Store16(offset) => Opcode::Store { + offset, + vtype: VarType::I32, + size: MemoryStoreSize::Byte16, + }, Instruction::I64Store8(offset) => Opcode::Store { offset, vtype: VarType::I64, size: MemoryStoreSize::Byte8, }, - Instruction::I64Store16(_) => todo!(), - Instruction::I64Store32(_) => todo!(), + Instruction::I64Store16(offset) => Opcode::Store { + offset, + vtype: VarType::I64, + size: MemoryStoreSize::Byte16, + }, + Instruction::I64Store32(offset) => Opcode::Store { + offset, + vtype: VarType::I64, + size: MemoryStoreSize::Byte32, + }, Instruction::CurrentMemory => todo!(), Instruction::GrowMemory => todo!(), Instruction::I32Const(v) => Opcode::Const { diff --git a/src/runner.rs b/src/runner.rs index b2a985bafa..323564e8a8 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -553,9 +553,12 @@ impl Interpreter { mmid: mmid as u64, }) } - isa::Instruction::I32Store(offset) | isa::Instruction::I32Store8(offset) => { + isa::Instruction::I32Store(offset) + | isa::Instruction::I32Store8(offset) + | isa::Instruction::I32Store16(offset) => { let store_size = match *instructions { isa::Instruction::I32Store8(_) => MemoryStoreSize::Byte8, + isa::Instruction::I32Store16(_) => MemoryStoreSize::Byte16, isa::Instruction::I32Store(_) => MemoryStoreSize::Byte32, _ => unreachable!(), }; @@ -588,10 +591,15 @@ impl Interpreter { pre_block_value, }) } - isa::Instruction::I64Store(offset) | isa::Instruction::I64Store8(offset) => { + isa::Instruction::I64Store(offset) + | isa::Instruction::I64Store8(offset) + | isa::Instruction::I64Store16(offset) + | isa::Instruction::I64Store32(offset) => { let store_size = match *instructions { isa::Instruction::I64Store(..) => MemoryStoreSize::Byte64, isa::Instruction::I64Store8(..) => MemoryStoreSize::Byte8, + isa::Instruction::I64Store16(..) => MemoryStoreSize::Byte16, + isa::Instruction::I64Store32(..) => MemoryStoreSize::Byte32, _ => unreachable!(), }; @@ -1043,8 +1051,11 @@ impl Interpreter { } isa::Instruction::I32Store(..) | isa::Instruction::I32Store8(..) + | isa::Instruction::I32Store16(..) | isa::Instruction::I64Store(..) - | isa::Instruction::I64Store8(..) => { + | isa::Instruction::I64Store8(..) + | isa::Instruction::I64Store16(..) + | isa::Instruction::I64Store32(..) => { if let RunInstructionTracePre::Store { offset, raw_address, From 50a516204b5b3b819a06987fe6f0d9c764c3dccd Mon Sep 17 00:00:00 2001 From: Heng Zhang Date: Fri, 16 Dec 2022 12:49:47 +0800 Subject: [PATCH 084/129] add missing load case --- src/runner.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/runner.rs b/src/runner.rs index 323564e8a8..d34b99e05e 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -493,8 +493,10 @@ impl Interpreter { | isa::Instruction::I32Load16U(offset) => { let load_size = match *instructions { isa::Instruction::I32Load(..) => MemoryReadSize::U32, - isa::Instruction::I32Load8U(..) => MemoryReadSize::U8, isa::Instruction::I32Load8S(..) => MemoryReadSize::S8, + isa::Instruction::I32Load8U(..) => MemoryReadSize::U8, + isa::Instruction::I32Load16S(..) => MemoryReadSize::S16, + isa::Instruction::I32Load16U(..) => MemoryReadSize::U16, _ => unreachable!(), }; From e700d70ab6261e4424f8b078ce80fc65cc8f6957 Mon Sep 17 00:00:00 2001 From: hzx Date: Mon, 26 Dec 2022 14:25:58 +0800 Subject: [PATCH 085/129] support store cross --- src/runner.rs | 69 +++++++++++++++++++++++++++++++++++++++----- src/tracer/etable.rs | 3 +- 2 files changed, 63 insertions(+), 9 deletions(-) diff --git a/src/runner.rs b/src/runner.rs index d34b99e05e..91684c4bf5 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -571,7 +571,7 @@ impl Interpreter { effective_address(offset, raw_address).map_or(None, |addr| Some(addr)); let mmid = tracer.lookup_memory_instance(&function_context.memory.clone().unwrap()); - let pre_block_value = address.map(|address| { + let pre_block_value1 = address.map(|address| { let mut buf = [0u8; 8]; function_context .memory @@ -582,6 +582,23 @@ impl Interpreter { u64::from_le_bytes(buf) }); + let pre_block_value2 = address + .map(|address| { + if store_size.byte_size() as u32 + address % 8 > 8 { + let mut buf = [0u8; 8]; + function_context + .memory + .clone() + .unwrap() + .get_into((address / 8 + 1) * 8, &mut buf) + .unwrap(); + Some(u64::from_le_bytes(buf)) + } else { + None + } + }) + .flatten(); + Some(RunInstructionTracePre::Store { offset, raw_address, @@ -590,7 +607,8 @@ impl Interpreter { vtype: parity_wasm::elements::ValueType::I32, store_size, mmid: mmid as u64, - pre_block_value, + pre_block_value1, + pre_block_value2, }) } isa::Instruction::I64Store(offset) @@ -611,7 +629,7 @@ impl Interpreter { effective_address(offset, raw_address).map_or(None, |addr| Some(addr)); let mmid = tracer.lookup_memory_instance(&function_context.memory.clone().unwrap()); - let pre_block_value = address.map(|address| { + let pre_block_value1 = address.map(|address| { let mut buf = [0u8; 8]; function_context .memory @@ -622,6 +640,23 @@ impl Interpreter { u64::from_le_bytes(buf) }); + let pre_block_value2 = address + .map(|address| { + if store_size.byte_size() as u32 + address % 8 > 8 { + let mut buf = [0u8; 8]; + function_context + .memory + .clone() + .unwrap() + .get_into((address / 8 + 1) * 8, &mut buf) + .unwrap(); + Some(u64::from_le_bytes(buf)) + } else { + None + } + }) + .flatten(); + Some(RunInstructionTracePre::Store { offset, raw_address, @@ -630,7 +665,8 @@ impl Interpreter { vtype: parity_wasm::elements::ValueType::I64, store_size, mmid: mmid as u64, - pre_block_value, + pre_block_value1, + pre_block_value2, }) } @@ -1066,10 +1102,11 @@ impl Interpreter { vtype, store_size, mmid, - pre_block_value, + pre_block_value1, + pre_block_value2, } = pre_status.unwrap() { - let updated_block_value = { + let updated_block_value1 = { let mut buf = [0u8; 8]; context .memory @@ -1080,6 +1117,20 @@ impl Interpreter { u64::from_le_bytes(buf) }; + let updated_block_value2 = + if effective_address.unwrap() % 8 + store_size.byte_size() as u32 > 8 { + let mut buf = [0u8; 8]; + context + .memory + .clone() + .unwrap() + .get_into((effective_address.unwrap() / 8 + 1) * 8, &mut buf) + .unwrap(); + u64::from_le_bytes(buf) + } else { + 0 + }; + StepInfo::Store { vtype: vtype.into(), store_size, @@ -1088,8 +1139,10 @@ impl Interpreter { effective_address: effective_address.unwrap(), value: value as u64, mmid, - pre_block_value: pre_block_value.unwrap(), - updated_block_value, + pre_block_value1: pre_block_value1.unwrap(), + pre_block_value2: pre_block_value2.unwrap_or(0u64), + updated_block_value1, + updated_block_value2, } } else { unreachable!() diff --git a/src/tracer/etable.rs b/src/tracer/etable.rs index c426f2e0bf..3e327c905d 100644 --- a/src/tracer/etable.rs +++ b/src/tracer/etable.rs @@ -51,7 +51,8 @@ pub enum RunInstructionTracePre { vtype: ValueType, store_size: MemoryStoreSize, mmid: u64, - pre_block_value: Option, + pre_block_value1: Option, + pre_block_value2: Option, }, I32BinOp { From 4a5bae4e1a3a77ae53fc63ccf845220228e46f7a Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Sun, 18 Dec 2022 17:47:40 +0000 Subject: [PATCH 086/129] feat: support call_indirect --- src/isa.rs | 2 +- src/module.rs | 68 ++++++++++++++++++++++++-------------------- src/runner.rs | 62 ++++++++++++++++++++++++++++++++++++---- src/tracer/etable.rs | 5 ++++ src/tracer/mod.rs | 34 +++++++++++++++++++++- 5 files changed, 133 insertions(+), 38 deletions(-) diff --git a/src/isa.rs b/src/isa.rs index 27d2046645..70cb5bac94 100644 --- a/src/isa.rs +++ b/src/isa.rs @@ -457,7 +457,7 @@ impl<'a> Instruction<'a> { }, } } - Instruction::CallIndirect(_) => todo!(), + Instruction::CallIndirect(idx) => Opcode::CallIndirect { type_idx: idx }, Instruction::Drop => Opcode::Drop, Instruction::Select(_) => Opcode::Select, Instruction::GetGlobal(idx) => Opcode::GlobalGet { idx: idx as u64 }, diff --git a/src/module.rs b/src/module.rs index bc0b14bca9..ff93be43a2 100644 --- a/src/module.rs +++ b/src/module.rs @@ -166,7 +166,7 @@ impl ExternVal { /// [`invoke_export`]: #method.invoke_export #[derive(Debug, PartialEq)] pub struct ModuleInstance { - signatures: RefCell>>, + pub(crate) signatures: RefCell>>, tables: RefCell>, funcs: RefCell>, memories: RefCell>, @@ -239,6 +239,7 @@ impl ModuleInstance { fn alloc_module<'i, I: Iterator>( loaded_module: &Module, extern_vals: I, + tracer: Option>>, ) -> Result { let module = loaded_module.module(); let instance = ModuleRef(Rc::new(ModuleInstance::default())); @@ -338,6 +339,13 @@ impl ModuleInstance { }; let func_instance = FuncInstance::alloc_internal(Rc::downgrade(&instance.0), signature, func_body); + + if let Some(tracer) = tracer.clone() { + tracer + .borrow_mut() + .push_type_of_func_ref(func_instance.clone(), ty.type_ref()) + } + instance.push_func(func_instance); } } @@ -422,7 +430,13 @@ impl ModuleInstance { ) -> Result, Error> { let module = loaded_module.module(); - let module_ref = ModuleInstance::alloc_module(loaded_module, extern_vals)?; + let module_ref = ModuleInstance::alloc_module(loaded_module, extern_vals, tracer.clone())?; + + if let Some(tracer) = tracer.clone() { + tracer + .borrow_mut() + .register_module_instance(loaded_module, &module_ref); + } for element_segment in module .elements_section() @@ -457,6 +471,18 @@ impl ModuleInstance { .func_by_index(*func_idx) .expect("Due to validation funcs from element segments should exists"); + if let Some(tracer) = tracer.clone() { + let func_idx = tracer.borrow().lookup_function(&func); + let type_idx = tracer.borrow().lookup_type_of_func_ref(&func); + + tracer.borrow_mut().push_elem( + DEFAULT_TABLE_INDEX, + offset_val + j as u32, + func_idx as u32, + type_idx as u32, + ); + } + table_inst.set(offset_val + j as u32, Some(func))?; } } @@ -477,23 +503,20 @@ impl ModuleInstance { memory_inst.set(offset_val, data_segment.value())?; } - match &tracer { - Some(tracer) => { - let current_module_id = { tracer.borrow().next_module_id() }; + if let Some(tracer) = tracer { + let current_module_id = { tracer.borrow().lookup_module_instance(&module_ref) }; - { - let mut tracer = tracer.borrow_mut(); + { + let mut tracer = tracer.borrow_mut(); - for (globalidx, globalref) in module_ref.globals().iter().enumerate() { - tracer.push_global(current_module_id, globalidx as u32, globalref); - } + for (globalidx, globalref) in module_ref.globals().iter().enumerate() { + tracer.push_global(current_module_id, globalidx as u32, globalref); + } - if let Some(memory_ref) = module_ref.memory_by_index(DEFAULT_MEMORY_INDEX) { - tracer.push_init_memory(memory_ref) - } + if let Some(memory_ref) = module_ref.memory_by_index(DEFAULT_MEMORY_INDEX) { + tracer.push_init_memory(memory_ref) } } - None => (), } Ok(NotStartedModuleRef { @@ -607,23 +630,6 @@ impl ModuleInstance { let module_ref = Self::with_externvals(loaded_module, extern_vals.iter(), tracer.clone()); - let _ = module_ref.as_ref().map(|module_ref| { - let module = module_ref.loaded_module; - match tracer { - Some(tracer) => { - /* - (*tracer) - .borrow_mut() - .statistics_instructions(&module_ref.instance); - */ - (*tracer) - .borrow_mut() - .register_module_instance(module, &module_ref.instance); - } - None => (), - } - }); - module_ref } diff --git a/src/runner.rs b/src/runner.rs index 91684c4bf5..4ae2229787 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -478,6 +478,16 @@ impl Interpreter { Some(RunInstructionTracePre::Call { args }) } + isa::Instruction::CallIndirect(type_idx) => { + let table_idx = DEFAULT_TABLE_INDEX; + let offset = <_>::from_value_internal(*self.value_stack.top()); + + Some(RunInstructionTracePre::CallIndirect { + table_idx, + type_idx, + offset, + }) + } isa::Instruction::Drop => Some(RunInstructionTracePre::Drop), isa::Instruction::Select(vtype) => Some(RunInstructionTracePre::Select { @@ -882,7 +892,10 @@ impl Interpreter { vec![] }, keep_values: match target.drop_keep.keep { - Keep::Single(_) => vec![(*self.value_stack.top()).0], + Keep::Single(t) => vec![from_value_internal_to_u64_with_typ( + t.into(), + *self.value_stack.top(), + )], Keep::None => vec![], }, }, @@ -898,7 +911,10 @@ impl Interpreter { vec![] }, keep_values: match target.drop_keep.keep { - Keep::Single(_) => vec![(*self.value_stack.top()).0], + Keep::Single(t) => vec![from_value_internal_to_u64_with_typ( + t.into(), + *self.value_stack.top(), + )], Keep::None => vec![], }, } @@ -918,7 +934,10 @@ impl Interpreter { vec![] }, keep_values: match target.drop_keep.keep { - Keep::Single(_) => vec![(*self.value_stack.top()).0], + Keep::Single(t) => vec![from_value_internal_to_u64_with_typ( + t.into(), + *self.value_stack.top(), + )], Keep::None => vec![], }, } @@ -938,7 +957,10 @@ impl Interpreter { vec![] }, keep_values: match targets.get(index as u32).drop_keep.keep { - Keep::Single(_) => vec![(*self.value_stack.top()).0], + Keep::Single(t) => vec![from_value_internal_to_u64_with_typ( + t.into(), + *self.value_stack.top(), + )], Keep::None => vec![], }, } @@ -963,7 +985,10 @@ impl Interpreter { }, drop_values: drop_values.iter().map(|v| v.0).collect::>(), keep_values: match keep { - Keep::Single(_) => vec![(*self.value_stack.top()).0], + Keep::Single(t) => vec![from_value_internal_to_u64_with_typ( + t.into(), + *self.value_stack.top(), + )], Keep::None => vec![], }, } @@ -1037,6 +1062,33 @@ impl Interpreter { unreachable!() } } + isa::Instruction::CallIndirect(_) => { + if let RunInstructionTracePre::CallIndirect { + table_idx, + type_idx, + offset, + } = pre_status.unwrap() + { + let tracer = self.tracer.clone().unwrap(); + + let table = context + .module() + .table_by_index(DEFAULT_TABLE_INDEX) + .unwrap(); + let func_ref = table.get(offset).unwrap().unwrap(); + + let func_idx = tracer.borrow().lookup_function(&func_ref); + + StepInfo::CallIndirect { + table_index: table_idx, + type_index: type_idx, + offset, + func_index: func_idx, + } + } else { + unreachable!() + } + } isa::Instruction::I32Load(..) | isa::Instruction::I32Load8U(..) diff --git a/src/tracer/etable.rs b/src/tracer/etable.rs index 3e327c905d..770952be13 100644 --- a/src/tracer/etable.rs +++ b/src/tracer/etable.rs @@ -24,6 +24,11 @@ pub enum RunInstructionTracePre { Call { args: Vec, }, + CallIndirect { + table_idx: u32, + type_idx: u32, + offset: u32, + }, SetLocal { depth: u32, diff --git a/src/tracer/mod.rs b/src/tracer/mod.rs index f6ee1c1a59..ab30756821 100644 --- a/src/tracer/mod.rs +++ b/src/tracer/mod.rs @@ -1,6 +1,11 @@ use std::collections::HashMap; -use specs::{host_function::HostFunctionDesc, mtable::VarType, types::FunctionType}; +use specs::{ + brtable::{ElemEntry, ElemTable}, + host_function::HostFunctionDesc, + mtable::VarType, + types::FunctionType, +}; use crate::{ runner::{from_value_internal_to_u64_with_typ, ValueInternal}, @@ -37,6 +42,8 @@ pub struct Tracer { pub imtable: IMTable, pub etable: ETable, pub jtable: JTable, + pub elem_table: ElemTable, + type_of_func_ref: Vec<(FuncRef, u32)>, module_instance_lookup: Vec<(ModuleRef, u16)>, memory_instance_lookup: Vec<(MemoryRef, u16)>, global_instance_lookup: Vec<(GlobalRef, (u16, u16))>, @@ -56,6 +63,8 @@ impl Tracer { etable: ETable::default(), last_jump_eid: vec![0], jtable: JTable::default(), + elem_table: ElemTable::default(), + type_of_func_ref: vec![], module_instance_lookup: vec![], memory_instance_lookup: vec![], global_instance_lookup: vec![], @@ -146,6 +155,21 @@ impl Tracer { } } + pub(crate) fn push_elem(&mut self, table_idx: u32, offset: u32, func_idx: u32, type_idx: u32) { + self.elem_table.insert( + ElemEntry { + table_idx, + type_idx, + offset, + func_idx, + }, + ) + } + + pub(crate) fn push_type_of_func_ref(&mut self, func: FuncRef, type_idx: u32) { + self.type_of_func_ref.push((func, type_idx)) + } + #[allow(dead_code)] pub(crate) fn statistics_instructions<'a>(&mut self, module_instance: &ModuleRef) { let mut func_index = 0; @@ -174,6 +198,14 @@ impl Tracer { } } + pub(crate) fn lookup_type_of_func_ref(&self, func_ref: &FuncRef) -> u32 { + self.type_of_func_ref + .iter() + .find(|&f| f.0 == *func_ref) + .unwrap() + .1 + } + pub(crate) fn register_module_instance( &mut self, module: &Module, From 144ec6c73c4eec27f0349b2d78df29e40999d730 Mon Sep 17 00:00:00 2001 From: hzx Date: Thu, 29 Dec 2022 13:58:01 +0800 Subject: [PATCH 087/129] feat: support load cross --- src/runner.rs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/runner.rs b/src/runner.rs index 4ae2229787..09960d9c9c 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -1111,7 +1111,7 @@ impl Interpreter { mmid, } = pre_status.unwrap() { - let block_value = { + let block_value1 = { let mut buf = [0u8; 8]; context .memory @@ -1122,6 +1122,20 @@ impl Interpreter { u64::from_le_bytes(buf) }; + let block_value2 = + if effective_address.unwrap() % 8 + load_size.byte_size() as u32 > 8 { + let mut buf = [0u8; 8]; + context + .memory + .clone() + .unwrap() + .get_into((effective_address.unwrap() / 8 + 1) * 8, &mut buf) + .unwrap(); + u64::from_le_bytes(buf) + } else { + 0 + }; + StepInfo::Load { vtype: vtype.into(), load_size, @@ -1132,7 +1146,8 @@ impl Interpreter { vtype.into(), *self.value_stack.top(), ), - block_value, + block_value1, + block_value2, mmid, } } else { From 6c78965d1ccb828a6342ea6872d3cc288d6882c4 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Wed, 4 Jan 2023 06:34:13 +0000 Subject: [PATCH 088/129] feat: support memory.size/memory.grow instruction --- src/isa.rs | 4 ++-- src/module.rs | 10 ++++++++++ src/runner.rs | 24 ++++++++++++++++++++++++ src/tracer/etable.rs | 6 ++++++ src/tracer/mod.rs | 17 +++++++++-------- 5 files changed, 51 insertions(+), 10 deletions(-) diff --git a/src/isa.rs b/src/isa.rs index 70cb5bac94..b18b402a02 100644 --- a/src/isa.rs +++ b/src/isa.rs @@ -561,8 +561,8 @@ impl<'a> Instruction<'a> { vtype: VarType::I64, size: MemoryStoreSize::Byte32, }, - Instruction::CurrentMemory => todo!(), - Instruction::GrowMemory => todo!(), + Instruction::CurrentMemory => Opcode::MemorySize, + Instruction::GrowMemory => Opcode::MemoryGrow, Instruction::I32Const(v) => Opcode::Const { vtype: VarType::I32, value: v as u32 as u64, diff --git a/src/module.rs b/src/module.rs index ff93be43a2..1e02c8a133 100644 --- a/src/module.rs +++ b/src/module.rs @@ -30,6 +30,7 @@ use core::{ fmt, }; use parity_wasm::elements::{External, InitExpr, Instruction, Internal, ResizableLimits, Type}; +use specs::configure_table::ConfigureTable; use validation::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX}; /// Reference to a [`ModuleInstance`]. @@ -367,6 +368,15 @@ impl ModuleInstance { let memory = MemoryInstance::alloc(initial, maximum) .expect("Due to validation `initial` and `maximum` should be valid"); instance.push_memory(memory); + + if let Some(tracer) = tracer.clone() { + let mut tracer = tracer.borrow_mut(); + + tracer.configure_table = ConfigureTable { + init_memory_pages: memory_type.limits().initial() as usize, + maximal_memory_pages: memory_type.limits().maximum().unwrap_or(65536) as usize, + }; + } } for global_entry in module diff --git a/src/runner.rs b/src/runner.rs index 09960d9c9c..76087f9e47 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -680,6 +680,11 @@ impl Interpreter { }) } + isa::Instruction::CurrentMemory => None, + isa::Instruction::GrowMemory => Some(RunInstructionTracePre::GrowMemory( + <_>::from_value_internal(*self.value_stack.pick(1)), + )), + isa::Instruction::I32Const(_) => None, isa::Instruction::I64Const(_) => None, @@ -1216,6 +1221,18 @@ impl Interpreter { } } + isa::Instruction::CurrentMemory => StepInfo::MemorySize, + isa::Instruction::GrowMemory => { + if let RunInstructionTracePre::GrowMemory(grow_size) = pre_status.unwrap() { + StepInfo::MemoryGrow { + grow_size, + result: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } + isa::Instruction::I32Const(value) => StepInfo::I32Const { value }, isa::Instruction::I64Const(value) => StepInfo::I64Const { value }, @@ -1907,6 +1924,12 @@ impl Interpreter { None }; + let current_memory = { + function_context + .memory() + .map_or(0usize, |m| m.current_size().0) + }; + macro_rules! trace_post { () => { if let Some(tracer) = self.tracer.clone() { @@ -1928,6 +1951,7 @@ impl Interpreter { module_instance, function, sp as u64, + current_memory, pc, last_jump_eid, instruction, diff --git a/src/tracer/etable.rs b/src/tracer/etable.rs index 770952be13..34f9e9a1f9 100644 --- a/src/tracer/etable.rs +++ b/src/tracer/etable.rs @@ -60,6 +60,8 @@ pub enum RunInstructionTracePre { pre_block_value2: Option, }, + GrowMemory(i32), + I32BinOp { left: i32, right: i32, @@ -109,6 +111,7 @@ pub enum RunInstructionTracePre { pub struct EEntry { pub id: u64, pub sp: u64, + pub memory_size: usize, pub last_jump_eid: u64, pub inst: IEntry, pub step: StepInfo, @@ -126,6 +129,7 @@ impl Into for EEntry { last_jump_eid: self.last_jump_eid, inst: self.inst.into(), step_info: self.step.clone(), + allocated_memory_pages: self.memory_size, } } } @@ -165,6 +169,7 @@ impl ETable { module_instance_index: u16, func_index: u16, sp: u64, + memory_size: usize, pc: u32, last_jump_eid: u64, opcode: Opcode, @@ -173,6 +178,7 @@ impl ETable { let eentry = EEntry { id: self.allocate_eid(), sp, + memory_size, last_jump_eid, inst: IEntry { module_instance_index: module_instance_index as u16, diff --git a/src/tracer/mod.rs b/src/tracer/mod.rs index ab30756821..966a1d41da 100644 --- a/src/tracer/mod.rs +++ b/src/tracer/mod.rs @@ -2,6 +2,7 @@ use std::collections::HashMap; use specs::{ brtable::{ElemEntry, ElemTable}, + configure_table::ConfigureTable, host_function::HostFunctionDesc, mtable::VarType, types::FunctionType, @@ -43,6 +44,7 @@ pub struct Tracer { pub etable: ETable, pub jtable: JTable, pub elem_table: ElemTable, + pub configure_table: ConfigureTable, type_of_func_ref: Vec<(FuncRef, u32)>, module_instance_lookup: Vec<(ModuleRef, u16)>, memory_instance_lookup: Vec<(MemoryRef, u16)>, @@ -64,6 +66,7 @@ impl Tracer { last_jump_eid: vec![0], jtable: JTable::default(), elem_table: ElemTable::default(), + configure_table: ConfigureTable::default(), type_of_func_ref: vec![], module_instance_lookup: vec![], memory_instance_lookup: vec![], @@ -156,14 +159,12 @@ impl Tracer { } pub(crate) fn push_elem(&mut self, table_idx: u32, offset: u32, func_idx: u32, type_idx: u32) { - self.elem_table.insert( - ElemEntry { - table_idx, - type_idx, - offset, - func_idx, - }, - ) + self.elem_table.insert(ElemEntry { + table_idx, + type_idx, + offset, + func_idx, + }) } pub(crate) fn push_type_of_func_ref(&mut self, func: FuncRef, type_idx: u32) { From 8debc77fb6a9300f48066865183a426bea388280 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Wed, 18 Jan 2023 19:26:27 +0800 Subject: [PATCH 089/129] feat: support i64eqz --- src/isa.rs | 5 ++++- src/runner.rs | 14 ++++++++++++++ src/tracer/etable.rs | 1 + 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/isa.rs b/src/isa.rs index b18b402a02..b0b4eb7feb 100644 --- a/src/isa.rs +++ b/src/isa.rs @@ -617,7 +617,10 @@ impl<'a> Instruction<'a> { class: RelOp::UnsignedGe, vtype: VarType::I32, }, - Instruction::I64Eqz => todo!(), + Instruction::I64Eqz => Opcode::Test { + class: TestOp::Eqz, + vtype: VarType::I64, + }, Instruction::I64Eq => Opcode::Rel { class: RelOp::Eq, vtype: VarType::I64, diff --git a/src/runner.rs b/src/runner.rs index 76087f9e47..66ec164e22 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -691,6 +691,9 @@ impl Interpreter { isa::Instruction::I32Eqz => Some(RunInstructionTracePre::I32Single( <_>::from_value_internal(*self.value_stack.pick(1)), )), + isa::Instruction::I64Eqz => Some(RunInstructionTracePre::I64Single( + <_>::from_value_internal(*self.value_stack.pick(1)), + )), isa::Instruction::I32Eq | isa::Instruction::I32Ne @@ -1368,6 +1371,17 @@ impl Interpreter { } } + isa::Instruction::I64Eqz => { + if let RunInstructionTracePre::I64Single(value) = pre_status.unwrap() { + StepInfo::Test { + vtype: VarType::I64, + value: value as u64, + result: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } isa::Instruction::I64Eq => { if let RunInstructionTracePre::I64Comp { left, right } = pre_status.unwrap() { StepInfo::I64Comp { diff --git a/src/tracer/etable.rs b/src/tracer/etable.rs index 34f9e9a1f9..189db093d5 100644 --- a/src/tracer/etable.rs +++ b/src/tracer/etable.rs @@ -81,6 +81,7 @@ pub enum RunInstructionTracePre { left: i32, right: i32, }, + I64Single(i64), I64Comp { left: i64, right: i64, From 4d22067e8dc9b9913694b4edb65fba4dfd087f18 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Mon, 30 Jan 2023 18:32:46 +0800 Subject: [PATCH 090/129] refactor: unify tables strucutre with zkwasm --- src/runner.rs | 33 +++++++++---- src/tracer/etable.rs | 107 ++++++++++++++---------------------------- src/tracer/imtable.rs | 22 ++++++--- src/tracer/itable.rs | 53 --------------------- src/tracer/jtable.rs | 33 ------------- src/tracer/mod.rs | 40 +++++++--------- 6 files changed, 91 insertions(+), 197 deletions(-) delete mode 100644 src/tracer/itable.rs delete mode 100644 src/tracer/jtable.rs diff --git a/src/runner.rs b/src/runner.rs index 66ec164e22..0075baea09 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -8,7 +8,10 @@ use crate::{ memory_units::Pages, module::ModuleRef, nan_preserving_float::{F32, F64}, - tracer::{etable::RunInstructionTracePre, Tracer}, + tracer::{ + etable::{ETable, RunInstructionTracePre}, + Tracer, + }, value::{ ArithmeticOps, ExtendInto, @@ -29,7 +32,8 @@ use alloc::{boxed::Box, vec::Vec}; use core::{cell::RefCell, fmt, ops, u32, usize}; use parity_wasm::elements::Local; use specs::{ - itable::{BinOp, BitOp, RelOp, ShiftOp, UnaryOp}, + itable::{BinOp, BitOp, InstructionTableEntry, RelOp, ShiftOp, UnaryOp}, + jtable::JumpTableEntry, mtable::{MemoryReadSize, MemoryStoreSize, VarType}, step::StepInfo, }; @@ -334,7 +338,11 @@ impl Interpreter { function_context.position, ); - tracer.jtable.push(eid, last_jump_eid, &inst); + tracer.jtable.push(JumpTableEntry { + eid, + last_jump_eid, + inst: Box::new(inst.into()), + }); tracer.push_frame(); } @@ -384,9 +392,9 @@ impl Interpreter { if let Some(tracer) = self.tracer.clone() { let mut tracer = (*tracer).borrow_mut(); - let entry = tracer.etable.entries.last_mut().unwrap(); + let entry = tracer.etable.get_last_entry_mut().unwrap(); - match &entry.step { + match &entry.step_info { StepInfo::CallHost { plugin, host_function_idx, @@ -397,7 +405,7 @@ impl Interpreter { op_index_in_plugin, } => { assert!(ret_val.is_none()); - entry.step = StepInfo::CallHost { + entry.step_info = StepInfo::CallHost { plugin: *plugin, host_function_idx: *host_function_idx, function_name: function_name.clone(), @@ -1961,14 +1969,19 @@ impl Interpreter { let last_jump_eid = tracer.last_jump_eid(); + let inst_entry = InstructionTableEntry { + moid: module_instance, + mmid: module_instance, + fid: function, + iid: pc as u16, + opcode: instruction, + }; + tracer.etable.push( - module_instance, - function, + inst_entry, sp as u64, current_memory, - pc, last_jump_eid, - instruction, post_status, ); } diff --git a/src/tracer/etable.rs b/src/tracer/etable.rs index 189db093d5..538ef619ad 100644 --- a/src/tracer/etable.rs +++ b/src/tracer/etable.rs @@ -1,15 +1,13 @@ use parity_wasm::elements::ValueType; use specs::{ - etable::EventTableEntry, - itable::Opcode, + etable::{EventTable, EventTableEntry}, + itable::InstructionTableEntry, mtable::{MemoryReadSize, MemoryStoreSize, VarType}, step::StepInfo, }; use crate::{runner::ValueInternal, DEFAULT_VALUE_STACK_LIMIT}; -use super::itable::IEntry; - pub enum RunInstructionTracePre { BrIfEqz { value: i32, @@ -108,89 +106,54 @@ pub enum RunInstructionTracePre { }, } -#[derive(Debug, Clone)] -pub struct EEntry { - pub id: u64, - pub sp: u64, - pub memory_size: usize, - pub last_jump_eid: u64, - pub inst: IEntry, - pub step: StepInfo, -} - -impl Into for EEntry { - fn into(self) -> EventTableEntry { - EventTableEntry { - eid: self.id, - sp: (DEFAULT_VALUE_STACK_LIMIT as u64) - .checked_sub(self.sp) - .unwrap() - .checked_sub(1) - .unwrap(), - last_jump_eid: self.last_jump_eid, - inst: self.inst.into(), - step_info: self.step.clone(), - allocated_memory_pages: self.memory_size, - } - } -} +pub(crate) trait ETable { + fn get_latest_eid(&self) -> u64; -#[derive(Debug)] -pub struct ETable { - eid: u64, - pub(crate) entries: Vec, -} + fn get_last_entry_mut(&mut self) -> Option<&mut EventTableEntry>; -impl Default for ETable { - fn default() -> Self { - Self { - eid: 1, - entries: vec![], - } - } + fn push( + &mut self, + inst: InstructionTableEntry, + sp: u64, + allocated_memory_pages: usize, + last_jump_eid: u64, + step_info: StepInfo, + ) -> EventTableEntry; } -impl ETable { - pub fn get_latest_eid(&self) -> u64 { - self.entries.last().unwrap().id - } - - pub fn get_entries(&self) -> &Vec { - &self.entries +impl ETable for EventTable { + fn get_latest_eid(&self) -> u64 { + self.entries().last().unwrap().eid } - fn allocate_eid(&mut self) -> u64 { - let r = self.eid; - self.eid = r + 1; - return r; + fn get_last_entry_mut(&mut self) -> Option<&mut EventTableEntry> { + self.entries_mut().last_mut() } - pub fn push( + fn push( &mut self, - module_instance_index: u16, - func_index: u16, + inst: InstructionTableEntry, sp: u64, - memory_size: usize, - pc: u32, + allocated_memory_pages: usize, last_jump_eid: u64, - opcode: Opcode, - step: StepInfo, - ) -> EEntry { - let eentry = EEntry { - id: self.allocate_eid(), + step_info: StepInfo, + ) -> EventTableEntry { + let sp = (DEFAULT_VALUE_STACK_LIMIT as u64) + .checked_sub(sp) + .unwrap() + .checked_sub(1) + .unwrap(); + + let eentry = EventTableEntry { + eid: self.entries().len() as u64 + 1, sp, - memory_size, + allocated_memory_pages, last_jump_eid, - inst: IEntry { - module_instance_index: module_instance_index as u16, - func_index, - pc: pc as u16, - opcode, - }, - step, + inst, + step_info, }; - self.entries.push(eentry.clone()); + self.entries_mut().push(eentry.clone()); eentry } diff --git a/src/tracer/imtable.rs b/src/tracer/imtable.rs index 87e6b5d5ef..fe778b0a99 100644 --- a/src/tracer/imtable.rs +++ b/src/tracer/imtable.rs @@ -1,5 +1,5 @@ use specs::{ - imtable::InitMemoryTableEntry, + imtable::{InitMemoryTable, InitMemoryTableEntry}, mtable::{LocationType, VarType}, }; @@ -31,10 +31,10 @@ impl Into for IMEntry { } #[derive(Debug, Default)] -pub struct IMTable(pub Vec); +pub struct IMTable(Vec); impl IMTable { - pub(crate) fn push( + pub fn push( &mut self, is_global: bool, is_mutable: bool, @@ -43,13 +43,21 @@ impl IMTable { vtype: VarType, value: u64, ) { - self.0.push(IMEntry { + self.0.push(InitMemoryTableEntry { is_mutable, - is_global, - module_instance_index, - offset, + ltype: if is_global { + LocationType::Global + } else { + LocationType::Heap + }, + mmid: module_instance_index as u64, + offset: offset as u64, vtype, value, }) } + + pub fn finalized(&self) -> InitMemoryTable { + InitMemoryTable::new(self.0.clone()) + } } diff --git a/src/tracer/itable.rs b/src/tracer/itable.rs deleted file mode 100644 index 4a25807bdb..0000000000 --- a/src/tracer/itable.rs +++ /dev/null @@ -1,53 +0,0 @@ -use core::fmt::Debug; - -use specs::itable::{InstructionTableEntry, Opcode}; - -#[derive(Debug, Clone)] -pub struct IEntry { - pub module_instance_index: u16, - pub func_index: u16, - pub pc: u16, - pub opcode: Opcode, -} - -impl Into for IEntry { - fn into(self) -> InstructionTableEntry { - InstructionTableEntry { - moid: self.module_instance_index, - mmid: self.module_instance_index, - fid: self.func_index, - iid: self.pc, - opcode: self.opcode, - } - } -} - -#[derive(Debug)] -pub struct ITable(pub Vec); - -impl Default for ITable { - fn default() -> Self { - Self(vec![]) - } -} - -impl ITable { - pub(crate) fn push( - &mut self, - module_instance_index: u32, - func_index: u16, - pc: u32, - opcode: Opcode, - ) -> IEntry { - let ientry = IEntry { - module_instance_index: module_instance_index as u16, - func_index, - pc: pc as u16, - opcode, - }; - - self.0.push(ientry.clone()); - - ientry - } -} diff --git a/src/tracer/jtable.rs b/src/tracer/jtable.rs deleted file mode 100644 index 9b73a757c3..0000000000 --- a/src/tracer/jtable.rs +++ /dev/null @@ -1,33 +0,0 @@ -use specs::jtable::JumpTableEntry; - -use super::itable::IEntry; - -#[derive(Debug, Clone)] -pub struct JEntry { - eid: u64, - last_jump_eid: u64, - inst: IEntry, -} - -#[derive(Debug, Default)] -pub struct JTable(pub Vec); - -impl JTable { - pub fn push(&mut self, eid: u64, last_jump_eid: u64, inst: &IEntry) { - self.0.push(JEntry { - eid, - last_jump_eid, - inst: inst.clone(), - }) - } -} - -impl Into for JEntry { - fn into(self) -> JumpTableEntry { - JumpTableEntry { - eid: self.eid, - last_jump_eid: self.last_jump_eid, - inst: Box::new(self.inst.into()), - } - } -} diff --git a/src/tracer/mod.rs b/src/tracer/mod.rs index 966a1d41da..81bd2a848d 100644 --- a/src/tracer/mod.rs +++ b/src/tracer/mod.rs @@ -3,7 +3,10 @@ use std::collections::HashMap; use specs::{ brtable::{ElemEntry, ElemTable}, configure_table::ConfigureTable, + etable::EventTable, host_function::HostFunctionDesc, + itable::{InstructionTable, InstructionTableEntry}, + jtable::JumpTable, mtable::VarType, types::FunctionType, }; @@ -18,17 +21,10 @@ use crate::{ Signature, }; -use self::{ - etable::ETable, - imtable::IMTable, - itable::{IEntry, ITable}, - jtable::JTable, -}; +use self::{etable::ETable, imtable::IMTable}; pub mod etable; pub mod imtable; -pub mod itable; -pub mod jtable; #[derive(Debug)] pub struct FuncDesc { @@ -39,10 +35,10 @@ pub struct FuncDesc { #[derive(Debug)] pub struct Tracer { - pub itable: ITable, + pub itable: InstructionTable, pub imtable: IMTable, - pub etable: ETable, - pub jtable: JTable, + pub etable: EventTable, + pub jtable: JumpTable, pub elem_table: ElemTable, pub configure_table: ConfigureTable, type_of_func_ref: Vec<(FuncRef, u32)>, @@ -60,11 +56,11 @@ impl Tracer { /// Create an empty tracer pub fn new(host_plugin_lookup: HashMap) -> Self { Tracer { - itable: ITable::default(), + itable: InstructionTable::default(), imtable: IMTable::default(), - etable: ETable::default(), + etable: EventTable::default(), last_jump_eid: vec![0], - jtable: JTable::default(), + jtable: JumpTable::default(), elem_table: ElemTable::default(), configure_table: ConfigureTable::default(), type_of_func_ref: vec![], @@ -274,9 +270,9 @@ impl Tracer { let pc = iter.position(); if let Some(instruction) = iter.next() { let _ = self.itable.push( - self.next_module_id() as u32, + self.next_module_id(), funcdesc.index_within_jtable, - pc, + pc as u16, instruction.into(&self.function_index_translation), ); } else { @@ -335,11 +331,11 @@ impl Tracer { self.function_lookup.get(pos).unwrap().1 } - pub fn lookup_ientry(&self, function: &FuncRef, pos: u32) -> IEntry { + pub fn lookup_ientry(&self, function: &FuncRef, pos: u32) -> InstructionTableEntry { let function_idx = self.lookup_function(function); - for ientry in &self.itable.0 { - if ientry.func_index as u16 == function_idx && ientry.pc as u32 == pos { + for ientry in self.itable.entries() { + if ientry.fid as u16 == function_idx && ientry.iid as u32 == pos { return ientry.clone(); } } @@ -347,11 +343,11 @@ impl Tracer { unreachable!() } - pub fn lookup_first_inst(&self, function: &FuncRef) -> IEntry { + pub fn lookup_first_inst(&self, function: &FuncRef) -> InstructionTableEntry { let function_idx = self.lookup_function(function); - for ientry in &self.itable.0 { - if ientry.func_index as u16 == function_idx { + for ientry in self.itable.entries() { + if ientry.fid as u16 == function_idx { return ientry.clone(); } } From ccacdf155a2583f90daf3564ce343ea2d04c3fa6 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Mon, 6 Feb 2023 20:44:16 +0800 Subject: [PATCH 091/129] feat: support external host call --- src/isa.rs | 5 ++++- src/runner.rs | 30 ++++++++++++++++++++++++++++++ src/tracer/mod.rs | 23 ++++++++++++++++++----- 3 files changed, 52 insertions(+), 6 deletions(-) diff --git a/src/isa.rs b/src/isa.rs index b0b4eb7feb..4104912609 100644 --- a/src/isa.rs +++ b/src/isa.rs @@ -449,12 +449,15 @@ impl<'a> Instruction<'a> { function_index, function_name, op_index_in_plugin, - } => Opcode::CallHost { + } => Opcode::InternalHostCall { plugin: *plugin, function_index: *function_index, function_name: function_name.clone(), op_index_in_plugin: *op_index_in_plugin, }, + specs::types::FunctionType::HostFunctionExternal { op, sig, .. } => { + Opcode::ExternalHostCall { op: *op, sig: *sig } + } } } Instruction::CallIndirect(idx) => Opcode::CallIndirect { type_idx: idx }, diff --git a/src/runner.rs b/src/runner.rs index 0075baea09..981d4195a2 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -32,6 +32,7 @@ use alloc::{boxed::Box, vec::Vec}; use core::{cell::RefCell, fmt, ops, u32, usize}; use parity_wasm::elements::Local; use specs::{ + external_host_call_table::ExternalHostCallSignature, itable::{BinOp, BitOp, InstructionTableEntry, RelOp, ShiftOp, UnaryOp}, jtable::JumpTableEntry, mtable::{MemoryReadSize, MemoryStoreSize, VarType}, @@ -418,6 +419,20 @@ impl Interpreter { op_index_in_plugin: *op_index_in_plugin, } } + StepInfo::ExternalHostCall { op, sig, .. } => { + if let ExternalHostCallSignature::Return = sig { + entry.step_info = StepInfo::ExternalHostCall { + op: *op, + value: Some( + from_value_internal_to_u64_with_typ( + VarType::I64, + return_val.into(), + ), + ), + sig: *sig, + } + } + } _ => unreachable!(), } } @@ -1073,6 +1088,21 @@ impl Interpreter { op_index_in_plugin: *op_index_in_plugin, } } + specs::types::FunctionType::HostFunctionExternal { op, sig, .. } => { + StepInfo::ExternalHostCall { + op: *op, + value: match sig { + ExternalHostCallSignature::Argument => { + Some(from_value_internal_to_u64_with_typ( + VarType::I64, + *self.value_stack.top(), + )) + } + ExternalHostCallSignature::Return => None, + }, + sig: *sig, + } + } } } else { unreachable!() diff --git a/src/tracer/mod.rs b/src/tracer/mod.rs index 81bd2a848d..4e89959656 100644 --- a/src/tracer/mod.rs +++ b/src/tracer/mod.rs @@ -230,11 +230,24 @@ impl Tracer { } => { let plugin_desc = self.lookup_host_plugin(host_func_index); - FunctionType::HostFunction { - plugin: plugin_desc.plugin, - function_index: host_func_index, - function_name: plugin_desc.name, - op_index_in_plugin: plugin_desc.op_index_in_plugin, + match plugin_desc { + HostFunctionDesc::Internal { + name, + op_index_in_plugin, + plugin, + } => FunctionType::HostFunction { + plugin, + function_index: host_func_index, + function_name: name, + op_index_in_plugin, + }, + HostFunctionDesc::External { name, op, sig } => { + FunctionType::HostFunctionExternal { + function_name: name, + op, + sig, + } + } } } }; From 67f1bcf604610937e37dc8231ba36dd9199a142b Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Fri, 17 Feb 2023 09:14:36 +0000 Subject: [PATCH 092/129] refactor: remove moid and mmid --- src/module.rs | 16 +++++------ src/runner.rs | 62 +------------------------------------------ src/tracer/etable.rs | 2 -- src/tracer/imtable.rs | 3 --- src/tracer/mod.rs | 61 ++++++------------------------------------ 5 files changed, 15 insertions(+), 129 deletions(-) diff --git a/src/module.rs b/src/module.rs index 1e02c8a133..cd6b9e6971 100644 --- a/src/module.rs +++ b/src/module.rs @@ -514,18 +514,14 @@ impl ModuleInstance { } if let Some(tracer) = tracer { - let current_module_id = { tracer.borrow().lookup_module_instance(&module_ref) }; + let mut tracer = tracer.borrow_mut(); - { - let mut tracer = tracer.borrow_mut(); - - for (globalidx, globalref) in module_ref.globals().iter().enumerate() { - tracer.push_global(current_module_id, globalidx as u32, globalref); - } + for (globalidx, globalref) in module_ref.globals().iter().enumerate() { + tracer.push_global(globalidx as u32, globalref); + } - if let Some(memory_ref) = module_ref.memory_by_index(DEFAULT_MEMORY_INDEX) { - tracer.push_init_memory(memory_ref) - } + if let Some(memory_ref) = module_ref.memory_by_index(DEFAULT_MEMORY_INDEX) { + tracer.push_init_memory(memory_ref) } } diff --git a/src/runner.rs b/src/runner.rs index 981d4195a2..3d1971bbcc 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -446,12 +446,9 @@ impl Interpreter { fn run_instruction_pre( &mut self, - tracer: Rc>, function_context: &FunctionContext, instructions: &isa::Instruction, ) -> Option { - let tracer = tracer.borrow(); - match *instructions { isa::Instruction::GetLocal(..) => None, isa::Instruction::SetLocal(depth, vtype) => { @@ -536,12 +533,6 @@ impl Interpreter { let raw_address = <_>::from_value_internal(*self.value_stack.top()); let address = effective_address(offset, raw_address).map_or(None, |addr| Some(addr)); - let mmid = tracer.lookup_memory_instance( - &function_context - .memory - .clone() - .expect("Due to validation memory should exists"), - ); Some(RunInstructionTracePre::Load { offset, @@ -549,7 +540,6 @@ impl Interpreter { effective_address: address, vtype: parity_wasm::elements::ValueType::I32, load_size, - mmid: mmid as u64, }) } isa::Instruction::I64Load(offset) @@ -572,12 +562,6 @@ impl Interpreter { let raw_address = <_>::from_value_internal(*self.value_stack.top()); let address = effective_address(offset, raw_address).map_or(None, |addr| Some(addr)); - let mmid = tracer.lookup_memory_instance( - &function_context - .memory - .clone() - .expect("Due to validation memory should exists"), - ); Some(RunInstructionTracePre::Load { offset, @@ -585,7 +569,6 @@ impl Interpreter { effective_address: address, vtype: parity_wasm::elements::ValueType::I64, load_size, - mmid: mmid as u64, }) } isa::Instruction::I32Store(offset) @@ -602,7 +585,6 @@ impl Interpreter { let raw_address = <_>::from_value_internal(*self.value_stack.pick(2)); let address = effective_address(offset, raw_address).map_or(None, |addr| Some(addr)); - let mmid = tracer.lookup_memory_instance(&function_context.memory.clone().unwrap()); let pre_block_value1 = address.map(|address| { let mut buf = [0u8; 8]; @@ -639,7 +621,6 @@ impl Interpreter { value: value as u64, vtype: parity_wasm::elements::ValueType::I32, store_size, - mmid: mmid as u64, pre_block_value1, pre_block_value2, }) @@ -660,7 +641,6 @@ impl Interpreter { let raw_address = <_>::from_value_internal(*self.value_stack.pick(2)); let address = effective_address(offset, raw_address).map_or(None, |addr| Some(addr)); - let mmid = tracer.lookup_memory_instance(&function_context.memory.clone().unwrap()); let pre_block_value1 = address.map(|address| { let mut buf = [0u8; 8]; @@ -697,7 +677,6 @@ impl Interpreter { value, vtype: parity_wasm::elements::ValueType::I64, store_size, - mmid: mmid as u64, pre_block_value1, pre_block_value2, }) @@ -856,8 +835,6 @@ impl Interpreter { vtype: vtype.into(), }, isa::Instruction::GetGlobal(idx) => { - let tracer = self.tracer.as_ref().unwrap().borrow(); - let global_ref = context.module().global_by_index(idx).unwrap(); let is_mutable = global_ref.is_mutable(); let vtype: VarType = global_ref.value_type().into_elements().into(); @@ -866,27 +843,14 @@ impl Interpreter { ValueInternal::from(global_ref.get()), ); - let (origin_module, origin_idx) = - tracer.lookup_global_instance(&global_ref).unwrap(); - let moid = tracer.lookup_module_instance(&context.module); - /* - * TODO: imported global is not support yet. - */ - assert_eq!(origin_module, moid); - assert_eq!(origin_idx, idx as u16); - StepInfo::GetGlobal { idx, - origin_module: moid, - origin_idx: idx as u16, vtype, is_mutable, value, } } isa::Instruction::SetGlobal(idx) => { - let tracer = self.tracer.as_ref().unwrap().borrow(); - let global_ref = context.module().global_by_index(idx).unwrap(); let is_mutable = global_ref.is_mutable(); let vtype: VarType = global_ref.value_type().into_elements().into(); @@ -895,19 +859,8 @@ impl Interpreter { ValueInternal::from(global_ref.get()), ); - let (origin_module, origin_idx) = - tracer.lookup_global_instance(&global_ref).unwrap(); - let moid = tracer.lookup_module_instance(&context.module); - /* - * TODO: imported global is not support yet. - */ - assert_eq!(origin_module, moid); - assert_eq!(origin_idx, idx as u16); - StepInfo::SetGlobal { idx, - origin_module: moid, - origin_idx: idx as u16, vtype, is_mutable, value, @@ -1154,7 +1107,6 @@ impl Interpreter { effective_address, vtype, load_size, - mmid, } = pre_status.unwrap() { let block_value1 = { @@ -1194,7 +1146,6 @@ impl Interpreter { ), block_value1, block_value2, - mmid, } } else { unreachable!() @@ -1214,7 +1165,6 @@ impl Interpreter { value, vtype, store_size, - mmid, pre_block_value1, pre_block_value2, } = pre_status.unwrap() @@ -1251,7 +1201,6 @@ impl Interpreter { raw_address, effective_address: effective_address.unwrap(), value: value as u64, - mmid, pre_block_value1: pre_block_value1.unwrap(), pre_block_value2: pre_block_value2.unwrap_or(0u64), updated_block_value1, @@ -1967,11 +1916,7 @@ impl Interpreter { ); let pre_status = if self.tracer.is_some() { - self.run_instruction_pre( - self.tracer.clone().unwrap(), - function_context, - &instruction, - ) + self.run_instruction_pre(function_context, &instruction) } else { None }; @@ -1992,16 +1937,11 @@ impl Interpreter { let instruction = { instruction.into(&tracer.function_index_translation) }; - let module_instance = - tracer.lookup_module_instance(&function_context.module); - let function = tracer.lookup_function(&function_context.function); let last_jump_eid = tracer.last_jump_eid(); let inst_entry = InstructionTableEntry { - moid: module_instance, - mmid: module_instance, fid: function, iid: pc as u16, opcode: instruction, diff --git a/src/tracer/etable.rs b/src/tracer/etable.rs index 538ef619ad..567cca48e5 100644 --- a/src/tracer/etable.rs +++ b/src/tracer/etable.rs @@ -44,7 +44,6 @@ pub enum RunInstructionTracePre { effective_address: Option, // use option in case of memory out of bound vtype: ValueType, load_size: MemoryReadSize, - mmid: u64, }, Store { offset: u32, @@ -53,7 +52,6 @@ pub enum RunInstructionTracePre { value: u64, vtype: ValueType, store_size: MemoryStoreSize, - mmid: u64, pre_block_value1: Option, pre_block_value2: Option, }, diff --git a/src/tracer/imtable.rs b/src/tracer/imtable.rs index fe778b0a99..1152cdd7cc 100644 --- a/src/tracer/imtable.rs +++ b/src/tracer/imtable.rs @@ -22,7 +22,6 @@ impl Into for IMEntry { } else { LocationType::Heap }, - mmid: self.module_instance_index as u64, offset: self.offset as u64, vtype: self.vtype, value: self.value, @@ -38,7 +37,6 @@ impl IMTable { &mut self, is_global: bool, is_mutable: bool, - module_instance_index: u16, offset: u32, vtype: VarType, value: u64, @@ -50,7 +48,6 @@ impl IMTable { } else { LocationType::Heap }, - mmid: module_instance_index as u64, offset: offset as u64, vtype, value, diff --git a/src/tracer/mod.rs b/src/tracer/mod.rs index 4e89959656..7913d0137f 100644 --- a/src/tracer/mod.rs +++ b/src/tracer/mod.rs @@ -42,9 +42,8 @@ pub struct Tracer { pub elem_table: ElemTable, pub configure_table: ConfigureTable, type_of_func_ref: Vec<(FuncRef, u32)>, - module_instance_lookup: Vec<(ModuleRef, u16)>, - memory_instance_lookup: Vec<(MemoryRef, u16)>, - global_instance_lookup: Vec<(GlobalRef, (u16, u16))>, + // GlobalRef to global indexÆ’ + global_instance_lookup: Vec<(GlobalRef, u16)>, function_lookup: Vec<(FuncRef, u16)>, last_jump_eid: Vec, function_index_allocator: u32, @@ -64,8 +63,6 @@ impl Tracer { elem_table: ElemTable::default(), configure_table: ConfigureTable::default(), type_of_func_ref: vec![], - module_instance_lookup: vec![], - memory_instance_lookup: vec![], global_instance_lookup: vec![], function_lookup: vec![], function_index_allocator: 1, @@ -82,14 +79,6 @@ impl Tracer { self.last_jump_eid.pop().unwrap(); } - pub fn next_module_id(&self) -> u16 { - (self.module_instance_lookup.len() as u16) + 1 - } - - pub fn next_memory_id(&self) -> u16 { - (self.memory_instance_lookup.len() as u16) + 1 - } - pub fn last_jump_eid(&self) -> u64 { *self.last_jump_eid.last().unwrap() } @@ -119,34 +108,24 @@ impl Tracer { for i in 0..(pages * 8192) { let mut buf = [0u8; 8]; (*memref).get_into(i * 8, &mut buf).unwrap(); - self.imtable.push( - false, - true, - self.next_memory_id(), - i, - VarType::I64, - u64::from_le_bytes(buf), - ); + self.imtable + .push(false, true, i, VarType::I64, u64::from_le_bytes(buf)); } - - self.memory_instance_lookup - .push((memref, self.next_memory_id())); } - pub(crate) fn push_global(&mut self, moid: u16, globalidx: u32, globalref: &GlobalRef) { + pub(crate) fn push_global(&mut self, globalidx: u32, globalref: &GlobalRef) { let vtype = globalref.elements_value_type().into(); - if let Some((_origin_moid, _origin_idx)) = self.lookup_global_instance(globalref) { + if let Some(_origin_idx) = self.lookup_global_instance(globalref) { // Import global does not support yet. todo!() } else { self.global_instance_lookup - .push((globalref.clone(), (moid, globalidx as u16))); + .push((globalref.clone(), globalidx as u16)); self.imtable.push( true, globalref.is_mutable(), - moid, globalidx, vtype, from_value_internal_to_u64_with_typ(vtype, ValueInternal::from(globalref.get())), @@ -283,7 +262,6 @@ impl Tracer { let pc = iter.position(); if let Some(instruction) = iter.next() { let _ = self.itable.push( - self.next_module_id(), funcdesc.index_within_jtable, pc as u16, instruction.into(&self.function_index_translation), @@ -300,32 +278,9 @@ impl Tracer { } } } - - self.module_instance_lookup - .push((module_instance.clone(), self.next_module_id())); - } - - pub fn lookup_module_instance(&self, module_instance: &ModuleRef) -> u16 { - for m in &self.module_instance_lookup { - if &m.0 == module_instance { - return m.1; - } - } - - unreachable!() - } - - pub fn lookup_memory_instance(&self, module_instance: &MemoryRef) -> u16 { - for m in &self.memory_instance_lookup { - if &m.0 == module_instance { - return m.1; - } - } - - unreachable!() } - pub fn lookup_global_instance(&self, global_instance: &GlobalRef) -> Option<(u16, u16)> { + pub fn lookup_global_instance(&self, global_instance: &GlobalRef) -> Option { for m in &self.global_instance_lookup { if &m.0 == global_instance { return Some(m.1); From 1dbffeddb4ca837d03574a1dfa80205a78b31b52 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Wed, 15 Feb 2023 19:55:49 +0800 Subject: [PATCH 093/129] fix: use GlobalRef as key is incorrect --- src/tracer/mod.rs | 35 +++++++---------------------------- 1 file changed, 7 insertions(+), 28 deletions(-) diff --git a/src/tracer/mod.rs b/src/tracer/mod.rs index 7913d0137f..e6aa293125 100644 --- a/src/tracer/mod.rs +++ b/src/tracer/mod.rs @@ -42,8 +42,6 @@ pub struct Tracer { pub elem_table: ElemTable, pub configure_table: ConfigureTable, type_of_func_ref: Vec<(FuncRef, u32)>, - // GlobalRef to global indexÆ’ - global_instance_lookup: Vec<(GlobalRef, u16)>, function_lookup: Vec<(FuncRef, u16)>, last_jump_eid: Vec, function_index_allocator: u32, @@ -63,7 +61,6 @@ impl Tracer { elem_table: ElemTable::default(), configure_table: ConfigureTable::default(), type_of_func_ref: vec![], - global_instance_lookup: vec![], function_lookup: vec![], function_index_allocator: 1, function_index_translation: Default::default(), @@ -116,21 +113,13 @@ impl Tracer { pub(crate) fn push_global(&mut self, globalidx: u32, globalref: &GlobalRef) { let vtype = globalref.elements_value_type().into(); - if let Some(_origin_idx) = self.lookup_global_instance(globalref) { - // Import global does not support yet. - todo!() - } else { - self.global_instance_lookup - .push((globalref.clone(), globalidx as u16)); - - self.imtable.push( - true, - globalref.is_mutable(), - globalidx, - vtype, - from_value_internal_to_u64_with_typ(vtype, ValueInternal::from(globalref.get())), - ) - } + self.imtable.push( + true, + globalref.is_mutable(), + globalidx, + vtype, + from_value_internal_to_u64_with_typ(vtype, ValueInternal::from(globalref.get())), + ); } pub(crate) fn push_elem(&mut self, table_idx: u32, offset: u32, func_idx: u32, type_idx: u32) { @@ -280,16 +269,6 @@ impl Tracer { } } - pub fn lookup_global_instance(&self, global_instance: &GlobalRef) -> Option { - for m in &self.global_instance_lookup { - if &m.0 == global_instance { - return Some(m.1); - } - } - - None - } - pub fn lookup_function(&self, function: &FuncRef) -> u16 { let pos = self .function_lookup From c86bbac83981dfed1a8c60a665de20b10a2a3e67 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Thu, 16 Feb 2023 13:34:35 +0800 Subject: [PATCH 094/129] feat: support start function --- src/module.rs | 17 +++++++++++++++++ src/runner.rs | 5 +++++ src/tracer/mod.rs | 8 +++++--- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/module.rs b/src/module.rs index cd6b9e6971..96abcce376 100644 --- a/src/module.rs +++ b/src/module.rs @@ -706,6 +706,12 @@ impl ModuleInstance { ) -> Result, Error> { let func_instance = self.func_by_name(func_name)?; + { + let mut tracer = tracer.borrow_mut(); + + tracer.last_jump_eid.push(0); + } + FuncInstance::invoke_trace(&func_instance, args, externals, tracer).map_err(Error::Trap) } @@ -814,6 +820,11 @@ impl<'a> NotStartedModuleRef<'a> { state: &mut E, tracer: Rc>, ) -> Result { + { + let mut tracer = tracer.borrow_mut(); + tracer.last_jump_eid.push(0); + } + if let Some(start_fn_idx) = self.loaded_module.module().start_section() { let start_func = self .instance @@ -863,6 +874,12 @@ impl<'a> NotStartedModuleRef<'a> { pub fn has_start(&self) -> bool { self.loaded_module.module().start_section().is_some() } + + pub fn lookup_function_by_name(&self, tracer: Rc>, func_name: &str) -> u16 { + let func_ref = self.instance.func_by_name(func_name).unwrap(); + + tracer.borrow().lookup_function(&func_ref) + } } fn eval_init_expr(init_expr: &InitExpr, module: &ModuleInstance) -> RuntimeValue { diff --git a/src/runner.rs b/src/runner.rs index 3d1971bbcc..164bd3d14c 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -330,6 +330,10 @@ impl Interpreter { let nested_context = FunctionContext::new(nested_func.clone()); if let Some(tracer) = self.tracer.clone() { + let callee_fid = { + tracer.clone().borrow().lookup_function(&nested_func) as u64 + }; + let mut tracer = (*tracer).borrow_mut(); let eid = tracer.eid(); let last_jump_eid = tracer.last_jump_eid(); @@ -342,6 +346,7 @@ impl Interpreter { tracer.jtable.push(JumpTableEntry { eid, last_jump_eid, + callee_fid, inst: Box::new(inst.into()), }); diff --git a/src/tracer/mod.rs b/src/tracer/mod.rs index e6aa293125..8fa1fbe2e1 100644 --- a/src/tracer/mod.rs +++ b/src/tracer/mod.rs @@ -6,7 +6,7 @@ use specs::{ etable::EventTable, host_function::HostFunctionDesc, itable::{InstructionTable, InstructionTableEntry}, - jtable::JumpTable, + jtable::{JumpTable, StaticFrameEntry}, mtable::VarType, types::FunctionType, }; @@ -43,10 +43,11 @@ pub struct Tracer { pub configure_table: ConfigureTable, type_of_func_ref: Vec<(FuncRef, u32)>, function_lookup: Vec<(FuncRef, u16)>, - last_jump_eid: Vec, + pub(crate) last_jump_eid: Vec, function_index_allocator: u32, pub(crate) function_index_translation: HashMap, pub host_function_index_lookup: HashMap, + pub static_jtable_entries: Vec, } impl Tracer { @@ -56,7 +57,7 @@ impl Tracer { itable: InstructionTable::default(), imtable: IMTable::default(), etable: EventTable::default(), - last_jump_eid: vec![0], + last_jump_eid: vec![], jtable: JumpTable::default(), elem_table: ElemTable::default(), configure_table: ConfigureTable::default(), @@ -65,6 +66,7 @@ impl Tracer { function_index_allocator: 1, function_index_translation: Default::default(), host_function_index_lookup: host_plugin_lookup, + static_jtable_entries: vec![], } } From d23ffcec27d809b513710a44ec39f69dda30bf69 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Tue, 21 Feb 2023 05:33:27 +0000 Subject: [PATCH 095/129] refactor: unify common range --- src/module.rs | 6 +++--- src/runner.rs | 11 +++++------ src/tracer/etable.rs | 20 ++++++++++---------- src/tracer/imtable.rs | 4 ++-- src/tracer/mod.rs | 22 +++++++++++----------- 5 files changed, 31 insertions(+), 32 deletions(-) diff --git a/src/module.rs b/src/module.rs index 96abcce376..a392ee38c4 100644 --- a/src/module.rs +++ b/src/module.rs @@ -373,8 +373,8 @@ impl ModuleInstance { let mut tracer = tracer.borrow_mut(); tracer.configure_table = ConfigureTable { - init_memory_pages: memory_type.limits().initial() as usize, - maximal_memory_pages: memory_type.limits().maximum().unwrap_or(65536) as usize, + init_memory_pages: memory_type.limits().initial(), + maximal_memory_pages: memory_type.limits().maximum().unwrap_or(65536), }; } } @@ -875,7 +875,7 @@ impl<'a> NotStartedModuleRef<'a> { self.loaded_module.module().start_section().is_some() } - pub fn lookup_function_by_name(&self, tracer: Rc>, func_name: &str) -> u16 { + pub fn lookup_function_by_name(&self, tracer: Rc>, func_name: &str) -> u32 { let func_ref = self.instance.func_by_name(func_name).unwrap(); tracer.borrow().lookup_function(&func_ref) diff --git a/src/runner.rs b/src/runner.rs index 164bd3d14c..c183b7be4c 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -330,9 +330,8 @@ impl Interpreter { let nested_context = FunctionContext::new(nested_func.clone()); if let Some(tracer) = self.tracer.clone() { - let callee_fid = { - tracer.clone().borrow().lookup_function(&nested_func) as u64 - }; + let callee_fid = + tracer.clone().borrow().lookup_function(&nested_func); let mut tracer = (*tracer).borrow_mut(); let eid = tracer.eid(); @@ -1948,14 +1947,14 @@ impl Interpreter { let inst_entry = InstructionTableEntry { fid: function, - iid: pc as u16, + iid: pc, opcode: instruction, }; tracer.etable.push( inst_entry, - sp as u64, - current_memory, + sp.try_into().unwrap(), + current_memory.try_into().unwrap(), last_jump_eid, post_status, ); diff --git a/src/tracer/etable.rs b/src/tracer/etable.rs index 567cca48e5..da32b444bd 100644 --- a/src/tracer/etable.rs +++ b/src/tracer/etable.rs @@ -105,22 +105,22 @@ pub enum RunInstructionTracePre { } pub(crate) trait ETable { - fn get_latest_eid(&self) -> u64; + fn get_latest_eid(&self) -> u32; fn get_last_entry_mut(&mut self) -> Option<&mut EventTableEntry>; fn push( &mut self, inst: InstructionTableEntry, - sp: u64, - allocated_memory_pages: usize, - last_jump_eid: u64, + sp: u32, + allocated_memory_pages: u32, + last_jump_eid: u32, step_info: StepInfo, ) -> EventTableEntry; } impl ETable for EventTable { - fn get_latest_eid(&self) -> u64 { + fn get_latest_eid(&self) -> u32 { self.entries().last().unwrap().eid } @@ -131,19 +131,19 @@ impl ETable for EventTable { fn push( &mut self, inst: InstructionTableEntry, - sp: u64, - allocated_memory_pages: usize, - last_jump_eid: u64, + sp: u32, + allocated_memory_pages: u32, + last_jump_eid: u32, step_info: StepInfo, ) -> EventTableEntry { - let sp = (DEFAULT_VALUE_STACK_LIMIT as u64) + let sp = (DEFAULT_VALUE_STACK_LIMIT as u32) .checked_sub(sp) .unwrap() .checked_sub(1) .unwrap(); let eentry = EventTableEntry { - eid: self.entries().len() as u64 + 1, + eid: (self.entries().len() + 1).try_into().unwrap(), sp, allocated_memory_pages, last_jump_eid, diff --git a/src/tracer/imtable.rs b/src/tracer/imtable.rs index 1152cdd7cc..97fe9bf6dd 100644 --- a/src/tracer/imtable.rs +++ b/src/tracer/imtable.rs @@ -22,7 +22,7 @@ impl Into for IMEntry { } else { LocationType::Heap }, - offset: self.offset as u64, + offset: self.offset, vtype: self.vtype, value: self.value, } @@ -48,7 +48,7 @@ impl IMTable { } else { LocationType::Heap }, - offset: offset as u64, + offset, vtype, value, }) diff --git a/src/tracer/mod.rs b/src/tracer/mod.rs index 8fa1fbe2e1..b27d7e88bf 100644 --- a/src/tracer/mod.rs +++ b/src/tracer/mod.rs @@ -28,7 +28,7 @@ pub mod imtable; #[derive(Debug)] pub struct FuncDesc { - pub index_within_jtable: u16, + pub index_within_jtable: u32, pub ftype: FunctionType, pub signature: Signature, } @@ -42,8 +42,8 @@ pub struct Tracer { pub elem_table: ElemTable, pub configure_table: ConfigureTable, type_of_func_ref: Vec<(FuncRef, u32)>, - function_lookup: Vec<(FuncRef, u16)>, - pub(crate) last_jump_eid: Vec, + function_lookup: Vec<(FuncRef, u32)>, + pub(crate) last_jump_eid: Vec, function_index_allocator: u32, pub(crate) function_index_translation: HashMap, pub host_function_index_lookup: HashMap, @@ -78,11 +78,11 @@ impl Tracer { self.last_jump_eid.pop().unwrap(); } - pub fn last_jump_eid(&self) -> u64 { + pub fn last_jump_eid(&self) -> u32 { *self.last_jump_eid.last().unwrap() } - pub fn eid(&self) -> u64 { + pub fn eid(&self) -> u32 { self.etable.get_latest_eid() } @@ -223,11 +223,11 @@ impl Tracer { }; self.function_lookup - .push((func.clone(), func_index_in_itable as u16)); + .push((func.clone(), func_index_in_itable)); self.function_index_translation.insert( func_index, FuncDesc { - index_within_jtable: func_index_in_itable as u16, + index_within_jtable: func_index_in_itable, ftype, signature: func.signature().clone(), }, @@ -254,7 +254,7 @@ impl Tracer { if let Some(instruction) = iter.next() { let _ = self.itable.push( funcdesc.index_within_jtable, - pc as u16, + pc, instruction.into(&self.function_index_translation), ); } else { @@ -271,7 +271,7 @@ impl Tracer { } } - pub fn lookup_function(&self, function: &FuncRef) -> u16 { + pub fn lookup_function(&self, function: &FuncRef) -> u32 { let pos = self .function_lookup .iter() @@ -284,7 +284,7 @@ impl Tracer { let function_idx = self.lookup_function(function); for ientry in self.itable.entries() { - if ientry.fid as u16 == function_idx && ientry.iid as u32 == pos { + if ientry.fid == function_idx && ientry.iid as u32 == pos { return ientry.clone(); } } @@ -296,7 +296,7 @@ impl Tracer { let function_idx = self.lookup_function(function); for ientry in self.itable.entries() { - if ientry.fid as u16 == function_idx { + if ientry.fid == function_idx { return ientry.clone(); } } From b434678b332e337ad73594372b67c3da5803fc1b Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Sat, 18 Mar 2023 12:04:38 +0000 Subject: [PATCH 096/129] unify imtable --- src/tracer/imtable.rs | 36 ++++++------------------------------ src/tracer/mod.rs | 16 +++++++++++++++- 2 files changed, 21 insertions(+), 31 deletions(-) diff --git a/src/tracer/imtable.rs b/src/tracer/imtable.rs index 97fe9bf6dd..2f7ea82113 100644 --- a/src/tracer/imtable.rs +++ b/src/tracer/imtable.rs @@ -3,32 +3,6 @@ use specs::{ mtable::{LocationType, VarType}, }; -#[derive(Debug, Clone)] -pub struct IMEntry { - pub is_global: bool, - pub is_mutable: bool, - pub module_instance_index: u16, - pub offset: u32, - pub vtype: VarType, - pub value: u64, -} - -impl Into for IMEntry { - fn into(self) -> InitMemoryTableEntry { - InitMemoryTableEntry { - is_mutable: self.is_mutable, - ltype: if self.is_global { - LocationType::Global - } else { - LocationType::Heap - }, - offset: self.offset, - vtype: self.vtype, - value: self.value, - } - } -} - #[derive(Debug, Default)] pub struct IMTable(Vec); @@ -37,7 +11,8 @@ impl IMTable { &mut self, is_global: bool, is_mutable: bool, - offset: u32, + start_offset: u32, + end_offset: u32, vtype: VarType, value: u64, ) { @@ -48,13 +23,14 @@ impl IMTable { } else { LocationType::Heap }, - offset, + start_offset, + end_offset, vtype, value, }) } - pub fn finalized(&self) -> InitMemoryTable { - InitMemoryTable::new(self.0.clone()) + pub fn finalized(&self, k: u32) -> InitMemoryTable { + InitMemoryTable::new(self.0.clone(), k) } } diff --git a/src/tracer/mod.rs b/src/tracer/mod.rs index b27d7e88bf..79442c8946 100644 --- a/src/tracer/mod.rs +++ b/src/tracer/mod.rs @@ -108,8 +108,21 @@ impl Tracer { let mut buf = [0u8; 8]; (*memref).get_into(i * 8, &mut buf).unwrap(); self.imtable - .push(false, true, i, VarType::I64, u64::from_le_bytes(buf)); + .push(false, true, i, i, VarType::I64, u64::from_le_bytes(buf)); } + + self.imtable.push( + false, + true, + pages * 8192, + memref + .limits() + .maximum() + .map(|limit| limit * 8192 - 1) + .unwrap_or(u32::MAX), + VarType::I64, + 0, + ); } pub(crate) fn push_global(&mut self, globalidx: u32, globalref: &GlobalRef) { @@ -119,6 +132,7 @@ impl Tracer { true, globalref.is_mutable(), globalidx, + globalidx, vtype, from_value_internal_to_u64_with_typ(vtype, ValueInternal::from(globalref.get())), ); From 023b9ba2355c71e634e913fd887f7603454df849 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Fri, 30 Jun 2023 15:19:06 +0800 Subject: [PATCH 097/129] fix: add index to distinguish between same functions --- src/func.rs | 11 ++++++----- src/module.rs | 8 ++++++-- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/func.rs b/src/func.rs index a17eaed23d..1f2b6342b5 100644 --- a/src/func.rs +++ b/src/func.rs @@ -55,6 +55,7 @@ pub(crate) enum FuncInstanceInternal { signature: Rc, module: Weak, body: Rc, + image_func_index: usize, }, Host { signature: Signature, @@ -67,16 +68,14 @@ impl PartialEq for FuncInstanceInternal { match (self, other) { ( Self::Internal { - signature: l_signature, - body: l_body, + image_func_index: l_image_func_index, .. }, Self::Internal { - signature: r_signature, - body: r_body, + image_func_index: r_image_func_index, .. }, - ) => l_signature == r_signature && l_body == r_body, + ) => l_image_func_index == r_image_func_index, ( Self::Host { signature: l_signature, @@ -144,11 +143,13 @@ impl FuncInstance { module: Weak, signature: Rc, body: FuncBody, + image_func_index: usize, ) -> FuncRef { let func = FuncInstanceInternal::Internal { signature, module, body: Rc::new(body), + image_func_index, }; FuncRef(Rc::new(FuncInstance(func))) } diff --git a/src/module.rs b/src/module.rs index a392ee38c4..d6eab23cd0 100644 --- a/src/module.rs +++ b/src/module.rs @@ -338,8 +338,12 @@ impl ModuleInstance { locals: body.locals().to_vec(), code, }; - let func_instance = - FuncInstance::alloc_internal(Rc::downgrade(&instance.0), signature, func_body); + let func_instance = FuncInstance::alloc_internal( + Rc::downgrade(&instance.0), + signature, + func_body, + index, + ); if let Some(tracer) = tracer.clone() { tracer From a6dc6e9c0c0e2cdf595aa31fe0f3d79e6b7ee7d6 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Mon, 24 Jul 2023 14:59:10 +0800 Subject: [PATCH 098/129] feat: perf: support phantom function to enhance performance --- src/lib.rs | 3 +- src/module.rs | 11 ++- src/runner.rs | 81 +++++++++++++++++----- src/tracer/mod.rs | 80 ++++++++++++++++++---- src/tracer/phantom.rs | 155 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 295 insertions(+), 35 deletions(-) create mode 100644 src/tracer/phantom.rs diff --git a/src/lib.rs b/src/lib.rs index f3679d58c1..b4183e2025 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -269,6 +269,7 @@ mod prepare; mod runner; mod table; mod types; + /// Tracer lib for zkWasm pub mod tracer; @@ -454,7 +455,7 @@ impl Module { Module::from_parity_wasm_module(module) } - pub(crate) fn module(&self) -> &parity_wasm::elements::Module { + pub fn module(&self) -> &parity_wasm::elements::Module { &self.module } diff --git a/src/module.rs b/src/module.rs index d6eab23cd0..f600611824 100644 --- a/src/module.rs +++ b/src/module.rs @@ -285,6 +285,12 @@ impl ModuleInstance { import.field(), ))); } + + if import.field() == "wasm_input" { + if let Some(tracer) = tracer.clone() { + tracer.borrow_mut().wasm_input_func_ref = Some(func.clone()); + } + } instance.push_func(func.clone()) } (&External::Table(ref tt), &ExternVal::Table(ref table)) => { @@ -739,7 +745,7 @@ impl ModuleInstance { .map_err(Error::Trap) } - fn func_by_name(&self, func_name: &str) -> Result { + pub fn func_by_name(&self, func_name: &str) -> Result { let extern_val = self .export_by_name(func_name) .ok_or_else(|| Error::Function(format!("Module doesn't have export {}", func_name)))?; @@ -825,8 +831,7 @@ impl<'a> NotStartedModuleRef<'a> { tracer: Rc>, ) -> Result { { - let mut tracer = tracer.borrow_mut(); - tracer.last_jump_eid.push(0); + tracer.borrow_mut().last_jump_eid.push(0); } if let Some(start_fn_idx) = self.loaded_module.module().start_section() { diff --git a/src/runner.rs b/src/runner.rs index c183b7be4c..8cfc68afba 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -199,6 +199,7 @@ pub struct Interpreter { state: InterpreterState, scratch: Vec, pub(crate) tracer: Option>>, + mask_tracer: Vec, } impl Interpreter { @@ -230,9 +231,18 @@ impl Interpreter { state: InterpreterState::Initialized, scratch: Vec::new(), tracer: None, + mask_tracer: vec![], }) } + fn get_tracer_if_active(&self) -> Option>> { + if self.tracer.is_some() && self.mask_tracer.is_empty() { + self.tracer.clone() + } else { + None + } + } + pub fn state(&self) -> &InterpreterState { &self.state } @@ -329,11 +339,10 @@ impl Interpreter { FuncInstanceInternal::Internal { .. } => { let nested_context = FunctionContext::new(nested_func.clone()); - if let Some(tracer) = self.tracer.clone() { - let callee_fid = - tracer.clone().borrow().lookup_function(&nested_func); + if let Some(tracer) = self.get_tracer_if_active() { + let mut tracer = tracer.borrow_mut(); + let callee_fid = tracer.lookup_function(&nested_func); - let mut tracer = (*tracer).borrow_mut(); let eid = tracer.eid(); let last_jump_eid = tracer.last_jump_eid(); @@ -352,6 +361,15 @@ impl Interpreter { tracer.push_frame(); } + if let Some(tracer) = self.tracer.clone() { + if tracer + .borrow() + .is_phantom_function(&nested_context.function) + { + self.mask_tracer.push(self.value_stack.sp as u32); + } + } + self.call_stack.push(function_context); self.call_stack.push(nested_context); } @@ -394,7 +412,7 @@ impl Interpreter { } if let Some(return_val) = return_val { - if let Some(tracer) = self.tracer.clone() { + if let Some(tracer) = self.get_tracer_if_active() { let mut tracer = (*tracer).borrow_mut(); let entry = tracer.etable.get_last_entry_mut().unwrap(); @@ -971,7 +989,6 @@ impl Interpreter { } else { vec![] }, - drop_values: drop_values.iter().map(|v| v.0).collect::>(), keep_values: match keep { Keep::Single(t) => vec![from_value_internal_to_u64_with_typ( t.into(), @@ -1908,7 +1925,6 @@ impl Interpreter { instructions: &isa::Instructions, ) -> Result { let mut iter = instructions.iterate_from(function_context.position); - loop { let pc = iter.position(); let sp = self.value_stack.sp; @@ -1919,11 +1935,9 @@ impl Interpreter { return or an implicit block `end`.", ); - let pre_status = if self.tracer.is_some() { + let pre_status = self.get_tracer_if_active().map_or(None, |_| { self.run_instruction_pre(function_context, &instruction) - } else { - None - }; + }); let current_memory = { function_context @@ -1932,12 +1946,12 @@ impl Interpreter { }; macro_rules! trace_post { - () => { - if let Some(tracer) = self.tracer.clone() { + () => {{ + if let Some(tracer) = self.get_tracer_if_active() { let post_status = self.run_instruction_post(pre_status, function_context, &instruction); - let mut tracer = (*tracer).borrow_mut(); + let mut tracer = tracer.borrow_mut(); let instruction = { instruction.into(&tracer.function_index_translation) }; @@ -1959,7 +1973,7 @@ impl Interpreter { post_status, ); } - }; + }}; } match self.run_instruction(function_context, &instruction)? { @@ -1980,8 +1994,43 @@ impl Interpreter { } InstructionOutcome::Return(drop_keep) => { trace_post!(); + if let Some(tracer) = self.tracer.clone() { - (*tracer).borrow_mut().pop_frame(); + if tracer + .borrow() + .is_phantom_function(&function_context.function) + { + let sp_before = self.mask_tracer.pop().unwrap(); + + if self.mask_tracer.is_empty() { + let last_jump_eid = tracer.borrow().last_jump_eid(); + let callee_fid = + tracer.borrow().lookup_function(&function_context.function); + let wasm_input_function_idx = + tracer.borrow().wasm_input_func_idx.unwrap(); + + tracer.borrow_mut().fill_trace( + sp_before, + current_memory as u32, + last_jump_eid, + callee_fid, + function_context.function.signature(), + wasm_input_function_idx, + if let isa::Keep::Single(t) = drop_keep.keep { + Some(from_value_internal_to_u64_with_typ( + t.into(), + *self.value_stack.top(), + )) + } else { + None + }, + ); + } + } + } + + if let Some(tracer) = self.get_tracer_if_active() { + tracer.borrow_mut().pop_frame(); } self.value_stack.drop_keep(drop_keep); diff --git a/src/tracer/mod.rs b/src/tracer/mod.rs index 79442c8946..57c02593d8 100644 --- a/src/tracer/mod.rs +++ b/src/tracer/mod.rs @@ -21,10 +21,11 @@ use crate::{ Signature, }; -use self::{etable::ETable, imtable::IMTable}; +use self::{etable::ETable, imtable::IMTable, phantom::PhantomFunction}; pub mod etable; pub mod imtable; +pub mod phantom; #[derive(Debug)] pub struct FuncDesc { @@ -48,11 +49,19 @@ pub struct Tracer { pub(crate) function_index_translation: HashMap, pub host_function_index_lookup: HashMap, pub static_jtable_entries: Vec, + pub phantom_functions: Vec, + pub phantom_functions_ref: Vec, + // Wasm Image Function Idx + pub wasm_input_func_idx: Option, + pub wasm_input_func_ref: Option, } impl Tracer { /// Create an empty tracer - pub fn new(host_plugin_lookup: HashMap) -> Self { + pub fn new( + host_plugin_lookup: HashMap, + phantom_functions: &Vec, + ) -> Self { Tracer { itable: InstructionTable::default(), imtable: IMTable::default(), @@ -67,6 +76,10 @@ impl Tracer { function_index_translation: Default::default(), host_function_index_lookup: host_plugin_lookup, static_jtable_entries: vec![], + phantom_functions: phantom_functions.clone(), + phantom_functions_ref: vec![], + wasm_input_func_ref: None, + wasm_input_func_idx: None, } } @@ -199,6 +212,10 @@ impl Tracer { loop { if let Some(func) = module_instance.func_by_index(func_index) { + if Some(&func) == self.wasm_input_func_ref.as_ref() { + self.wasm_input_func_idx = Some(func_index) + } + let func_index_in_itable = if Some(func_index) == start_fn_idx { 0 } else { @@ -253,6 +270,16 @@ impl Tracer { } } + { + let phantom_functions_ref = self.phantom_functions.clone(); + + for func_name in phantom_functions_ref { + let func = module_instance.func_by_name(&func_name).unwrap(); + + self.push_phantom_function(func); + } + } + { let mut func_index = 0; @@ -260,19 +287,34 @@ impl Tracer { if let Some(func) = module_instance.func_by_index(func_index) { let funcdesc = self.function_index_translation.get(&func_index).unwrap(); - if let Some(body) = func.body() { - let code = &body.code; - let mut iter = code.iterate_from(0); - loop { - let pc = iter.position(); - if let Some(instruction) = iter.next() { - let _ = self.itable.push( - funcdesc.index_within_jtable, - pc, - instruction.into(&self.function_index_translation), - ); - } else { - break; + if self.is_phantom_function(&func) { + let instructions = PhantomFunction::build_phantom_function_instructions( + &funcdesc.signature, + self.wasm_input_func_idx.unwrap(), + ); + + for (iid, inst) in instructions.into_iter().enumerate() { + self.itable.push( + funcdesc.index_within_jtable, + iid as u32, + inst.into(&self.function_index_translation), + ) + } + } else { + if let Some(body) = func.body() { + let code = &body.code; + let mut iter = code.iterate_from(0); + loop { + let pc = iter.position(); + if let Some(instruction) = iter.next() { + let _ = self.itable.push( + funcdesc.index_within_jtable, + pc, + instruction.into(&self.function_index_translation), + ); + } else { + break; + } } } } @@ -317,4 +359,12 @@ impl Tracer { unreachable!(); } + + pub fn push_phantom_function(&mut self, function: FuncRef) { + self.phantom_functions_ref.push(function) + } + + pub fn is_phantom_function(&self, func: &FuncRef) -> bool { + self.phantom_functions_ref.contains(func) + } } diff --git a/src/tracer/phantom.rs b/src/tracer/phantom.rs new file mode 100644 index 0000000000..c4142c6821 --- /dev/null +++ b/src/tracer/phantom.rs @@ -0,0 +1,155 @@ +use specs::{ + host_function::HostPlugin, + itable::InstructionTableEntry, + step::StepInfo, + types::ValueType, +}; + +use super::{etable::ETable, Tracer}; +use crate::{ + isa::{DropKeep, Instruction, Keep}, + Signature, +}; + +pub struct PhantomFunction; + +impl PhantomFunction { + pub fn build_phantom_function_instructions( + sig: &Signature, + // Wasm Image Function Id + wasm_input_function_idx: u32, + ) -> Vec> { + let mut instructions = vec![]; + + if sig.return_type().is_some() { + instructions.push(Instruction::I32Const(0)); + + instructions.push(Instruction::Call(wasm_input_function_idx)); + + if sig.return_type() != Some(wasmi_core::ValueType::I64) { + instructions.push(Instruction::I32WrapI64); + } + } + + instructions.push(Instruction::Return(DropKeep { + drop: sig.params().len() as u32, + keep: if let Some(t) = sig.return_type() { + Keep::Single(t.into_elements()) + } else { + Keep::None + }, + })); + + instructions + } +} + +impl Tracer { + pub fn fill_trace( + &mut self, + current_sp: u32, + allocated_memory_pages: u32, + last_jump_eid: u32, + fid: u32, + callee_sig: &Signature, + // Wasm Image Function Id + wasm_input_function_idx: u32, + keep_value: Option, + ) { + let mut inst = PhantomFunction::build_phantom_function_instructions( + &callee_sig, + wasm_input_function_idx, + ) + .into_iter(); + let mut iid = 0; + + let has_return_value = callee_sig.return_type().is_some(); + let wasm_input_host_function_ref = self.wasm_input_func_ref.clone().unwrap(); + let wasm_input_host_func_index = match wasm_input_host_function_ref.as_internal() { + crate::func::FuncInstanceInternal::Internal { .. } => unreachable!(), + crate::func::FuncInstanceInternal::Host { + host_func_index, .. + } => host_func_index, + }; + + if has_return_value { + self.etable.push( + InstructionTableEntry { + fid, + iid, + opcode: inst.next().unwrap().into(&self.function_index_translation), + }, + current_sp, + allocated_memory_pages, + last_jump_eid, + StepInfo::I32Const { value: 0 }, + ); + + iid += 1; + + self.etable.push( + InstructionTableEntry { + fid, + iid, + opcode: inst.next().unwrap().into(&self.function_index_translation), + }, + current_sp + 1, + allocated_memory_pages, + last_jump_eid, + StepInfo::CallHost { + plugin: HostPlugin::HostInput, + host_function_idx: *wasm_input_host_func_index, + function_name: "wasm_input".to_owned(), + signature: specs::host_function::Signature { + params: vec![ValueType::I32], + return_type: Some(ValueType::I64), + }, + args: vec![0], + ret_val: Some(keep_value.unwrap()), + op_index_in_plugin: 0, + }, + ); + + iid += 1; + + if callee_sig.return_type() != Some(wasmi_core::ValueType::I64) { + self.etable.push( + InstructionTableEntry { + fid, + iid, + opcode: inst.next().unwrap().into(&self.function_index_translation), + }, + current_sp + 1, + allocated_memory_pages, + last_jump_eid, + StepInfo::I32WrapI64 { + value: keep_value.unwrap() as i64, + result: keep_value.unwrap() as i32, + }, + ); + + iid += 1; + } + } + + self.etable.push( + InstructionTableEntry { + fid, + iid, + opcode: inst.next().unwrap().into(&self.function_index_translation), + }, + current_sp + has_return_value as u32, + allocated_memory_pages, + last_jump_eid, + StepInfo::Return { + drop: callee_sig.params().len() as u32, + keep: if let Some(t) = callee_sig.return_type() { + vec![t.into_elements().into()] + } else { + vec![] + }, + keep_values: keep_value.map_or(vec![], |v| vec![v]), + }, + ); + } +} From fa91eb0b34ad0635254c8b4b2e79eae9e4ec794a Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Thu, 3 Aug 2023 00:17:10 +0800 Subject: [PATCH 099/129] chore: adapt zkwasm --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index d653b0851e..63cfb8e65e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,7 @@ exclude = [ "/res/*", "/tests/*", "/fuzz/*", "/benches/*" ] wasmi_core = { version = "0.1", path = "core", default-features = false } validation = { package = "wasmi-validation", version = "0.4", path = "validation", default-features = false } parity-wasm = { version = "0.42.0", default-features = false } -specs = { path = "../specs" } +specs = { path = "../../crates/specs" } [dev-dependencies] assert_matches = "1.5" From e844381d080b4f9c0ae22bacf4d7061c84b82e5e Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Wed, 6 Sep 2023 23:16:30 +0800 Subject: [PATCH 100/129] feat: support ext-sign feature --- Cargo.toml | 2 +- core/Cargo.toml | 2 +- src/isa.rs | 38 ++++++++++++++++++++++ src/prepare/compile.rs | 19 ++++++++++- src/runner.rs | 71 ++++++++++++++++++++++++++++++++++++++++++ src/tracer/etable.rs | 15 +++++++++ validation/Cargo.toml | 2 +- validation/src/func.rs | 27 +++++++++++++++- 8 files changed, 171 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 63cfb8e65e..ab5bdd2ba7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ exclude = [ "/res/*", "/tests/*", "/fuzz/*", "/benches/*" ] [dependencies] wasmi_core = { version = "0.1", path = "core", default-features = false } validation = { package = "wasmi-validation", version = "0.4", path = "validation", default-features = false } -parity-wasm = { version = "0.42.0", default-features = false } +parity-wasm = { version = "0.42.0", features = ["sign_ext"] } specs = { path = "../../crates/specs" } [dev-dependencies] diff --git a/core/Cargo.toml b/core/Cargo.toml index af263bfe1e..5d23498c6f 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -11,7 +11,7 @@ description = "WebAssembly interpreter" keywords = ["wasm", "webassembly", "bytecode", "interpreter"] [dependencies] -parity-wasm = { version = "0.42.0", default-features = false } +parity-wasm = { version = "0.42.0", features = ["sign_ext"] } memory_units = "0.4.0" libm = "0.2.1" num-rational = { version = "0.4", default-features = false, features = ["num-bigint"] } diff --git a/src/isa.rs b/src/isa.rs index 4104912609..cb0400d3e4 100644 --- a/src/isa.rs +++ b/src/isa.rs @@ -348,6 +348,12 @@ pub enum Instruction<'a> { I64ReinterpretF64, F32ReinterpretI32, F64ReinterpretI64, + + I32Extend8S, + I32Extend16S, + I64Extend8S, + I64Extend16S, + I64Extend32S, } impl<'a> From> for UnaryOp { @@ -879,6 +885,21 @@ impl<'a> Instruction<'a> { Instruction::I64ReinterpretF64 => todo!(), Instruction::F32ReinterpretI32 => todo!(), Instruction::F64ReinterpretI64 => todo!(), + Instruction::I32Extend8S => Opcode::Conversion { + class: ConversionOp::I32Extend8S, + }, + Instruction::I32Extend16S => Opcode::Conversion { + class: ConversionOp::I32Extend16S, + }, + Instruction::I64Extend8S => Opcode::Conversion { + class: ConversionOp::I64Extend8S, + }, + Instruction::I64Extend16S => Opcode::Conversion { + class: ConversionOp::I64Extend16S, + }, + Instruction::I64Extend32S => Opcode::Conversion { + class: ConversionOp::I64Extend32S, + }, } } } @@ -1054,6 +1075,11 @@ impl<'a> Into for Instruction<'a> { Instruction::I64ReinterpretF64 => 164, Instruction::F32ReinterpretI32 => 165, Instruction::F64ReinterpretI64 => 166, + Instruction::I32Extend8S => 167, + Instruction::I32Extend16S => 168, + Instruction::I64Extend8S => 169, + Instruction::I64Extend16S => 170, + Instruction::I64Extend32S => 171, } } } @@ -1252,6 +1278,12 @@ pub(crate) enum InstructionInternal { I64ReinterpretF64, F32ReinterpretI32, F64ReinterpretI64, + + I32Extend8S, + I32Extend16S, + I64Extend8S, + I64Extend16S, + I64Extend32S, } #[derive(Debug, Clone, PartialEq)] @@ -1508,6 +1540,12 @@ impl<'a> Iterator for InstructionIter<'a> { InstructionInternal::I64ReinterpretF64 => Instruction::I64ReinterpretF64, InstructionInternal::F32ReinterpretI32 => Instruction::F32ReinterpretI32, InstructionInternal::F64ReinterpretI64 => Instruction::F64ReinterpretI64, + + InstructionInternal::I32Extend8S => Instruction::I32Extend8S, + InstructionInternal::I32Extend16S => Instruction::I32Extend16S, + InstructionInternal::I64Extend8S => Instruction::I64Extend8S, + InstructionInternal::I64Extend16S => Instruction::I64Extend16S, + InstructionInternal::I64Extend32S => Instruction::I64Extend32S, }; self.position += 1; diff --git a/src/prepare/compile.rs b/src/prepare/compile.rs index 0cac67a956..52ef4f4707 100644 --- a/src/prepare/compile.rs +++ b/src/prepare/compile.rs @@ -1,6 +1,6 @@ use alloc::{string::String, vec::Vec}; -use parity_wasm::elements::{BlockType, FuncBody, Instruction, ValueType}; +use parity_wasm::elements::{BlockType, FuncBody, Instruction, SignExtInstruction, ValueType}; use crate::isa::{self, InstructionInternal}; use validation::{ @@ -998,6 +998,23 @@ impl Compiler { context.step(instruction)?; self.sink.emit(isa::InstructionInternal::F64ReinterpretI64); } + SignExt(ref ext) => match ext { + SignExtInstruction::I32Extend8S => { + self.sink.emit(isa::InstructionInternal::I32Extend8S); + } + SignExtInstruction::I32Extend16S => { + self.sink.emit(isa::InstructionInternal::I32Extend16S); + } + SignExtInstruction::I64Extend8S => { + self.sink.emit(isa::InstructionInternal::I64Extend8S); + } + SignExtInstruction::I64Extend16S => { + self.sink.emit(isa::InstructionInternal::I64Extend16S); + } + SignExtInstruction::I64Extend32S => { + self.sink.emit(isa::InstructionInternal::I64Extend32S); + } + }, _ => { context.step(instruction)?; } diff --git a/src/runner.rs b/src/runner.rs index 8cfc68afba..bf09510c78 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -815,6 +815,21 @@ impl Interpreter { value: <_>::from_value_internal(*self.value_stack.pick(1)), sign: true, }), + isa::Instruction::I32Extend8S => Some(RunInstructionTracePre::I32SignExtendI8 { + value: <_>::from_value_internal(*self.value_stack.pick(1)), + }), + isa::Instruction::I32Extend16S => Some(RunInstructionTracePre::I32SignExtendI16 { + value: <_>::from_value_internal(*self.value_stack.pick(1)), + }), + isa::Instruction::I64Extend8S => Some(RunInstructionTracePre::I64SignExtendI8 { + value: <_>::from_value_internal(*self.value_stack.pick(1)), + }), + isa::Instruction::I64Extend16S => Some(RunInstructionTracePre::I64SignExtendI16 { + value: <_>::from_value_internal(*self.value_stack.pick(1)), + }), + isa::Instruction::I64Extend32S => Some(RunInstructionTracePre::I64SignExtendI32 { + value: <_>::from_value_internal(*self.value_stack.pick(1)), + }), _ => { println!("{:?}", *instructions); @@ -1911,6 +1926,56 @@ impl Interpreter { unreachable!() } } + isa::Instruction::I32Extend8S => { + if let RunInstructionTracePre::I32SignExtendI8 { value } = pre_status.unwrap() { + StepInfo::I32SignExtendI8 { + value, + result: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } + isa::Instruction::I32Extend16S => { + if let RunInstructionTracePre::I32SignExtendI16 { value } = pre_status.unwrap() { + StepInfo::I32SignExtendI16 { + value, + result: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } + isa::Instruction::I64Extend8S => { + if let RunInstructionTracePre::I64SignExtendI8 { value } = pre_status.unwrap() { + StepInfo::I64SignExtendI8 { + value, + result: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } + isa::Instruction::I64Extend16S => { + if let RunInstructionTracePre::I64SignExtendI16 { value } = pre_status.unwrap() { + StepInfo::I64SignExtendI16 { + value, + result: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } + isa::Instruction::I64Extend32S => { + if let RunInstructionTracePre::I64SignExtendI32 { value } = pre_status.unwrap() { + StepInfo::I64SignExtendI32 { + value, + result: <_>::from_value_internal(*self.value_stack.top()), + } + } else { + unreachable!() + } + } _ => { println!("{:?}", instructions); @@ -2260,6 +2325,12 @@ impl Interpreter { isa::Instruction::I64ReinterpretF64 => self.run_reinterpret::(), isa::Instruction::F32ReinterpretI32 => self.run_reinterpret::(), isa::Instruction::F64ReinterpretI64 => self.run_reinterpret::(), + + isa::Instruction::I32Extend8S => self.run_extend::(), + isa::Instruction::I32Extend16S => self.run_extend::(), + isa::Instruction::I64Extend8S => self.run_extend::(), + isa::Instruction::I64Extend16S => self.run_extend::(), + isa::Instruction::I64Extend32S => self.run_extend::(), } } diff --git a/src/tracer/etable.rs b/src/tracer/etable.rs index da32b444bd..58e94a8525 100644 --- a/src/tracer/etable.rs +++ b/src/tracer/etable.rs @@ -90,6 +90,21 @@ pub enum RunInstructionTracePre { value: i32, sign: bool, }, + I32SignExtendI8 { + value: i32, + }, + I32SignExtendI16 { + value: i32, + }, + I64SignExtendI8 { + value: i64, + }, + I64SignExtendI16 { + value: i64, + }, + I64SignExtendI32 { + value: i64, + }, UnaryOp { operand: u64, diff --git a/validation/Cargo.toml b/validation/Cargo.toml index 1ed24b217b..fcb039799b 100644 --- a/validation/Cargo.toml +++ b/validation/Cargo.toml @@ -8,7 +8,7 @@ repository = "https://github.com/paritytech/wasmi" description = "Wasm code validator" [dependencies] -parity-wasm = { version = "0.42.0", default-features = false } +parity-wasm = { version = "0.42.0", features = ["sign_ext"] } [dev-dependencies] assert_matches = "1.1" diff --git a/validation/src/func.rs b/validation/src/func.rs index 7553401685..d193422ae6 100644 --- a/validation/src/func.rs +++ b/validation/src/func.rs @@ -9,7 +9,15 @@ use crate::{ }; use core::u32; -use parity_wasm::elements::{BlockType, Func, FuncBody, Instruction, TableElementType, ValueType}; +use parity_wasm::elements::{ + BlockType, + Func, + FuncBody, + Instruction, + SignExtInstruction, + TableElementType, + ValueType, +}; /// Maximum number of entries in value stack per function. const DEFAULT_VALUE_STACK_LIMIT: usize = 16384; @@ -784,6 +792,23 @@ impl<'a> FunctionValidationContext<'a> { F64ReinterpretI64 => { self.validate_cvtop(ValueType::I64, ValueType::F64)?; } + SignExt(ref ext) => match ext { + SignExtInstruction::I32Extend8S => { + self.validate_cvtop(ValueType::I32, ValueType::I32)? + } + SignExtInstruction::I32Extend16S => { + self.validate_cvtop(ValueType::I32, ValueType::I32)? + } + SignExtInstruction::I64Extend8S => { + self.validate_cvtop(ValueType::I64, ValueType::I64)? + } + SignExtInstruction::I64Extend16S => { + self.validate_cvtop(ValueType::I64, ValueType::I64)? + } + SignExtInstruction::I64Extend32S => { + self.validate_cvtop(ValueType::I64, ValueType::I64)? + } + }, } Ok(()) From 9a136cb445951fff3be27bccb4241a69ff0c12f3 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Tue, 19 Sep 2023 13:41:53 +0800 Subject: [PATCH 101/129] bugfix: create matched value stack with DEFAULT_VALUE_STACK_LIMIT --- src/runner.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/runner.rs b/src/runner.rs index bf09510c78..ca11f1e654 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -42,11 +42,13 @@ use std::rc::Rc; use validation::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX}; /// Maximum number of bytes on the value stack. -/// wasmi's default value is 1024 * 1024, we set 4096 to adapt zkWasm +/// wasmi's default value is 1024 * 1024, +/// ZKWASM: Maximum number of entries on the value stack. +/// we set 4096 to adapt zkWasm pub const DEFAULT_VALUE_STACK_LIMIT: usize = 4096; /// Maximum number of levels on the call stack. -pub const DEFAULT_CALL_STACK_LIMIT: usize = 64 * 1024; +pub const DEFAULT_CALL_STACK_LIMIT: usize = 128 * 1024; /// This is a wrapper around u64 to allow us to treat runtime values as a tag-free `u64` /// (where if the runtime value is <64 bits the upper bits are 0). This is safe, since @@ -3251,7 +3253,7 @@ pub struct StackRecycler { impl StackRecycler { /// Limit stacks created by this recycler to - /// - `value_stack_limit` bytes for values and + /// - `value_stack_limit` entries for values and /// - `call_stack_limit` levels for calls. pub fn with_limits(value_stack_limit: usize, call_stack_limit: usize) -> Self { Self { @@ -3281,8 +3283,7 @@ impl StackRecycler { fn recreate_value_stack(this: &mut Option<&mut Self>) -> ValueStack { let limit = this .as_ref() - .map_or(DEFAULT_VALUE_STACK_LIMIT, |this| this.value_stack_limit) - / ::core::mem::size_of::(); + .map_or(DEFAULT_VALUE_STACK_LIMIT, |this| this.value_stack_limit); let buf = this .as_mut() From 21875f71194c461596dd121c459b004f14289c89 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Wed, 15 Nov 2023 16:07:03 +0800 Subject: [PATCH 102/129] feat: support regex for phantom function --- Cargo.toml | 1 + src/module.rs | 2 +- src/tracer/mod.rs | 13 +++++++++---- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ab5bdd2ba7..38c2921d36 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ exclude = [ "/res/*", "/tests/*", "/fuzz/*", "/benches/*" ] wasmi_core = { version = "0.1", path = "core", default-features = false } validation = { package = "wasmi-validation", version = "0.4", path = "validation", default-features = false } parity-wasm = { version = "0.42.0", features = ["sign_ext"] } +regex = "1.10.2" specs = { path = "../../crates/specs" } [dev-dependencies] diff --git a/src/module.rs b/src/module.rs index f600611824..6a514c144b 100644 --- a/src/module.rs +++ b/src/module.rs @@ -172,7 +172,7 @@ pub struct ModuleInstance { funcs: RefCell>, memories: RefCell>, globals: RefCell>, - exports: RefCell>, + pub(crate) exports: RefCell>, } impl ModuleInstance { diff --git a/src/tracer/mod.rs b/src/tracer/mod.rs index 57c02593d8..ef315c0a56 100644 --- a/src/tracer/mod.rs +++ b/src/tracer/mod.rs @@ -1,5 +1,6 @@ use std::collections::HashMap; +use regex::Regex; use specs::{ brtable::{ElemEntry, ElemTable}, configure_table::ConfigureTable, @@ -271,12 +272,16 @@ impl Tracer { } { - let phantom_functions_ref = self.phantom_functions.clone(); + let phantom_functions = self.phantom_functions.clone(); - for func_name in phantom_functions_ref { - let func = module_instance.func_by_name(&func_name).unwrap(); + for func_name_regex in phantom_functions { + let re = Regex::new(&func_name_regex).unwrap(); - self.push_phantom_function(func); + for (export_name, export) in module_instance.exports.borrow().iter() { + if re.is_match(export_name) && export.as_func().is_some() { + self.push_phantom_function(export.as_func().unwrap().clone()); + } + } } } From 126160abf8a99112976b908862417df14e8c4f8b Mon Sep 17 00:00:00 2001 From: cwbhhjl Date: Thu, 16 Nov 2023 21:51:07 +0800 Subject: [PATCH 103/129] trace counter --- src/runner.rs | 15 +++++++++++++-- src/tracer/mod.rs | 18 ++++++++++++++++++ src/tracer/phantom.rs | 15 ++++++++++++++- 3 files changed, 45 insertions(+), 3 deletions(-) diff --git a/src/runner.rs b/src/runner.rs index ca11f1e654..7e6c59647e 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -238,13 +238,23 @@ impl Interpreter { } fn get_tracer_if_active(&self) -> Option>> { - if self.tracer.is_some() && self.mask_tracer.is_empty() { - self.tracer.clone() + if let Some(tracer) = &self.tracer { + if !tracer.borrow().only_count() && self.mask_tracer.is_empty() { + self.tracer.clone() + } else { + None + } } else { None } } + fn tracer_count(&self) { + if let Some(tracer) = &self.tracer { + tracer.borrow_mut().count(); + } + } + pub fn state(&self) -> &InterpreterState { &self.state } @@ -2014,6 +2024,7 @@ impl Interpreter { macro_rules! trace_post { () => {{ + self.tracer_count(); if let Some(tracer) = self.get_tracer_if_active() { let post_status = self.run_instruction_post(pre_status, function_context, &instruction); diff --git a/src/tracer/mod.rs b/src/tracer/mod.rs index 57c02593d8..7f0efd20c3 100644 --- a/src/tracer/mod.rs +++ b/src/tracer/mod.rs @@ -54,6 +54,8 @@ pub struct Tracer { // Wasm Image Function Idx pub wasm_input_func_idx: Option, pub wasm_input_func_ref: Option, + only_counter: bool, + counter: usize, } impl Tracer { @@ -61,6 +63,7 @@ impl Tracer { pub fn new( host_plugin_lookup: HashMap, phantom_functions: &Vec, + only_counter: bool, ) -> Self { Tracer { itable: InstructionTable::default(), @@ -80,6 +83,8 @@ impl Tracer { phantom_functions_ref: vec![], wasm_input_func_ref: None, wasm_input_func_idx: None, + only_counter, + counter: 0, } } @@ -111,6 +116,19 @@ impl Tracer { .unwrap() .clone() } + + pub fn count(&mut self) -> bool { + self.counter += 1; + self.only_counter + } + + pub fn only_count(&self) -> bool { + self.only_counter + } + + pub fn get_trace_count(&self) -> usize { + self.counter + } } impl Tracer { diff --git a/src/tracer/phantom.rs b/src/tracer/phantom.rs index c4142c6821..4bf3c16b6f 100644 --- a/src/tracer/phantom.rs +++ b/src/tracer/phantom.rs @@ -56,6 +56,20 @@ impl Tracer { wasm_input_function_idx: u32, keep_value: Option, ) { + let has_return_value = callee_sig.return_type().is_some(); + + if self.only_count() { + if has_return_value { + self.count(); + self.count(); + if callee_sig.return_type() != Some(wasmi_core::ValueType::I64) { + self.count(); + } + } + self.count(); + return; + } + let mut inst = PhantomFunction::build_phantom_function_instructions( &callee_sig, wasm_input_function_idx, @@ -63,7 +77,6 @@ impl Tracer { .into_iter(); let mut iid = 0; - let has_return_value = callee_sig.return_type().is_some(); let wasm_input_host_function_ref = self.wasm_input_func_ref.clone().unwrap(); let wasm_input_host_func_index = match wasm_input_host_function_ref.as_internal() { crate::func::FuncInstanceInternal::Internal { .. } => unreachable!(), From 3dba40c2a5d7261c47c99d87213c80638fafa134 Mon Sep 17 00:00:00 2001 From: cwbhhjl Date: Thu, 16 Nov 2023 22:51:02 +0800 Subject: [PATCH 104/129] fix phantom --- src/runner.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/runner.rs b/src/runner.rs index 7e6c59647e..9049acd493 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -250,6 +250,9 @@ impl Interpreter { } fn tracer_count(&self) { + if self.mask_tracer.is_empty() { + return; + } if let Some(tracer) = &self.tracer { tracer.borrow_mut().count(); } From 8c0d7ec9625ad6d411f4bac25c3073bcc9daab50 Mon Sep 17 00:00:00 2001 From: cwbhhjl Date: Thu, 16 Nov 2023 22:56:45 +0800 Subject: [PATCH 105/129] fix phantom --- src/runner.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runner.rs b/src/runner.rs index 9049acd493..f375827153 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -250,7 +250,7 @@ impl Interpreter { } fn tracer_count(&self) { - if self.mask_tracer.is_empty() { + if !self.mask_tracer.is_empty() { return; } if let Some(tracer) = &self.tracer { From 7b1f8a5547674d0a84f33eb67999fff737da230d Mon Sep 17 00:00:00 2001 From: cwbhhjl Date: Thu, 23 Nov 2023 16:06:27 +0800 Subject: [PATCH 106/129] trace count --- src/tracer/mod.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/tracer/mod.rs b/src/tracer/mod.rs index 7f0efd20c3..a335ebc376 100644 --- a/src/tracer/mod.rs +++ b/src/tracer/mod.rs @@ -117,9 +117,8 @@ impl Tracer { .clone() } - pub fn count(&mut self) -> bool { + pub fn count(&mut self) { self.counter += 1; - self.only_counter } pub fn only_count(&self) -> bool { From 73361e53f2243b95f6f85d36d3365d579ed7b960 Mon Sep 17 00:00:00 2001 From: cwbhhjl Date: Thu, 23 Nov 2023 16:06:30 +0800 Subject: [PATCH 107/129] fmt --- src/prepare/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/prepare/tests.rs b/src/prepare/tests.rs index 5ba1c3d5ea..7e3c5b0c50 100644 --- a/src/prepare/tests.rs +++ b/src/prepare/tests.rs @@ -282,7 +282,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(ValueType::I32), // 1 result }), isa::Instruction::I32Const(3), From 91048a6e73a5aa24d1700b22a810b0c7f42554fe Mon Sep 17 00:00:00 2001 From: cwbhhjl Date: Thu, 23 Nov 2023 16:21:09 +0800 Subject: [PATCH 108/129] code compatibility --- src/tracer/mod.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/tracer/mod.rs b/src/tracer/mod.rs index a335ebc376..be0359cbf2 100644 --- a/src/tracer/mod.rs +++ b/src/tracer/mod.rs @@ -63,6 +63,13 @@ impl Tracer { pub fn new( host_plugin_lookup: HashMap, phantom_functions: &Vec, + ) -> Self { + Self::new_with_counter(host_plugin_lookup, phantom_functions, false) + } + + pub fn new_with_counter( + host_plugin_lookup: HashMap, + phantom_functions: &Vec, only_counter: bool, ) -> Self { Tracer { From 7ca4830439bbcec8435cee84a46d02132c1b98e9 Mon Sep 17 00:00:00 2001 From: cwbhhjl Date: Mon, 27 Nov 2023 17:11:36 +0800 Subject: [PATCH 109/129] rename --- src/runner.rs | 8 ++++---- src/tracer/mod.rs | 19 ++++++------------- src/tracer/phantom.rs | 10 +++++----- 3 files changed, 15 insertions(+), 22 deletions(-) diff --git a/src/runner.rs b/src/runner.rs index f375827153..124b26eafd 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -239,7 +239,7 @@ impl Interpreter { fn get_tracer_if_active(&self) -> Option>> { if let Some(tracer) = &self.tracer { - if !tracer.borrow().only_count() && self.mask_tracer.is_empty() { + if !tracer.borrow().dry_run() && self.mask_tracer.is_empty() { self.tracer.clone() } else { None @@ -249,12 +249,12 @@ impl Interpreter { } } - fn tracer_count(&self) { + fn inc_trace_counter(&self) { if !self.mask_tracer.is_empty() { return; } if let Some(tracer) = &self.tracer { - tracer.borrow_mut().count(); + tracer.borrow_mut().inc_counter(); } } @@ -2027,7 +2027,7 @@ impl Interpreter { macro_rules! trace_post { () => {{ - self.tracer_count(); + self.inc_trace_counter(); if let Some(tracer) = self.get_tracer_if_active() { let post_status = self.run_instruction_post(pre_status, function_context, &instruction); diff --git a/src/tracer/mod.rs b/src/tracer/mod.rs index be0359cbf2..fb712747c9 100644 --- a/src/tracer/mod.rs +++ b/src/tracer/mod.rs @@ -54,7 +54,7 @@ pub struct Tracer { // Wasm Image Function Idx pub wasm_input_func_idx: Option, pub wasm_input_func_ref: Option, - only_counter: bool, + dry_run: bool, counter: usize, } @@ -63,14 +63,7 @@ impl Tracer { pub fn new( host_plugin_lookup: HashMap, phantom_functions: &Vec, - ) -> Self { - Self::new_with_counter(host_plugin_lookup, phantom_functions, false) - } - - pub fn new_with_counter( - host_plugin_lookup: HashMap, - phantom_functions: &Vec, - only_counter: bool, + dry_run: bool, ) -> Self { Tracer { itable: InstructionTable::default(), @@ -90,7 +83,7 @@ impl Tracer { phantom_functions_ref: vec![], wasm_input_func_ref: None, wasm_input_func_idx: None, - only_counter, + dry_run, counter: 0, } } @@ -124,12 +117,12 @@ impl Tracer { .clone() } - pub fn count(&mut self) { + pub fn inc_counter(&mut self) { self.counter += 1; } - pub fn only_count(&self) -> bool { - self.only_counter + pub fn dry_run(&self) -> bool { + self.dry_run } pub fn get_trace_count(&self) -> usize { diff --git a/src/tracer/phantom.rs b/src/tracer/phantom.rs index 4bf3c16b6f..a59358fa1a 100644 --- a/src/tracer/phantom.rs +++ b/src/tracer/phantom.rs @@ -58,15 +58,15 @@ impl Tracer { ) { let has_return_value = callee_sig.return_type().is_some(); - if self.only_count() { + if self.dry_run() { if has_return_value { - self.count(); - self.count(); + self.inc_counter(); + self.inc_counter(); if callee_sig.return_type() != Some(wasmi_core::ValueType::I64) { - self.count(); + self.inc_counter(); } } - self.count(); + self.inc_counter(); return; } From 322ac1fc3c7be7e82d1a52591c46bd43c032eaa8 Mon Sep 17 00:00:00 2001 From: sinka Date: Thu, 30 Nov 2023 21:24:33 +1100 Subject: [PATCH 110/129] refactor of filltrace --- src/runner.rs | 10 +--------- src/tracer/phantom.rs | 9 ++++++--- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/src/runner.rs b/src/runner.rs index 124b26eafd..46ac7ebd81 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -2084,19 +2084,11 @@ impl Interpreter { let sp_before = self.mask_tracer.pop().unwrap(); if self.mask_tracer.is_empty() { - let last_jump_eid = tracer.borrow().last_jump_eid(); - let callee_fid = - tracer.borrow().lookup_function(&function_context.function); - let wasm_input_function_idx = - tracer.borrow().wasm_input_func_idx.unwrap(); - tracer.borrow_mut().fill_trace( sp_before, current_memory as u32, - last_jump_eid, - callee_fid, + &function_context.function, function_context.function.signature(), - wasm_input_function_idx, if let isa::Keep::Single(t) = drop_keep.keep { Some(from_value_internal_to_u64_with_typ( t.into(), diff --git a/src/tracer/phantom.rs b/src/tracer/phantom.rs index a59358fa1a..990f787f37 100644 --- a/src/tracer/phantom.rs +++ b/src/tracer/phantom.rs @@ -7,6 +7,7 @@ use specs::{ use super::{etable::ETable, Tracer}; use crate::{ + func::FuncRef, isa::{DropKeep, Instruction, Keep}, Signature, }; @@ -49,11 +50,9 @@ impl Tracer { &mut self, current_sp: u32, allocated_memory_pages: u32, - last_jump_eid: u32, - fid: u32, + callee_func_ref: &FuncRef, callee_sig: &Signature, // Wasm Image Function Id - wasm_input_function_idx: u32, keep_value: Option, ) { let has_return_value = callee_sig.return_type().is_some(); @@ -70,6 +69,10 @@ impl Tracer { return; } + let last_jump_eid = self.last_jump_eid(); + let fid = self.lookup_function(callee_func_ref); + let wasm_input_function_idx = self.wasm_input_func_idx.unwrap(); + let mut inst = PhantomFunction::build_phantom_function_instructions( &callee_sig, wasm_input_function_idx, From 7ac2bb54dca011e68bd9f84633387a064944fbff Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Fri, 1 Dec 2023 13:44:06 +0800 Subject: [PATCH 111/129] refactor: unify function index with binary --- src/func.rs | 31 ++++++++++++++-------------- src/isa.rs | 7 +------ src/module.rs | 14 +++++++------ src/runner.rs | 8 +++----- src/tracer/mod.rs | 47 +++++++++---------------------------------- src/tracer/phantom.rs | 8 ++++---- 6 files changed, 42 insertions(+), 73 deletions(-) diff --git a/src/func.rs b/src/func.rs index 1f2b6342b5..fcd610e859 100644 --- a/src/func.rs +++ b/src/func.rs @@ -55,7 +55,7 @@ pub(crate) enum FuncInstanceInternal { signature: Rc, module: Weak, body: Rc, - image_func_index: usize, + index: usize, }, Host { signature: Signature, @@ -66,16 +66,9 @@ pub(crate) enum FuncInstanceInternal { impl PartialEq for FuncInstanceInternal { fn eq(&self, other: &Self) -> bool { match (self, other) { - ( - Self::Internal { - image_func_index: l_image_func_index, - .. - }, - Self::Internal { - image_func_index: r_image_func_index, - .. - }, - ) => l_image_func_index == r_image_func_index, + (Self::Internal { index: l_index, .. }, Self::Internal { index: r_index, .. }) => { + l_index == r_index + } ( Self::Host { signature: l_signature, @@ -94,10 +87,18 @@ impl PartialEq for FuncInstanceInternal { impl fmt::Debug for FuncInstance { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self.as_internal() { - FuncInstanceInternal::Internal { ref signature, .. } => { + FuncInstanceInternal::Internal { + ref signature, + index, + .. + } => { // We can't write description of self.module here, because it generate // debug string for function instances and this will lead to infinite loop. - write!(f, "Internal {{ signature={:?} }}", signature,) + write!( + f, + "Internal {{ signature={:?}, index={} }}", + signature, index + ) } FuncInstanceInternal::Host { ref signature, .. } => { write!(f, "Host {{ signature={:?} }}", signature) @@ -143,13 +144,13 @@ impl FuncInstance { module: Weak, signature: Rc, body: FuncBody, - image_func_index: usize, + index: usize, ) -> FuncRef { let func = FuncInstanceInternal::Internal { signature, module, body: Rc::new(body), - image_func_index, + index, }; FuncRef(Rc::new(FuncInstance(func))) } diff --git a/src/isa.rs b/src/isa.rs index cb0400d3e4..76690a82a0 100644 --- a/src/isa.rs +++ b/src/isa.rs @@ -444,12 +444,7 @@ impl<'a> Instruction<'a> { let func_desc = function_mapping.get(&func_index).unwrap(); match &func_desc.ftype { - specs::types::FunctionType::WasmFunction => Opcode::Call { - index: function_mapping - .get(&func_index) - .unwrap() - .index_within_jtable, - }, + specs::types::FunctionType::WasmFunction => Opcode::Call { index: func_index }, specs::types::FunctionType::HostFunction { plugin, function_index, diff --git a/src/module.rs b/src/module.rs index 6a514c144b..d64e3392b1 100644 --- a/src/module.rs +++ b/src/module.rs @@ -207,6 +207,10 @@ impl ModuleInstance { self.signatures.borrow().get(idx as usize).cloned() } + fn funcs(&self) -> RefCell> { + self.funcs.clone() + } + fn push_func(&self, func: FuncRef) { self.funcs.borrow_mut().push(func); } @@ -287,7 +291,7 @@ impl ModuleInstance { } if import.field() == "wasm_input" { - if let Some(tracer) = tracer.clone() { + if let Some(tracer) = tracer.as_ref() { tracer.borrow_mut().wasm_input_func_ref = Some(func.clone()); } } @@ -348,10 +352,10 @@ impl ModuleInstance { Rc::downgrade(&instance.0), signature, func_body, - index, + instance.funcs().borrow().len(), ); - if let Some(tracer) = tracer.clone() { + if let Some(tracer) = tracer.as_ref() { tracer .borrow_mut() .push_type_of_func_ref(func_instance.clone(), ty.type_ref()) @@ -453,9 +457,7 @@ impl ModuleInstance { let module_ref = ModuleInstance::alloc_module(loaded_module, extern_vals, tracer.clone())?; if let Some(tracer) = tracer.clone() { - tracer - .borrow_mut() - .register_module_instance(loaded_module, &module_ref); + tracer.borrow_mut().register_module_instance(&module_ref); } for element_segment in module diff --git a/src/runner.rs b/src/runner.rs index 46ac7ebd81..f0f1492a1a 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -1058,12 +1058,10 @@ impl Interpreter { let tracer = self.tracer.clone().unwrap(); let tracer = tracer.borrow(); - let desc = tracer.function_index_translation.get(&index).unwrap(); + let desc = tracer.function_desc.get(&index).unwrap(); match &desc.ftype { - specs::types::FunctionType::WasmFunction => StepInfo::Call { - index: desc.index_within_jtable, - }, + specs::types::FunctionType::WasmFunction => StepInfo::Call { index }, specs::types::FunctionType::HostFunction { plugin, function_index: host_function_idx, @@ -2034,7 +2032,7 @@ impl Interpreter { let mut tracer = tracer.borrow_mut(); - let instruction = { instruction.into(&tracer.function_index_translation) }; + let instruction = { instruction.into(&tracer.function_desc) }; let function = tracer.lookup_function(&function_context.function); diff --git a/src/tracer/mod.rs b/src/tracer/mod.rs index c91b080a6f..2af0e63d32 100644 --- a/src/tracer/mod.rs +++ b/src/tracer/mod.rs @@ -17,7 +17,6 @@ use crate::{ FuncRef, GlobalRef, MemoryRef, - Module, ModuleRef, Signature, }; @@ -30,7 +29,6 @@ pub mod phantom; #[derive(Debug)] pub struct FuncDesc { - pub index_within_jtable: u32, pub ftype: FunctionType, pub signature: Signature, } @@ -46,8 +44,7 @@ pub struct Tracer { type_of_func_ref: Vec<(FuncRef, u32)>, function_lookup: Vec<(FuncRef, u32)>, pub(crate) last_jump_eid: Vec, - function_index_allocator: u32, - pub(crate) function_index_translation: HashMap, + pub(crate) function_desc: HashMap, pub host_function_index_lookup: HashMap, pub static_jtable_entries: Vec, pub phantom_functions: Vec, @@ -76,8 +73,7 @@ impl Tracer { configure_table: ConfigureTable::default(), type_of_func_ref: vec![], function_lookup: vec![], - function_index_allocator: 1, - function_index_translation: Default::default(), + function_desc: Default::default(), host_function_index_lookup: host_plugin_lookup, static_jtable_entries: vec![], phantom_functions: phantom_functions.clone(), @@ -105,12 +101,6 @@ impl Tracer { self.etable.get_latest_eid() } - fn allocate_func_index(&mut self) -> u32 { - let r = self.function_index_allocator; - self.function_index_allocator = r + 1; - r - } - fn lookup_host_plugin(&self, function_index: usize) -> HostFunctionDesc { self.host_function_index_lookup .get(&function_index) @@ -218,13 +208,7 @@ impl Tracer { .1 } - pub(crate) fn register_module_instance( - &mut self, - module: &Module, - module_instance: &ModuleRef, - ) { - let start_fn_idx = module.module().start_section(); - + pub(crate) fn register_module_instance(&mut self, module_instance: &ModuleRef) { { let mut func_index = 0; @@ -234,12 +218,6 @@ impl Tracer { self.wasm_input_func_idx = Some(func_index) } - let func_index_in_itable = if Some(func_index) == start_fn_idx { - 0 - } else { - self.allocate_func_index() - }; - let ftype = match *func.as_internal() { crate::func::FuncInstanceInternal::Internal { .. } => { FunctionType::WasmFunction @@ -271,12 +249,10 @@ impl Tracer { } }; - self.function_lookup - .push((func.clone(), func_index_in_itable)); - self.function_index_translation.insert( + self.function_lookup.push((func.clone(), func_index)); + self.function_desc.insert( func_index, FuncDesc { - index_within_jtable: func_index_in_itable, ftype, signature: func.signature().clone(), }, @@ -307,7 +283,7 @@ impl Tracer { loop { if let Some(func) = module_instance.func_by_index(func_index) { - let funcdesc = self.function_index_translation.get(&func_index).unwrap(); + let funcdesc = self.function_desc.get(&func_index).unwrap(); if self.is_phantom_function(&func) { let instructions = PhantomFunction::build_phantom_function_instructions( @@ -316,11 +292,8 @@ impl Tracer { ); for (iid, inst) in instructions.into_iter().enumerate() { - self.itable.push( - funcdesc.index_within_jtable, - iid as u32, - inst.into(&self.function_index_translation), - ) + self.itable + .push(func_index, iid as u32, inst.into(&self.function_desc)) } } else { if let Some(body) = func.body() { @@ -330,9 +303,9 @@ impl Tracer { let pc = iter.position(); if let Some(instruction) = iter.next() { let _ = self.itable.push( - funcdesc.index_within_jtable, + func_index, pc, - instruction.into(&self.function_index_translation), + instruction.into(&self.function_desc), ); } else { break; diff --git a/src/tracer/phantom.rs b/src/tracer/phantom.rs index 990f787f37..8650083658 100644 --- a/src/tracer/phantom.rs +++ b/src/tracer/phantom.rs @@ -93,7 +93,7 @@ impl Tracer { InstructionTableEntry { fid, iid, - opcode: inst.next().unwrap().into(&self.function_index_translation), + opcode: inst.next().unwrap().into(&self.function_desc), }, current_sp, allocated_memory_pages, @@ -107,7 +107,7 @@ impl Tracer { InstructionTableEntry { fid, iid, - opcode: inst.next().unwrap().into(&self.function_index_translation), + opcode: inst.next().unwrap().into(&self.function_desc), }, current_sp + 1, allocated_memory_pages, @@ -133,7 +133,7 @@ impl Tracer { InstructionTableEntry { fid, iid, - opcode: inst.next().unwrap().into(&self.function_index_translation), + opcode: inst.next().unwrap().into(&self.function_desc), }, current_sp + 1, allocated_memory_pages, @@ -152,7 +152,7 @@ impl Tracer { InstructionTableEntry { fid, iid, - opcode: inst.next().unwrap().into(&self.function_index_translation), + opcode: inst.next().unwrap().into(&self.function_desc), }, current_sp + has_return_value as u32, allocated_memory_pages, From 09105f15946c8cd2796a27139842f2c314d3f2f7 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Thu, 12 Oct 2023 18:14:44 +0800 Subject: [PATCH 112/129] dump function name for perf monitor --- src/lib.rs | 2 +- src/module.rs | 15 +++++++++++++++ src/runner.rs | 10 ++++++++-- src/tracer/mod.rs | 20 ++++++++++++++++++-- src/tracer/phantom.rs | 5 +++++ 5 files changed, 47 insertions(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index b4183e2025..c62536c012 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -321,7 +321,7 @@ pub mod nan_preserving_float { /// Deserialized module prepared for instantiation. pub struct Module { code_map: Vec, - module: parity_wasm::elements::Module, + pub module: parity_wasm::elements::Module, } impl Module { diff --git a/src/module.rs b/src/module.rs index d64e3392b1..71a0707283 100644 --- a/src/module.rs +++ b/src/module.rs @@ -247,6 +247,7 @@ impl ModuleInstance { tracer: Option>>, ) -> Result { let module = loaded_module.module(); + let instance = ModuleRef(Rc::new(ModuleInstance::default())); for &Type::Function(ref ty) in module.type_section().map(|ts| ts.types()).unwrap_or(&[]) { @@ -438,6 +439,20 @@ impl ModuleInstance { instance.insert_export(field, extern_val); } + if let Some(tracer) = tracer { + if let Some(name_section) = module.names_section() { + let mut tracer = tracer.borrow_mut(); + + name_section.functions().map(|function_names| { + for (function_index, name) in function_names.names().iter() { + tracer + .function_lookup_name + .insert(function_index, name.to_string()); + } + }); + } + } + Ok(instance) } diff --git a/src/runner.rs b/src/runner.rs index f0f1492a1a..877ecd251f 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -1061,7 +1061,10 @@ impl Interpreter { let desc = tracer.function_desc.get(&index).unwrap(); match &desc.ftype { - specs::types::FunctionType::WasmFunction => StepInfo::Call { index }, + specs::types::FunctionType::WasmFunction => StepInfo::Call { + index, + function_name: tracer.lookup_function_name(index), + }, specs::types::FunctionType::HostFunction { plugin, function_index: host_function_idx, @@ -1118,6 +1121,7 @@ impl Interpreter { } = pre_status.unwrap() { let tracer = self.tracer.clone().unwrap(); + let tracer = tracer.borrow(); let table = context .module() @@ -1125,13 +1129,14 @@ impl Interpreter { .unwrap(); let func_ref = table.get(offset).unwrap().unwrap(); - let func_idx = tracer.borrow().lookup_function(&func_ref); + let func_idx = tracer.lookup_function(&func_ref); StepInfo::CallIndirect { table_index: table_idx, type_index: type_idx, offset, func_index: func_idx, + function_name: tracer.lookup_function_name(func_idx), } } else { unreachable!() @@ -2040,6 +2045,7 @@ impl Interpreter { let inst_entry = InstructionTableEntry { fid: function, + function_name: tracer.lookup_function_name(function), iid: pc, opcode: instruction, }; diff --git a/src/tracer/mod.rs b/src/tracer/mod.rs index 2af0e63d32..bf7abb83b4 100644 --- a/src/tracer/mod.rs +++ b/src/tracer/mod.rs @@ -43,6 +43,7 @@ pub struct Tracer { pub configure_table: ConfigureTable, type_of_func_ref: Vec<(FuncRef, u32)>, function_lookup: Vec<(FuncRef, u32)>, + pub(crate) function_lookup_name: HashMap, pub(crate) last_jump_eid: Vec, pub(crate) function_desc: HashMap, pub host_function_index_lookup: HashMap, @@ -74,6 +75,7 @@ impl Tracer { type_of_func_ref: vec![], function_lookup: vec![], function_desc: Default::default(), + function_lookup_name: Default::default(), host_function_index_lookup: host_plugin_lookup, static_jtable_entries: vec![], phantom_functions: phantom_functions.clone(), @@ -284,6 +286,7 @@ impl Tracer { loop { if let Some(func) = module_instance.func_by_index(func_index) { let funcdesc = self.function_desc.get(&func_index).unwrap(); + let function_name = self.lookup_function_name(func_index); if self.is_phantom_function(&func) { let instructions = PhantomFunction::build_phantom_function_instructions( @@ -292,8 +295,12 @@ impl Tracer { ); for (iid, inst) in instructions.into_iter().enumerate() { - self.itable - .push(func_index, iid as u32, inst.into(&self.function_desc)) + self.itable.push( + func_index, + function_name.clone(), + iid as u32, + inst.into(&self.function_desc), + ) } } else { if let Some(body) = func.body() { @@ -304,6 +311,7 @@ impl Tracer { if let Some(instruction) = iter.next() { let _ = self.itable.push( func_index, + function_name.clone(), pc, instruction.into(&self.function_desc), ); @@ -322,6 +330,14 @@ impl Tracer { } } + pub fn lookup_function_name(&self, function: u32) -> String { + if let Some(name) = self.function_lookup_name.get(&function) { + name.to_owned() + } else { + function.to_string() + } + } + pub fn lookup_function(&self, function: &FuncRef) -> u32 { let pos = self .function_lookup diff --git a/src/tracer/phantom.rs b/src/tracer/phantom.rs index 8650083658..1276e09775 100644 --- a/src/tracer/phantom.rs +++ b/src/tracer/phantom.rs @@ -68,6 +68,7 @@ impl Tracer { self.inc_counter(); return; } + let function_name = self.lookup_function_name(fid); let last_jump_eid = self.last_jump_eid(); let fid = self.lookup_function(callee_func_ref); @@ -92,6 +93,7 @@ impl Tracer { self.etable.push( InstructionTableEntry { fid, + function_name: function_name.clone(), iid, opcode: inst.next().unwrap().into(&self.function_desc), }, @@ -106,6 +108,7 @@ impl Tracer { self.etable.push( InstructionTableEntry { fid, + function_name: function_name.clone(), iid, opcode: inst.next().unwrap().into(&self.function_desc), }, @@ -132,6 +135,7 @@ impl Tracer { self.etable.push( InstructionTableEntry { fid, + function_name: function_name.clone(), iid, opcode: inst.next().unwrap().into(&self.function_desc), }, @@ -151,6 +155,7 @@ impl Tracer { self.etable.push( InstructionTableEntry { fid, + function_name, iid, opcode: inst.next().unwrap().into(&self.function_desc), }, From cf89916af358e200b4d67cab8d8538f889ff5542 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Fri, 1 Dec 2023 15:32:16 +0800 Subject: [PATCH 113/129] refine lookup_function with hashmap --- src/func.rs | 25 ++++++++++++++++++++++--- src/tracer/mod.rs | 13 ++++--------- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/src/func.rs b/src/func.rs index fcd610e859..b4d812cf60 100644 --- a/src/func.rs +++ b/src/func.rs @@ -14,7 +14,7 @@ use alloc::{ rc::{Rc, Weak}, vec::Vec, }; -use core::{cell::RefCell, fmt}; +use core::{cell::RefCell, fmt, hash::Hash}; use parity_wasm::elements::Local; /// Reference to a function (See [`FuncInstance`] for details). @@ -22,7 +22,7 @@ use parity_wasm::elements::Local; /// This reference has a reference-counting semantics. /// /// [`FuncInstance`]: struct.FuncInstance.html -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct FuncRef(Rc); impl ::core::ops::Deref for FuncRef { @@ -46,7 +46,7 @@ impl ::core::ops::Deref for FuncRef { /// See more in [`Externals`]. /// /// [`Externals`]: trait.Externals.html -#[derive(PartialEq)] +#[derive(PartialEq, Eq, Hash)] pub struct FuncInstance(FuncInstanceInternal); #[derive(Clone)] @@ -63,6 +63,23 @@ pub(crate) enum FuncInstanceInternal { }, } +impl Hash for FuncInstanceInternal { + fn hash(&self, state: &mut H) { + match self { + FuncInstanceInternal::Internal { index, .. } => { + 0.hash(state); + index.hash(state); + } + FuncInstanceInternal::Host { + host_func_index, .. + } => { + 1.hash(state); + host_func_index.hash(state); + } + } + } +} + impl PartialEq for FuncInstanceInternal { fn eq(&self, other: &Self) -> bool { match (self, other) { @@ -84,6 +101,8 @@ impl PartialEq for FuncInstanceInternal { } } +impl Eq for FuncInstanceInternal {} + impl fmt::Debug for FuncInstance { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self.as_internal() { diff --git a/src/tracer/mod.rs b/src/tracer/mod.rs index bf7abb83b4..bb5e65afeb 100644 --- a/src/tracer/mod.rs +++ b/src/tracer/mod.rs @@ -42,7 +42,7 @@ pub struct Tracer { pub elem_table: ElemTable, pub configure_table: ConfigureTable, type_of_func_ref: Vec<(FuncRef, u32)>, - function_lookup: Vec<(FuncRef, u32)>, + function_lookup: HashMap, pub(crate) function_lookup_name: HashMap, pub(crate) last_jump_eid: Vec, pub(crate) function_desc: HashMap, @@ -73,7 +73,7 @@ impl Tracer { elem_table: ElemTable::default(), configure_table: ConfigureTable::default(), type_of_func_ref: vec![], - function_lookup: vec![], + function_lookup: HashMap::default(), function_desc: Default::default(), function_lookup_name: Default::default(), host_function_index_lookup: host_plugin_lookup, @@ -251,7 +251,7 @@ impl Tracer { } }; - self.function_lookup.push((func.clone(), func_index)); + self.function_lookup.insert(func.clone(), func_index); self.function_desc.insert( func_index, FuncDesc { @@ -339,12 +339,7 @@ impl Tracer { } pub fn lookup_function(&self, function: &FuncRef) -> u32 { - let pos = self - .function_lookup - .iter() - .position(|m| m.0 == *function) - .unwrap(); - self.function_lookup.get(pos).unwrap().1 + *self.function_lookup.get(function).unwrap() } pub fn lookup_ientry(&self, function: &FuncRef, pos: u32) -> InstructionTableEntry { From c21a9947b55ce15a5f50954029258c41ec2d71bc Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Fri, 1 Dec 2023 18:38:14 +0800 Subject: [PATCH 114/129] perf: Remove instruction entry from event table --- src/runner.rs | 30 ++++++++------------------- src/tracer/etable.rs | 10 +++++---- src/tracer/mod.rs | 30 +++------------------------ src/tracer/phantom.rs | 47 +++++++++---------------------------------- 4 files changed, 26 insertions(+), 91 deletions(-) diff --git a/src/runner.rs b/src/runner.rs index 877ecd251f..73c7b05288 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -33,7 +33,7 @@ use core::{cell::RefCell, fmt, ops, u32, usize}; use parity_wasm::elements::Local; use specs::{ external_host_call_table::ExternalHostCallSignature, - itable::{BinOp, BitOp, InstructionTableEntry, RelOp, ShiftOp, UnaryOp}, + itable::{BinOp, BitOp, RelOp, ShiftOp, UnaryOp}, jtable::JumpTableEntry, mtable::{MemoryReadSize, MemoryStoreSize, VarType}, step::StepInfo, @@ -360,17 +360,15 @@ impl Interpreter { let eid = tracer.eid(); let last_jump_eid = tracer.last_jump_eid(); - - let inst = tracer.lookup_ientry( - &function_context.function, - function_context.position, - ); + let fid = tracer.lookup_function(&function_context.function); + let iid = function_context.position; tracer.jtable.push(JumpTableEntry { eid, last_jump_eid, callee_fid, - inst: Box::new(inst.into()), + fid, + iid, }); tracer.push_frame(); @@ -1061,10 +1059,7 @@ impl Interpreter { let desc = tracer.function_desc.get(&index).unwrap(); match &desc.ftype { - specs::types::FunctionType::WasmFunction => StepInfo::Call { - index, - function_name: tracer.lookup_function_name(index), - }, + specs::types::FunctionType::WasmFunction => StepInfo::Call { index }, specs::types::FunctionType::HostFunction { plugin, function_index: host_function_idx, @@ -1136,7 +1131,6 @@ impl Interpreter { type_index: type_idx, offset, func_index: func_idx, - function_name: tracer.lookup_function_name(func_idx), } } else { unreachable!() @@ -2037,21 +2031,13 @@ impl Interpreter { let mut tracer = tracer.borrow_mut(); - let instruction = { instruction.into(&tracer.function_desc) }; - let function = tracer.lookup_function(&function_context.function); let last_jump_eid = tracer.last_jump_eid(); - let inst_entry = InstructionTableEntry { - fid: function, - function_name: tracer.lookup_function_name(function), - iid: pc, - opcode: instruction, - }; - tracer.etable.push( - inst_entry, + function, + pc, sp.try_into().unwrap(), current_memory.try_into().unwrap(), last_jump_eid, diff --git a/src/tracer/etable.rs b/src/tracer/etable.rs index 58e94a8525..27725f99ff 100644 --- a/src/tracer/etable.rs +++ b/src/tracer/etable.rs @@ -1,7 +1,6 @@ use parity_wasm::elements::ValueType; use specs::{ etable::{EventTable, EventTableEntry}, - itable::InstructionTableEntry, mtable::{MemoryReadSize, MemoryStoreSize, VarType}, step::StepInfo, }; @@ -126,7 +125,8 @@ pub(crate) trait ETable { fn push( &mut self, - inst: InstructionTableEntry, + fid: u32, + iid: u32, sp: u32, allocated_memory_pages: u32, last_jump_eid: u32, @@ -145,7 +145,8 @@ impl ETable for EventTable { fn push( &mut self, - inst: InstructionTableEntry, + fid: u32, + iid: u32, sp: u32, allocated_memory_pages: u32, last_jump_eid: u32, @@ -159,10 +160,11 @@ impl ETable for EventTable { let eentry = EventTableEntry { eid: (self.entries().len() + 1).try_into().unwrap(), + fid, + iid, sp, allocated_memory_pages, last_jump_eid, - inst, step_info, }; diff --git a/src/tracer/mod.rs b/src/tracer/mod.rs index bb5e65afeb..e46838e9b1 100644 --- a/src/tracer/mod.rs +++ b/src/tracer/mod.rs @@ -6,7 +6,7 @@ use specs::{ configure_table::ConfigureTable, etable::EventTable, host_function::HostFunctionDesc, - itable::{InstructionTable, InstructionTableEntry}, + itable::InstructionTableInternal, jtable::{JumpTable, StaticFrameEntry}, mtable::VarType, types::FunctionType, @@ -35,7 +35,7 @@ pub struct FuncDesc { #[derive(Debug)] pub struct Tracer { - pub itable: InstructionTable, + pub itable: InstructionTableInternal, pub imtable: IMTable, pub etable: EventTable, pub jtable: JumpTable, @@ -65,7 +65,7 @@ impl Tracer { dry_run: bool, ) -> Self { Tracer { - itable: InstructionTable::default(), + itable: InstructionTableInternal::default(), imtable: IMTable::default(), etable: EventTable::default(), last_jump_eid: vec![], @@ -342,30 +342,6 @@ impl Tracer { *self.function_lookup.get(function).unwrap() } - pub fn lookup_ientry(&self, function: &FuncRef, pos: u32) -> InstructionTableEntry { - let function_idx = self.lookup_function(function); - - for ientry in self.itable.entries() { - if ientry.fid == function_idx && ientry.iid as u32 == pos { - return ientry.clone(); - } - } - - unreachable!() - } - - pub fn lookup_first_inst(&self, function: &FuncRef) -> InstructionTableEntry { - let function_idx = self.lookup_function(function); - - for ientry in self.itable.entries() { - if ientry.fid == function_idx { - return ientry.clone(); - } - } - - unreachable!(); - } - pub fn push_phantom_function(&mut self, function: FuncRef) { self.phantom_functions_ref.push(function) } diff --git a/src/tracer/phantom.rs b/src/tracer/phantom.rs index 1276e09775..7f9c062a7d 100644 --- a/src/tracer/phantom.rs +++ b/src/tracer/phantom.rs @@ -1,9 +1,4 @@ -use specs::{ - host_function::HostPlugin, - itable::InstructionTableEntry, - step::StepInfo, - types::ValueType, -}; +use specs::{host_function::HostPlugin, step::StepInfo, types::ValueType}; use super::{etable::ETable, Tracer}; use crate::{ @@ -52,7 +47,6 @@ impl Tracer { allocated_memory_pages: u32, callee_func_ref: &FuncRef, callee_sig: &Signature, - // Wasm Image Function Id keep_value: Option, ) { let has_return_value = callee_sig.return_type().is_some(); @@ -68,17 +62,10 @@ impl Tracer { self.inc_counter(); return; } - let function_name = self.lookup_function_name(fid); let last_jump_eid = self.last_jump_eid(); let fid = self.lookup_function(callee_func_ref); - let wasm_input_function_idx = self.wasm_input_func_idx.unwrap(); - let mut inst = PhantomFunction::build_phantom_function_instructions( - &callee_sig, - wasm_input_function_idx, - ) - .into_iter(); let mut iid = 0; let wasm_input_host_function_ref = self.wasm_input_func_ref.clone().unwrap(); @@ -91,12 +78,8 @@ impl Tracer { if has_return_value { self.etable.push( - InstructionTableEntry { - fid, - function_name: function_name.clone(), - iid, - opcode: inst.next().unwrap().into(&self.function_desc), - }, + fid, + iid, current_sp, allocated_memory_pages, last_jump_eid, @@ -106,12 +89,8 @@ impl Tracer { iid += 1; self.etable.push( - InstructionTableEntry { - fid, - function_name: function_name.clone(), - iid, - opcode: inst.next().unwrap().into(&self.function_desc), - }, + fid, + iid, current_sp + 1, allocated_memory_pages, last_jump_eid, @@ -133,12 +112,8 @@ impl Tracer { if callee_sig.return_type() != Some(wasmi_core::ValueType::I64) { self.etable.push( - InstructionTableEntry { - fid, - function_name: function_name.clone(), - iid, - opcode: inst.next().unwrap().into(&self.function_desc), - }, + fid, + iid, current_sp + 1, allocated_memory_pages, last_jump_eid, @@ -153,12 +128,8 @@ impl Tracer { } self.etable.push( - InstructionTableEntry { - fid, - function_name, - iid, - opcode: inst.next().unwrap().into(&self.function_desc), - }, + fid, + iid, current_sp + has_return_value as u32, allocated_memory_pages, last_jump_eid, From eee8fb1dfe144c43bc90a55315fc1a95e99b51c3 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Tue, 26 Dec 2023 13:55:04 +0800 Subject: [PATCH 115/129] feat: add Observer into Tracer to expose current state --- src/tracer/mod.rs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/tracer/mod.rs b/src/tracer/mod.rs index e46838e9b1..3aebc7980f 100644 --- a/src/tracer/mod.rs +++ b/src/tracer/mod.rs @@ -33,6 +33,11 @@ pub struct FuncDesc { pub signature: Signature, } +#[derive(Debug)] +pub struct Observer { + pub counter: usize, +} + #[derive(Debug)] pub struct Tracer { pub itable: InstructionTableInternal, @@ -54,7 +59,8 @@ pub struct Tracer { pub wasm_input_func_idx: Option, pub wasm_input_func_ref: Option, dry_run: bool, - counter: usize, + + pub observer: Observer, } impl Tracer { @@ -83,7 +89,8 @@ impl Tracer { wasm_input_func_ref: None, wasm_input_func_idx: None, dry_run, - counter: 0, + + observer: Observer { counter: 0 }, } } @@ -111,16 +118,12 @@ impl Tracer { } pub fn inc_counter(&mut self) { - self.counter += 1; + self.observer.counter += 1; } pub fn dry_run(&self) -> bool { self.dry_run } - - pub fn get_trace_count(&self) -> usize { - self.counter - } } impl Tracer { From c38b0822831807ef69f8206e4d0bcb264efffdf0 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Fri, 12 Jan 2024 11:18:43 +0800 Subject: [PATCH 116/129] feat: expose phantom status to Observer --- src/runner.rs | 26 ++++++++++++++++++++++++-- src/tracer/mod.rs | 14 +++++++++++++- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/src/runner.rs b/src/runner.rs index 73c7b05288..14da4180a5 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -258,6 +258,28 @@ impl Interpreter { } } + fn push_phantom_frame(&mut self, sp: u32) { + if self.mask_tracer.is_empty() { + self.tracer + .as_ref() + .map(|tracer| tracer.borrow_mut().set_in_phantom()); + } + + self.mask_tracer.push(sp); + } + + fn pop_phantom_frame(&mut self) -> Option { + let r = self.mask_tracer.pop(); + + if self.mask_tracer.is_empty() { + self.tracer + .as_ref() + .map(|tracer| tracer.borrow_mut().set_exit_phantom()); + } + + r + } + pub fn state(&self) -> &InterpreterState { &self.state } @@ -379,7 +401,7 @@ impl Interpreter { .borrow() .is_phantom_function(&nested_context.function) { - self.mask_tracer.push(self.value_stack.sp as u32); + self.push_phantom_frame(self.value_stack.sp as u32); } } @@ -2071,7 +2093,7 @@ impl Interpreter { .borrow() .is_phantom_function(&function_context.function) { - let sp_before = self.mask_tracer.pop().unwrap(); + let sp_before = self.pop_phantom_frame().unwrap(); if self.mask_tracer.is_empty() { tracer.borrow_mut().fill_trace( diff --git a/src/tracer/mod.rs b/src/tracer/mod.rs index 3aebc7980f..23ca56865d 100644 --- a/src/tracer/mod.rs +++ b/src/tracer/mod.rs @@ -36,6 +36,7 @@ pub struct FuncDesc { #[derive(Debug)] pub struct Observer { pub counter: usize, + pub is_in_phantom: bool, } #[derive(Debug)] @@ -90,7 +91,10 @@ impl Tracer { wasm_input_func_idx: None, dry_run, - observer: Observer { counter: 0 }, + observer: Observer { + counter: 0, + is_in_phantom: false, + }, } } @@ -121,6 +125,14 @@ impl Tracer { self.observer.counter += 1; } + pub fn set_in_phantom(&mut self) { + self.observer.is_in_phantom = true; + } + + pub fn set_exit_phantom(&mut self) { + self.observer.is_in_phantom = false; + } + pub fn dry_run(&self) -> bool { self.dry_run } From d0b7e3ede7b08833c6d0058d476d9f8eec802eae Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Thu, 19 Oct 2023 00:03:18 +0800 Subject: [PATCH 117/129] remove unused param for imtable --- src/tracer/imtable.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tracer/imtable.rs b/src/tracer/imtable.rs index 2f7ea82113..3a62029f47 100644 --- a/src/tracer/imtable.rs +++ b/src/tracer/imtable.rs @@ -30,7 +30,7 @@ impl IMTable { }) } - pub fn finalized(&self, k: u32) -> InitMemoryTable { - InitMemoryTable::new(self.0.clone(), k) + pub fn finalized(&self) -> InitMemoryTable { + InitMemoryTable::new(self.0.clone()) } } From 50d495fb39e7469f68ac6d5e74a285a917b8e0ba Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Thu, 19 Oct 2023 11:57:24 +0800 Subject: [PATCH 118/129] revert init memory table initialization --- src/tracer/imtable.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tracer/imtable.rs b/src/tracer/imtable.rs index 3a62029f47..2f7ea82113 100644 --- a/src/tracer/imtable.rs +++ b/src/tracer/imtable.rs @@ -30,7 +30,7 @@ impl IMTable { }) } - pub fn finalized(&self) -> InitMemoryTable { - InitMemoryTable::new(self.0.clone()) + pub fn finalized(&self, k: u32) -> InitMemoryTable { + InitMemoryTable::new(self.0.clone(), k) } } From 2700e8890c3e32d30d558a5637b33d72319ee817 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Thu, 9 Nov 2023 23:11:13 +0800 Subject: [PATCH 119/129] chore: remove k for init memory table --- src/tracer/imtable.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/tracer/imtable.rs b/src/tracer/imtable.rs index 2f7ea82113..8d7f78fd74 100644 --- a/src/tracer/imtable.rs +++ b/src/tracer/imtable.rs @@ -27,10 +27,11 @@ impl IMTable { end_offset, vtype, value, + eid: 0, }) } - pub fn finalized(&self, k: u32) -> InitMemoryTable { - InitMemoryTable::new(self.0.clone(), k) + pub fn finalized(&self) -> InitMemoryTable { + InitMemoryTable::new(self.0.clone()) } } From 581a5b62d01d0176c6dbecc0edaa657ef98f2370 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Fri, 24 Nov 2023 17:19:54 +0800 Subject: [PATCH 120/129] WIP: adapt imtable --- src/tracer/imtable.rs | 6 ++---- src/tracer/mod.rs | 27 +++++++++++++-------------- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/src/tracer/imtable.rs b/src/tracer/imtable.rs index 8d7f78fd74..7fd44c890c 100644 --- a/src/tracer/imtable.rs +++ b/src/tracer/imtable.rs @@ -11,8 +11,7 @@ impl IMTable { &mut self, is_global: bool, is_mutable: bool, - start_offset: u32, - end_offset: u32, + offset: u32, vtype: VarType, value: u64, ) { @@ -23,8 +22,7 @@ impl IMTable { } else { LocationType::Heap }, - start_offset, - end_offset, + offset, vtype, value, eid: 0, diff --git a/src/tracer/mod.rs b/src/tracer/mod.rs index 23ca56865d..b150bd0fc5 100644 --- a/src/tracer/mod.rs +++ b/src/tracer/mod.rs @@ -140,27 +140,27 @@ impl Tracer { impl Tracer { pub(crate) fn push_init_memory(&mut self, memref: MemoryRef) { - let pages = (*memref).limits().initial(); // one page contains 64KB*1024/8=8192 u64 entries - for i in 0..(pages * 8192) { + const ENTRIES: u32 = 8192; + + let pages = (*memref).limits().initial(); + for i in 0..(pages * ENTRIES) { let mut buf = [0u8; 8]; (*memref).get_into(i * 8, &mut buf).unwrap(); self.imtable - .push(false, true, i, i, VarType::I64, u64::from_le_bytes(buf)); + .push(false, true, i, VarType::I64, u64::from_le_bytes(buf)); } - self.imtable.push( - false, - true, - pages * 8192, - memref + // TODO: perf + for offset in (pages * ENTRIES) + ..memref .limits() .maximum() - .map(|limit| limit * 8192 - 1) - .unwrap_or(u32::MAX), - VarType::I64, - 0, - ); + .map(|limit| limit * ENTRIES) + .unwrap_or(u32::MAX) + { + self.imtable.push(false, true, offset, VarType::I64, 0); + } } pub(crate) fn push_global(&mut self, globalidx: u32, globalref: &GlobalRef) { @@ -170,7 +170,6 @@ impl Tracer { true, globalref.is_mutable(), globalidx, - globalidx, vtype, from_value_internal_to_u64_with_typ(vtype, ValueInternal::from(globalref.get())), ); From 1f0265582419844055826ccd26b577b5ee43e27f Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Mon, 11 Dec 2023 14:23:05 +0000 Subject: [PATCH 121/129] perf: reduce imtable --- src/tracer/mod.rs | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/tracer/mod.rs b/src/tracer/mod.rs index b150bd0fc5..a66d177af0 100644 --- a/src/tracer/mod.rs +++ b/src/tracer/mod.rs @@ -147,19 +147,13 @@ impl Tracer { for i in 0..(pages * ENTRIES) { let mut buf = [0u8; 8]; (*memref).get_into(i * 8, &mut buf).unwrap(); - self.imtable - .push(false, true, i, VarType::I64, u64::from_le_bytes(buf)); - } - // TODO: perf - for offset in (pages * ENTRIES) - ..memref - .limits() - .maximum() - .map(|limit| limit * ENTRIES) - .unwrap_or(u32::MAX) - { - self.imtable.push(false, true, offset, VarType::I64, 0); + let v = u64::from_le_bytes(buf); + + if v != 0 { + self.imtable + .push(false, true, i, VarType::I64, u64::from_le_bytes(buf)); + } } } From 4b4f57143224625daf4bcc26887630916b74548a Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Thu, 18 Jan 2024 18:02:06 +0800 Subject: [PATCH 122/129] rebase main --- src/module.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/module.rs b/src/module.rs index 71a0707283..addfe0d37d 100644 --- a/src/module.rs +++ b/src/module.rs @@ -172,7 +172,7 @@ pub struct ModuleInstance { funcs: RefCell>, memories: RefCell>, globals: RefCell>, - pub(crate) exports: RefCell>, + pub exports: RefCell>, } impl ModuleInstance { From 0637ae62573ea9666858fe2c9ccce176af541ccb Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Thu, 1 Feb 2024 14:20:47 +0800 Subject: [PATCH 123/129] avoid unused clone --- src/tracer/etable.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/tracer/etable.rs b/src/tracer/etable.rs index 27725f99ff..3f1e0d5f1e 100644 --- a/src/tracer/etable.rs +++ b/src/tracer/etable.rs @@ -131,7 +131,7 @@ pub(crate) trait ETable { allocated_memory_pages: u32, last_jump_eid: u32, step_info: StepInfo, - ) -> EventTableEntry; + ); } impl ETable for EventTable { @@ -151,7 +151,7 @@ impl ETable for EventTable { allocated_memory_pages: u32, last_jump_eid: u32, step_info: StepInfo, - ) -> EventTableEntry { + ) { let sp = (DEFAULT_VALUE_STACK_LIMIT as u32) .checked_sub(sp) .unwrap() @@ -168,8 +168,6 @@ impl ETable for EventTable { step_info, }; - self.entries_mut().push(eentry.clone()); - - eentry + self.entries_mut().push(eentry); } } From 117129022ad6bdf87ce6082088e1c9c1b37486c2 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Sat, 3 Feb 2024 14:37:13 +0800 Subject: [PATCH 124/129] perf: optimize lookup_function --- src/tracer/mod.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/tracer/mod.rs b/src/tracer/mod.rs index a66d177af0..db6a3ddf77 100644 --- a/src/tracer/mod.rs +++ b/src/tracer/mod.rs @@ -13,6 +13,7 @@ use specs::{ }; use crate::{ + func::FuncInstanceInternal, runner::{from_value_internal_to_u64_with_typ, ValueInternal}, FuncRef, GlobalRef, @@ -347,7 +348,10 @@ impl Tracer { } pub fn lookup_function(&self, function: &FuncRef) -> u32 { - *self.function_lookup.get(function).unwrap() + match function.as_internal() { + FuncInstanceInternal::Internal { index, .. } => *index as u32, + FuncInstanceInternal::Host { .. } => *self.function_lookup.get(function).unwrap(), + } } pub fn push_phantom_function(&mut self, function: FuncRef) { From df05af0ba524ad03f8ad8dc840361ff97209d2ae Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Tue, 20 Feb 2024 08:17:03 +0800 Subject: [PATCH 125/129] perf: avoid tracing when dry-run --- src/module.rs | 32 ++++++++++++++++++-------------- src/tracer/mod.rs | 5 +++++ 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/src/module.rs b/src/module.rs index addfe0d37d..a2b0f5f9c3 100644 --- a/src/module.rs +++ b/src/module.rs @@ -509,15 +509,17 @@ impl ModuleInstance { .expect("Due to validation funcs from element segments should exists"); if let Some(tracer) = tracer.clone() { - let func_idx = tracer.borrow().lookup_function(&func); - let type_idx = tracer.borrow().lookup_type_of_func_ref(&func); - - tracer.borrow_mut().push_elem( - DEFAULT_TABLE_INDEX, - offset_val + j as u32, - func_idx as u32, - type_idx as u32, - ); + if !tracer.borrow().dry_run() { + let func_idx = tracer.borrow().lookup_function(&func); + let type_idx = tracer.borrow().lookup_type_of_func_ref(&func); + + tracer.borrow_mut().push_elem( + DEFAULT_TABLE_INDEX, + offset_val + j as u32, + func_idx as u32, + type_idx as u32, + ); + } } table_inst.set(offset_val + j as u32, Some(func))?; @@ -543,12 +545,14 @@ impl ModuleInstance { if let Some(tracer) = tracer { let mut tracer = tracer.borrow_mut(); - for (globalidx, globalref) in module_ref.globals().iter().enumerate() { - tracer.push_global(globalidx as u32, globalref); - } + if !tracer.dry_run() { + for (globalidx, globalref) in module_ref.globals().iter().enumerate() { + tracer.push_global(globalidx as u32, globalref); + } - if let Some(memory_ref) = module_ref.memory_by_index(DEFAULT_MEMORY_INDEX) { - tracer.push_init_memory(memory_ref) + if let Some(memory_ref) = module_ref.memory_by_index(DEFAULT_MEMORY_INDEX) { + tracer.push_init_memory(memory_ref) + } } } diff --git a/src/tracer/mod.rs b/src/tracer/mod.rs index db6a3ddf77..b7defa212e 100644 --- a/src/tracer/mod.rs +++ b/src/tracer/mod.rs @@ -289,6 +289,11 @@ impl Tracer { } } + // make dry_run ignore itable + if self.dry_run() { + return; + } + { let mut func_index = 0; From 0972bda4cc28e9df76bd85d261f1860d90694784 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Thu, 4 Apr 2024 08:41:35 +0000 Subject: [PATCH 126/129] feat: introduce file backend to support huge execution --- src/runner.rs | 11 +++---- src/tracer/etable.rs | 73 +++++++++++++++++++++++++++++-------------- src/tracer/mod.rs | 15 ++++----- src/tracer/phantom.rs | 2 +- 4 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/runner.rs b/src/runner.rs index 14da4180a5..beafcd8c61 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -8,10 +8,7 @@ use crate::{ memory_units::Pages, module::ModuleRef, nan_preserving_float::{F32, F64}, - tracer::{ - etable::{ETable, RunInstructionTracePre}, - Tracer, - }, + tracer::{etable::RunInstructionTracePre, Tracer}, value::{ ArithmeticOps, ExtendInto, @@ -380,13 +377,13 @@ impl Interpreter { let mut tracer = tracer.borrow_mut(); let callee_fid = tracer.lookup_function(&nested_func); - let eid = tracer.eid(); + let frame_id = tracer.etable.eid; let last_jump_eid = tracer.last_jump_eid(); let fid = tracer.lookup_function(&function_context.function); let iid = function_context.position; tracer.jtable.push(JumpTableEntry { - eid, + eid: frame_id, last_jump_eid, callee_fid, fid, @@ -450,7 +447,7 @@ impl Interpreter { if let Some(tracer) = self.get_tracer_if_active() { let mut tracer = (*tracer).borrow_mut(); - let entry = tracer.etable.get_last_entry_mut().unwrap(); + let entry = tracer.etable.entries_mut().last_mut().unwrap(); match &entry.step_info { StepInfo::CallHost { diff --git a/src/tracer/etable.rs b/src/tracer/etable.rs index 3f1e0d5f1e..5d3e3f8b08 100644 --- a/src/tracer/etable.rs +++ b/src/tracer/etable.rs @@ -1,8 +1,9 @@ use parity_wasm::elements::ValueType; use specs::{ - etable::{EventTable, EventTableEntry}, + etable::{EventTable, EventTableBackend, EventTableEntry}, mtable::{MemoryReadSize, MemoryStoreSize, VarType}, step::StepInfo, + TraceBackend, }; use crate::{runner::ValueInternal, DEFAULT_VALUE_STACK_LIMIT}; @@ -118,32 +119,42 @@ pub enum RunInstructionTracePre { }, } -pub(crate) trait ETable { - fn get_latest_eid(&self) -> u32; - - fn get_last_entry_mut(&mut self) -> Option<&mut EventTableEntry>; - - fn push( - &mut self, - fid: u32, - iid: u32, - sp: u32, - allocated_memory_pages: u32, - last_jump_eid: u32, - step_info: StepInfo, - ); +pub struct ETable { + pub(crate) eid: u32, + slices: Vec, + entries: Vec, + capacity: u32, + backend: TraceBackend, } -impl ETable for EventTable { - fn get_latest_eid(&self) -> u32 { - self.entries().last().unwrap().eid +impl ETable { + pub(crate) fn new(capacity: u32, backend: TraceBackend) -> Self { + Self { + eid: 0, + slices: Vec::default(), + entries: Vec::with_capacity(capacity as usize), + capacity, + backend, + } } - fn get_last_entry_mut(&mut self) -> Option<&mut EventTableEntry> { - self.entries_mut().last_mut() + fn flush(&mut self) { + let empty = Vec::with_capacity(self.capacity as usize); + let entries = std::mem::replace(&mut self.entries, empty); + + let event_table = match &self.backend { + TraceBackend::File(path_builder) => { + let path = path_builder(self.slices.len(), &EventTable::new(entries)); + + EventTableBackend::Json(path) + } + TraceBackend::Memory => EventTableBackend::Memory(EventTable::new(entries)), + }; + + self.slices.push(event_table); } - fn push( + pub(crate) fn push( &mut self, fid: u32, iid: u32, @@ -152,6 +163,12 @@ impl ETable for EventTable { last_jump_eid: u32, step_info: StepInfo, ) { + if self.entries.len() == self.capacity as usize { + self.flush(); + } + + self.eid += 1; + let sp = (DEFAULT_VALUE_STACK_LIMIT as u32) .checked_sub(sp) .unwrap() @@ -159,7 +176,7 @@ impl ETable for EventTable { .unwrap(); let eentry = EventTableEntry { - eid: (self.entries().len() + 1).try_into().unwrap(), + eid: self.eid, fid, iid, sp, @@ -168,6 +185,16 @@ impl ETable for EventTable { step_info, }; - self.entries_mut().push(eentry); + self.entries.push(eentry); + } + + pub(crate) fn entries_mut(&mut self) -> &mut Vec { + &mut self.entries + } + + pub fn finalized(mut self) -> Vec { + self.flush(); + + self.slices } } diff --git a/src/tracer/mod.rs b/src/tracer/mod.rs index b7defa212e..13f2c12b2a 100644 --- a/src/tracer/mod.rs +++ b/src/tracer/mod.rs @@ -4,12 +4,12 @@ use regex::Regex; use specs::{ brtable::{ElemEntry, ElemTable}, configure_table::ConfigureTable, - etable::EventTable, host_function::HostFunctionDesc, itable::InstructionTableInternal, jtable::{JumpTable, StaticFrameEntry}, mtable::VarType, types::FunctionType, + TraceBackend, }; use crate::{ @@ -40,11 +40,10 @@ pub struct Observer { pub is_in_phantom: bool, } -#[derive(Debug)] pub struct Tracer { pub itable: InstructionTableInternal, pub imtable: IMTable, - pub etable: EventTable, + pub etable: ETable, pub jtable: JumpTable, pub elem_table: ElemTable, pub configure_table: ConfigureTable, @@ -71,11 +70,13 @@ impl Tracer { host_plugin_lookup: HashMap, phantom_functions: &Vec, dry_run: bool, + backend: TraceBackend, + capacity: u32, ) -> Self { Tracer { itable: InstructionTableInternal::default(), imtable: IMTable::default(), - etable: EventTable::default(), + etable: ETable::new(capacity, backend), last_jump_eid: vec![], jtable: JumpTable::default(), elem_table: ElemTable::default(), @@ -100,7 +101,7 @@ impl Tracer { } pub fn push_frame(&mut self) { - self.last_jump_eid.push(self.etable.get_latest_eid()); + self.last_jump_eid.push(self.etable.eid); } pub fn pop_frame(&mut self) { @@ -111,10 +112,6 @@ impl Tracer { *self.last_jump_eid.last().unwrap() } - pub fn eid(&self) -> u32 { - self.etable.get_latest_eid() - } - fn lookup_host_plugin(&self, function_index: usize) -> HostFunctionDesc { self.host_function_index_lookup .get(&function_index) diff --git a/src/tracer/phantom.rs b/src/tracer/phantom.rs index 7f9c062a7d..e6260f5661 100644 --- a/src/tracer/phantom.rs +++ b/src/tracer/phantom.rs @@ -1,6 +1,6 @@ use specs::{host_function::HostPlugin, step::StepInfo, types::ValueType}; -use super::{etable::ETable, Tracer}; +use super::Tracer; use crate::{ func::FuncRef, isa::{DropKeep, Instruction, Keep}, From f6ed20ce2b894abb9d2a71ecc2259db81319a326 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Wed, 17 Apr 2024 08:29:50 +0000 Subject: [PATCH 127/129] rewrite tracer --- core/src/value.rs | 10 + examples/interpret.rs | 2 +- examples/invoke.rs | 2 +- examples/tictactoe.rs | 2 +- src/bin/instantiate.rs | 1 - src/func.rs | 30 +- src/isa.rs | 545 +------------ src/lib.rs | 9 +- src/module.rs | 139 +--- src/monitor/mod.rs | 48 ++ src/runner.rs | 1768 +--------------------------------------- src/tracer/etable.rs | 111 --- src/tracer/mod.rs | 357 +------- src/tracer/phantom.rs | 147 ---- tests/e2e/v0/host.rs | 75 +- tests/e2e/v0/wasm.rs | 20 +- tests/spec/v0/run.rs | 4 +- 17 files changed, 194 insertions(+), 3076 deletions(-) create mode 100644 src/monitor/mod.rs delete mode 100644 src/tracer/phantom.rs diff --git a/core/src/value.rs b/core/src/value.rs index 65f27734ce..abe860ba68 100644 --- a/core/src/value.rs +++ b/core/src/value.rs @@ -76,6 +76,16 @@ pub enum Value { F64(F64), } +impl Into for Value { + fn into(self) -> u64 { + match self { + Value::I32(val) => val as u32 as u64, + Value::I64(val) => val as u64, + _ => unreachable!(), + } + } +} + /// Trait for creating value from a [`Value`]. /// /// Typically each implementation can create a value from the specific type. diff --git a/examples/interpret.rs b/examples/interpret.rs index aebf6afd11..d18fc05545 100644 --- a/examples/interpret.rs +++ b/examples/interpret.rs @@ -30,7 +30,7 @@ fn main() { // - a module declaration // - "main" module doesn't import native module(s) this is why we don't need to provide external native modules here // This test shows how to implement native module https://github.com/NikVolf/parity-wasm/blob/master/src/interpreter/tests/basics.rs#L197 - let main = ModuleInstance::new(&module, &ImportsBuilder::default(), None) + let main = ModuleInstance::new(&module, &ImportsBuilder::default()) .expect("Failed to instantiate module") .run_start(&mut NopExternals) .expect("Failed to run start function in module"); diff --git a/examples/invoke.rs b/examples/invoke.rs index b8e6184dbb..5e49c82347 100644 --- a/examples/invoke.rs +++ b/examples/invoke.rs @@ -105,7 +105,7 @@ fn main() { // - a module declaration // - "main" module doesn't import native module(s) this is why we don't need to provide external native modules here // This test shows how to implement native module https://github.com/NikVolf/parity-wasm/blob/master/src/interpreter/tests/basics.rs#L197 - let main = ModuleInstance::new(&loaded_module, &ImportsBuilder::default(), None) + let main = ModuleInstance::new(&loaded_module, &ImportsBuilder::default()) .expect("Failed to instantiate module") .run_start(&mut NopExternals) .expect("Failed to run start function in module"); diff --git a/examples/tictactoe.rs b/examples/tictactoe.rs index 2f9040298a..2fc9926f8c 100644 --- a/examples/tictactoe.rs +++ b/examples/tictactoe.rs @@ -213,7 +213,7 @@ fn instantiate(path: &str) -> Result { let mut imports = ImportsBuilder::new(); imports.push_resolver("env", &RuntimeModuleImportResolver); - let instance = ModuleInstance::new(&module, &imports, None)?.assert_no_start(); + let instance = ModuleInstance::new(&module, &imports)?.assert_no_start(); Ok(instance) } diff --git a/src/bin/instantiate.rs b/src/bin/instantiate.rs index 07de6ccdc7..73bf10e9ea 100644 --- a/src/bin/instantiate.rs +++ b/src/bin/instantiate.rs @@ -91,7 +91,6 @@ fn main() { .with_resolver("global.Math", &ResolveAll) .with_resolver("asm2wasm", &ResolveAll) .with_resolver("spectest", &ResolveAll), - None, ) .expect("Failed to instantiate module") .run_start(&mut NopExternals) diff --git a/src/func.rs b/src/func.rs index b4d812cf60..889273d128 100644 --- a/src/func.rs +++ b/src/func.rs @@ -1,9 +1,9 @@ use crate::{ host::Externals, - isa::{self}, + isa, module::ModuleInstance, + monitor::Monitor, runner::{check_function_args, Interpreter, InterpreterState, StackRecycler}, - tracer::Tracer, RuntimeValue, Signature, Trap, @@ -14,7 +14,7 @@ use alloc::{ rc::{Rc, Weak}, vec::Vec, }; -use core::{cell::RefCell, fmt, hash::Hash}; +use core::{fmt, hash::Hash}; use parity_wasm::elements::Local; /// Reference to a function (See [`FuncInstance`] for details). @@ -50,7 +50,7 @@ impl ::core::ops::Deref for FuncRef { pub struct FuncInstance(FuncInstanceInternal); #[derive(Clone)] -pub(crate) enum FuncInstanceInternal { +pub enum FuncInstanceInternal { Internal { signature: Rc, module: Weak, @@ -155,7 +155,7 @@ impl FuncInstance { } } - pub(crate) fn as_internal(&self) -> &FuncInstanceInternal { + pub fn as_internal(&self) -> &FuncInstanceInternal { &self.0 } @@ -174,7 +174,7 @@ impl FuncInstance { FuncRef(Rc::new(FuncInstance(func))) } - pub(crate) fn body(&self) -> Option> { + pub fn body(&self) -> Option> { match *self.as_internal() { FuncInstanceInternal::Internal { ref body, .. } => Some(Rc::clone(body)), FuncInstanceInternal::Host { .. } => None, @@ -212,13 +212,13 @@ impl FuncInstance { func: &FuncRef, args: &[RuntimeValue], externals: &mut E, - tracer: Rc>, + monitor: &mut dyn Monitor, ) -> Result, Trap> { check_function_args(func.signature(), args)?; match *func.as_internal() { FuncInstanceInternal::Internal { .. } => { let mut interpreter = Interpreter::new(func, args, None)?; - interpreter.tracer = Some(tracer); + interpreter.monitor = Some(monitor); interpreter.start_execution(externals) } FuncInstanceInternal::Host { .. } => unreachable!(), @@ -267,10 +267,10 @@ impl FuncInstance { /// [`Trap`]: #enum.Trap.html /// [`start_execution`]: struct.FuncInvocation.html#method.start_execution /// [`resume_execution`]: struct.FuncInvocation.html#method.resume_execution - pub fn invoke_resumable<'args>( + pub fn invoke_resumable<'a, 'args>( func: &FuncRef, args: impl Into>, - ) -> Result, Trap> { + ) -> Result, Trap> { let args = args.into(); check_function_args(func.signature(), &args)?; match *func.as_internal() { @@ -325,12 +325,12 @@ impl From for ResumableError { } /// A resumable invocation handle. This struct is returned by `FuncInstance::invoke_resumable`. -pub struct FuncInvocation<'args> { - kind: FuncInvocationKind<'args>, +pub struct FuncInvocation<'a, 'args> { + kind: FuncInvocationKind<'a, 'args>, } -enum FuncInvocationKind<'args> { - Internal(Interpreter), +enum FuncInvocationKind<'a, 'args> { + Internal(Interpreter<'a>), Host { args: Cow<'args, [RuntimeValue]>, host_func_index: usize, @@ -338,7 +338,7 @@ enum FuncInvocationKind<'args> { }, } -impl<'args> FuncInvocation<'args> { +impl<'a, 'args> FuncInvocation<'a, 'args> { /// Whether this invocation is currently resumable. pub fn is_resumable(&self) -> bool { match &self.kind { diff --git a/src/isa.rs b/src/isa.rs index 76690a82a0..204352b86a 100644 --- a/src/isa.rs +++ b/src/isa.rs @@ -67,16 +67,9 @@ //! - Reserved immediates are ignored for `call_indirect`, `current_memory`, `grow_memory`. //! -use std::collections::HashMap; - use alloc::vec::Vec; use parity_wasm::elements::ValueType; -use specs::{ - itable::{BinOp, BitOp, BrTarget, ConversionOp, Opcode, RelOp, ShiftOp, TestOp, UnaryOp}, - mtable::{MemoryReadSize, MemoryStoreSize, VarType}, -}; - -use crate::tracer::FuncDesc; +use specs::itable::UnaryOp; /// Should we keep a value before "discarding" a stack frame? /// @@ -126,7 +119,7 @@ pub enum Reloc { #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct BrTargets<'a> { - stream: &'a [InstructionInternal], + pub stream: &'a [InstructionInternal], } impl<'a> BrTargets<'a> { @@ -367,538 +360,6 @@ impl<'a> From> for UnaryOp { } } -impl<'a> Instruction<'a> { - pub(crate) fn into(self, function_mapping: &HashMap) -> Opcode { - match self { - Instruction::GetLocal(offset, typ) => Opcode::LocalGet { - offset: offset as u64, - vtype: typ.into(), - }, - Instruction::SetLocal(offset, typ) => Opcode::LocalSet { - offset: offset as u64, - vtype: typ.into(), - }, - Instruction::TeeLocal(offset, typ) => Opcode::LocalTee { - offset: offset as u64, - vtype: typ.into(), - }, - Instruction::Br(Target { dst_pc, drop_keep }) => Opcode::Br { - drop: drop_keep.drop, - keep: if let Keep::Single(t) = drop_keep.keep { - vec![t.into()] - } else { - vec![] - }, - dst_pc, - }, - Instruction::BrIfEqz(Target { dst_pc, drop_keep }) => Opcode::BrIfEqz { - drop: drop_keep.drop, - keep: if let Keep::Single(t) = drop_keep.keep { - vec![t.into()] - } else { - vec![] - }, - dst_pc, - }, - Instruction::BrIfNez(Target { dst_pc, drop_keep }) => Opcode::BrIf { - drop: drop_keep.drop, - keep: if let Keep::Single(t) = drop_keep.keep { - vec![t.into()] - } else { - vec![] - }, - dst_pc, - }, - Instruction::BrTable(targets) => Opcode::BrTable { - targets: targets - .stream - .iter() - .map(|t| { - if let InstructionInternal::BrTableTarget(target) = t { - let keep_type = match target.drop_keep.keep { - Keep::None => vec![], - Keep::Single(t) => vec![t.into()], - }; - - BrTarget { - drop: target.drop_keep.drop, - keep: keep_type, - dst_pc: target.dst_pc, - } - } else { - unreachable!() - } - }) - .collect(), - }, - Instruction::Unreachable => Opcode::Unreachable, - Instruction::Return(drop_keep) => Opcode::Return { - drop: drop_keep.drop, - keep: if let Keep::Single(t) = drop_keep.keep { - vec![t.into()] - } else { - vec![] - }, - }, - Instruction::Call(func_index) => { - let func_desc = function_mapping.get(&func_index).unwrap(); - - match &func_desc.ftype { - specs::types::FunctionType::WasmFunction => Opcode::Call { index: func_index }, - specs::types::FunctionType::HostFunction { - plugin, - function_index, - function_name, - op_index_in_plugin, - } => Opcode::InternalHostCall { - plugin: *plugin, - function_index: *function_index, - function_name: function_name.clone(), - op_index_in_plugin: *op_index_in_plugin, - }, - specs::types::FunctionType::HostFunctionExternal { op, sig, .. } => { - Opcode::ExternalHostCall { op: *op, sig: *sig } - } - } - } - Instruction::CallIndirect(idx) => Opcode::CallIndirect { type_idx: idx }, - Instruction::Drop => Opcode::Drop, - Instruction::Select(_) => Opcode::Select, - Instruction::GetGlobal(idx) => Opcode::GlobalGet { idx: idx as u64 }, - Instruction::SetGlobal(idx) => Opcode::GlobalSet { idx: idx as u64 }, - Instruction::I32Load(offset) => Opcode::Load { - offset, - vtype: VarType::I32, - size: MemoryReadSize::U32, - }, - Instruction::I64Load(offset) => Opcode::Load { - offset, - vtype: VarType::I64, - size: MemoryReadSize::I64, - }, - Instruction::F32Load(_) => todo!(), - Instruction::F64Load(_) => todo!(), - Instruction::I32Load8S(offset) => Opcode::Load { - offset, - vtype: VarType::I32, - size: MemoryReadSize::S8, - }, - Instruction::I32Load8U(offset) => Opcode::Load { - offset, - vtype: VarType::I32, - size: MemoryReadSize::U8, - }, - Instruction::I32Load16S(offset) => Opcode::Load { - offset, - vtype: VarType::I32, - size: MemoryReadSize::S16, - }, - Instruction::I32Load16U(offset) => Opcode::Load { - offset, - vtype: VarType::I32, - size: MemoryReadSize::U16, - }, - Instruction::I64Load8S(offset) => Opcode::Load { - offset, - vtype: VarType::I64, - size: MemoryReadSize::S8, - }, - Instruction::I64Load8U(offset) => Opcode::Load { - offset, - vtype: VarType::I64, - size: MemoryReadSize::U8, - }, - Instruction::I64Load16S(offset) => Opcode::Load { - offset, - vtype: VarType::I64, - size: MemoryReadSize::S16, - }, - Instruction::I64Load16U(offset) => Opcode::Load { - offset, - vtype: VarType::I64, - size: MemoryReadSize::U16, - }, - Instruction::I64Load32S(offset) => Opcode::Load { - offset, - vtype: VarType::I64, - size: MemoryReadSize::S32, - }, - Instruction::I64Load32U(offset) => Opcode::Load { - offset, - vtype: VarType::I64, - size: MemoryReadSize::U32, - }, - Instruction::I32Store(offset) => Opcode::Store { - offset, - vtype: VarType::I32, - size: MemoryStoreSize::Byte32, - }, - Instruction::I64Store(offset) => Opcode::Store { - offset, - vtype: VarType::I64, - size: MemoryStoreSize::Byte64, - }, - Instruction::F32Store(_) => todo!(), - Instruction::F64Store(_) => todo!(), - Instruction::I32Store8(offset) => Opcode::Store { - offset, - vtype: VarType::I32, - size: MemoryStoreSize::Byte8, - }, - Instruction::I32Store16(offset) => Opcode::Store { - offset, - vtype: VarType::I32, - size: MemoryStoreSize::Byte16, - }, - Instruction::I64Store8(offset) => Opcode::Store { - offset, - vtype: VarType::I64, - size: MemoryStoreSize::Byte8, - }, - Instruction::I64Store16(offset) => Opcode::Store { - offset, - vtype: VarType::I64, - size: MemoryStoreSize::Byte16, - }, - Instruction::I64Store32(offset) => Opcode::Store { - offset, - vtype: VarType::I64, - size: MemoryStoreSize::Byte32, - }, - Instruction::CurrentMemory => Opcode::MemorySize, - Instruction::GrowMemory => Opcode::MemoryGrow, - Instruction::I32Const(v) => Opcode::Const { - vtype: VarType::I32, - value: v as u32 as u64, - }, - Instruction::I64Const(v) => Opcode::Const { - vtype: VarType::I64, - value: v as u64, - }, - Instruction::F32Const(_) => todo!(), - Instruction::F64Const(_) => todo!(), - Instruction::I32Eqz => Opcode::Test { - class: TestOp::Eqz, - vtype: VarType::I32, - }, - Instruction::I32Eq => Opcode::Rel { - class: RelOp::Eq, - vtype: VarType::I32, - }, - Instruction::I32Ne => Opcode::Rel { - class: RelOp::Ne, - vtype: VarType::I32, - }, - Instruction::I32LtS => Opcode::Rel { - class: RelOp::SignedLt, - vtype: VarType::I32, - }, - Instruction::I32LtU => Opcode::Rel { - class: RelOp::UnsignedLt, - vtype: VarType::I32, - }, - Instruction::I32GtS => Opcode::Rel { - class: RelOp::SignedGt, - vtype: VarType::I32, - }, - Instruction::I32GtU => Opcode::Rel { - class: RelOp::UnsignedGt, - vtype: VarType::I32, - }, - Instruction::I32LeS => Opcode::Rel { - class: RelOp::SignedLe, - vtype: VarType::I32, - }, - Instruction::I32LeU => Opcode::Rel { - class: RelOp::UnsignedLe, - vtype: VarType::I32, - }, - Instruction::I32GeS => Opcode::Rel { - class: RelOp::SignedGe, - vtype: VarType::I32, - }, - Instruction::I32GeU => Opcode::Rel { - class: RelOp::UnsignedGe, - vtype: VarType::I32, - }, - Instruction::I64Eqz => Opcode::Test { - class: TestOp::Eqz, - vtype: VarType::I64, - }, - Instruction::I64Eq => Opcode::Rel { - class: RelOp::Eq, - vtype: VarType::I64, - }, - Instruction::I64Ne => Opcode::Rel { - class: RelOp::Ne, - vtype: VarType::I64, - }, - Instruction::I64LtS => Opcode::Rel { - class: RelOp::SignedLt, - vtype: VarType::I64, - }, - Instruction::I64LtU => Opcode::Rel { - class: RelOp::UnsignedLt, - vtype: VarType::I64, - }, - Instruction::I64GtS => Opcode::Rel { - class: RelOp::SignedGt, - vtype: VarType::I64, - }, - Instruction::I64GtU => Opcode::Rel { - class: RelOp::UnsignedGt, - vtype: VarType::I64, - }, - Instruction::I64LeS => Opcode::Rel { - class: RelOp::SignedLe, - vtype: VarType::I64, - }, - Instruction::I64LeU => Opcode::Rel { - class: RelOp::UnsignedLe, - vtype: VarType::I64, - }, - Instruction::I64GeS => Opcode::Rel { - class: RelOp::SignedGe, - vtype: VarType::I64, - }, - Instruction::I64GeU => Opcode::Rel { - class: RelOp::UnsignedGe, - vtype: VarType::I64, - }, - Instruction::F32Eq => todo!(), - Instruction::F32Ne => todo!(), - Instruction::F32Lt => todo!(), - Instruction::F32Gt => todo!(), - Instruction::F32Le => todo!(), - Instruction::F32Ge => todo!(), - Instruction::F64Eq => todo!(), - Instruction::F64Ne => todo!(), - Instruction::F64Lt => todo!(), - Instruction::F64Gt => todo!(), - Instruction::F64Le => todo!(), - Instruction::F64Ge => todo!(), - Instruction::I32Clz => Opcode::Unary { - class: UnaryOp::Clz, - vtype: VarType::I32, - }, - Instruction::I32Ctz => Opcode::Unary { - class: UnaryOp::Ctz, - vtype: VarType::I32, - }, - Instruction::I32Popcnt => Opcode::Unary { - class: UnaryOp::Popcnt, - vtype: VarType::I32, - }, - Instruction::I32Add => Opcode::Bin { - class: BinOp::Add, - vtype: VarType::I32, - }, - Instruction::I32Sub => Opcode::Bin { - class: BinOp::Sub, - vtype: VarType::I32, - }, - Instruction::I32Mul => Opcode::Bin { - class: BinOp::Mul, - vtype: VarType::I32, - }, - Instruction::I32DivS => Opcode::Bin { - class: BinOp::SignedDiv, - vtype: VarType::I32, - }, - Instruction::I32DivU => Opcode::Bin { - class: BinOp::UnsignedDiv, - vtype: VarType::I32, - }, - Instruction::I32RemS => Opcode::Bin { - class: BinOp::SignedRem, - vtype: VarType::I32, - }, - Instruction::I32RemU => Opcode::Bin { - class: BinOp::UnsignedRem, - vtype: VarType::I32, - }, - Instruction::I32And => Opcode::BinBit { - class: BitOp::And, - vtype: VarType::I32, - }, - Instruction::I32Or => Opcode::BinBit { - class: BitOp::Or, - vtype: VarType::I32, - }, - Instruction::I32Xor => Opcode::BinBit { - class: BitOp::Xor, - vtype: VarType::I32, - }, - Instruction::I32Shl => Opcode::BinShift { - class: ShiftOp::Shl, - vtype: VarType::I32, - }, - Instruction::I32ShrS => Opcode::BinShift { - class: ShiftOp::SignedShr, - vtype: VarType::I32, - }, - Instruction::I32ShrU => Opcode::BinShift { - class: ShiftOp::UnsignedShr, - vtype: VarType::I32, - }, - Instruction::I32Rotl => Opcode::BinShift { - class: ShiftOp::Rotl, - vtype: VarType::I32, - }, - Instruction::I32Rotr => Opcode::BinShift { - class: ShiftOp::Rotr, - vtype: VarType::I32, - }, - Instruction::I64Clz => Opcode::Unary { - class: UnaryOp::Clz, - vtype: VarType::I64, - }, - Instruction::I64Ctz => Opcode::Unary { - class: UnaryOp::Ctz, - vtype: VarType::I64, - }, - Instruction::I64Popcnt => Opcode::Unary { - class: UnaryOp::Popcnt, - vtype: VarType::I64, - }, - Instruction::I64Add => Opcode::Bin { - class: BinOp::Add, - vtype: VarType::I64, - }, - Instruction::I64Sub => Opcode::Bin { - class: BinOp::Sub, - vtype: VarType::I64, - }, - Instruction::I64Mul => Opcode::Bin { - class: BinOp::Mul, - vtype: VarType::I64, - }, - Instruction::I64DivS => Opcode::Bin { - class: BinOp::SignedDiv, - vtype: VarType::I64, - }, - Instruction::I64DivU => Opcode::Bin { - class: BinOp::UnsignedDiv, - vtype: VarType::I64, - }, - Instruction::I64RemS => Opcode::Bin { - class: BinOp::SignedRem, - vtype: VarType::I64, - }, - Instruction::I64RemU => Opcode::Bin { - class: BinOp::UnsignedRem, - vtype: VarType::I64, - }, - Instruction::I64And => Opcode::BinBit { - class: BitOp::And, - vtype: VarType::I64, - }, - Instruction::I64Or => Opcode::BinBit { - class: BitOp::Or, - vtype: VarType::I64, - }, - Instruction::I64Xor => Opcode::BinBit { - class: BitOp::Xor, - vtype: VarType::I64, - }, - Instruction::I64Shl => Opcode::BinShift { - class: ShiftOp::Shl, - vtype: VarType::I64, - }, - Instruction::I64ShrS => Opcode::BinShift { - class: ShiftOp::SignedShr, - vtype: VarType::I64, - }, - Instruction::I64ShrU => Opcode::BinShift { - class: ShiftOp::UnsignedShr, - vtype: VarType::I64, - }, - Instruction::I64Rotl => Opcode::BinShift { - class: ShiftOp::Rotl, - vtype: VarType::I64, - }, - Instruction::I64Rotr => Opcode::BinShift { - class: ShiftOp::Rotr, - vtype: VarType::I64, - }, - Instruction::F32Abs => todo!(), - Instruction::F32Neg => todo!(), - Instruction::F32Ceil => todo!(), - Instruction::F32Floor => todo!(), - Instruction::F32Trunc => todo!(), - Instruction::F32Nearest => todo!(), - Instruction::F32Sqrt => todo!(), - Instruction::F32Add => todo!(), - Instruction::F32Sub => todo!(), - Instruction::F32Mul => todo!(), - Instruction::F32Div => todo!(), - Instruction::F32Min => todo!(), - Instruction::F32Max => todo!(), - Instruction::F32Copysign => todo!(), - Instruction::F64Abs => todo!(), - Instruction::F64Neg => todo!(), - Instruction::F64Ceil => todo!(), - Instruction::F64Floor => todo!(), - Instruction::F64Trunc => todo!(), - Instruction::F64Nearest => todo!(), - Instruction::F64Sqrt => todo!(), - Instruction::F64Add => todo!(), - Instruction::F64Sub => todo!(), - Instruction::F64Mul => todo!(), - Instruction::F64Div => todo!(), - Instruction::F64Min => todo!(), - Instruction::F64Max => todo!(), - Instruction::F64Copysign => todo!(), - Instruction::I32WrapI64 => Opcode::Conversion { - class: ConversionOp::I32WrapI64, - }, - Instruction::I32TruncSF32 => todo!(), - Instruction::I32TruncUF32 => todo!(), - Instruction::I32TruncSF64 => todo!(), - Instruction::I32TruncUF64 => todo!(), - Instruction::I64ExtendSI32 => Opcode::Conversion { - class: ConversionOp::I64ExtendI32s, - }, - Instruction::I64ExtendUI32 => Opcode::Conversion { - class: ConversionOp::I64ExtendI32u, - }, - Instruction::I64TruncSF32 => todo!(), - Instruction::I64TruncUF32 => todo!(), - Instruction::I64TruncSF64 => todo!(), - Instruction::I64TruncUF64 => todo!(), - Instruction::F32ConvertSI32 => todo!(), - Instruction::F32ConvertUI32 => todo!(), - Instruction::F32ConvertSI64 => todo!(), - Instruction::F32ConvertUI64 => todo!(), - Instruction::F32DemoteF64 => todo!(), - Instruction::F64ConvertSI32 => todo!(), - Instruction::F64ConvertUI32 => todo!(), - Instruction::F64ConvertSI64 => todo!(), - Instruction::F64ConvertUI64 => todo!(), - Instruction::F64PromoteF32 => todo!(), - Instruction::I32ReinterpretF32 => todo!(), - Instruction::I64ReinterpretF64 => todo!(), - Instruction::F32ReinterpretI32 => todo!(), - Instruction::F64ReinterpretI64 => todo!(), - Instruction::I32Extend8S => Opcode::Conversion { - class: ConversionOp::I32Extend8S, - }, - Instruction::I32Extend16S => Opcode::Conversion { - class: ConversionOp::I32Extend16S, - }, - Instruction::I64Extend8S => Opcode::Conversion { - class: ConversionOp::I64Extend8S, - }, - Instruction::I64Extend16S => Opcode::Conversion { - class: ConversionOp::I64Extend16S, - }, - Instruction::I64Extend32S => Opcode::Conversion { - class: ConversionOp::I64Extend32S, - }, - } - } -} - impl<'a> Into for Instruction<'a> { fn into(self) -> u32 { match self { @@ -1089,7 +550,7 @@ impl<'a> Into for Instruction<'a> { /// borrows the list of instructions and returns targets by reading it. #[derive(Copy, Debug, Clone, PartialEq, Eq)] #[allow(clippy::upper_case_acronyms)] -pub(crate) enum InstructionInternal { +pub enum InstructionInternal { GetLocal(u32, ValueType), SetLocal(u32, ValueType), TeeLocal(u32, ValueType), diff --git a/src/lib.rs b/src/lib.rs index c62536c012..af809716e8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -258,18 +258,19 @@ impl From for Error { } } -mod func; +pub mod func; mod global; mod host; mod imports; -mod isa; mod memory; -mod module; +pub mod module; mod prepare; -mod runner; +pub mod runner; mod table; mod types; +pub mod isa; +pub mod monitor; /// Tracer lib for zkWasm pub mod tracer; diff --git a/src/module.rs b/src/module.rs index a2b0f5f9c3..fd8aa42513 100644 --- a/src/module.rs +++ b/src/module.rs @@ -5,10 +5,10 @@ use crate::{ imports::ImportResolver, memory::MemoryRef, memory_units::Pages, + monitor::Monitor, nan_preserving_float::{F32, F64}, runner::StackRecycler, table::TableRef, - tracer::Tracer, types::{GlobalDescriptor, MemoryDescriptor, TableDescriptor}, Error, MemoryInstance, @@ -30,7 +30,7 @@ use core::{ fmt, }; use parity_wasm::elements::{External, InitExpr, Instruction, Internal, ResizableLimits, Type}; -use specs::configure_table::ConfigureTable; +use std::collections::HashMap; use validation::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX}; /// Reference to a [`ModuleInstance`]. @@ -173,6 +173,8 @@ pub struct ModuleInstance { memories: RefCell>, globals: RefCell>, pub exports: RefCell>, + + funcs_index: RefCell>, } impl ModuleInstance { @@ -184,25 +186,31 @@ impl ModuleInstance { memories: RefCell::new(Vec::new()), globals: RefCell::new(Vec::new()), exports: RefCell::new(BTreeMap::new()), + + funcs_index: RefCell::new(HashMap::new()), } } - pub(crate) fn memory_by_index(&self, idx: u32) -> Option { + pub fn memory_by_index(&self, idx: u32) -> Option { self.memories.borrow_mut().get(idx as usize).cloned() } - pub(crate) fn table_by_index(&self, idx: u32) -> Option { + pub fn table_by_index(&self, idx: u32) -> Option { self.tables.borrow_mut().get(idx as usize).cloned() } - pub(crate) fn global_by_index(&self, idx: u32) -> Option { + pub fn global_by_index(&self, idx: u32) -> Option { self.globals.borrow_mut().get(idx as usize).cloned() } - pub(crate) fn func_by_index(&self, idx: u32) -> Option { + pub fn func_by_index(&self, idx: u32) -> Option { self.funcs.borrow().get(idx as usize).cloned() } + pub fn func_index_by_func_ref(&self, func: &FuncRef) -> u32 { + *self.funcs_index.borrow().get(func).unwrap() + } + pub(crate) fn signature_by_index(&self, idx: u32) -> Option> { self.signatures.borrow().get(idx as usize).cloned() } @@ -212,6 +220,9 @@ impl ModuleInstance { } fn push_func(&self, func: FuncRef) { + let index = self.funcs().borrow().len() as u32; + + self.funcs_index.borrow_mut().insert(func.clone(), index); self.funcs.borrow_mut().push(func); } @@ -244,7 +255,7 @@ impl ModuleInstance { fn alloc_module<'i, I: Iterator>( loaded_module: &Module, extern_vals: I, - tracer: Option>>, + //tracer: Option>>, ) -> Result { let module = loaded_module.module(); @@ -291,11 +302,6 @@ impl ModuleInstance { ))); } - if import.field() == "wasm_input" { - if let Some(tracer) = tracer.as_ref() { - tracer.borrow_mut().wasm_input_func_ref = Some(func.clone()); - } - } instance.push_func(func.clone()) } (&External::Table(ref tt), &ExternVal::Table(ref table)) => { @@ -356,12 +362,6 @@ impl ModuleInstance { instance.funcs().borrow().len(), ); - if let Some(tracer) = tracer.as_ref() { - tracer - .borrow_mut() - .push_type_of_func_ref(func_instance.clone(), ty.type_ref()) - } - instance.push_func(func_instance); } } @@ -383,15 +383,6 @@ impl ModuleInstance { let memory = MemoryInstance::alloc(initial, maximum) .expect("Due to validation `initial` and `maximum` should be valid"); instance.push_memory(memory); - - if let Some(tracer) = tracer.clone() { - let mut tracer = tracer.borrow_mut(); - - tracer.configure_table = ConfigureTable { - init_memory_pages: memory_type.limits().initial(), - maximal_memory_pages: memory_type.limits().maximum().unwrap_or(65536), - }; - } } for global_entry in module @@ -439,20 +430,6 @@ impl ModuleInstance { instance.insert_export(field, extern_val); } - if let Some(tracer) = tracer { - if let Some(name_section) = module.names_section() { - let mut tracer = tracer.borrow_mut(); - - name_section.functions().map(|function_names| { - for (function_index, name) in function_names.names().iter() { - tracer - .function_lookup_name - .insert(function_index, name.to_string()); - } - }); - } - } - Ok(instance) } @@ -465,15 +442,10 @@ impl ModuleInstance { pub fn with_externvals<'a, 'i, I: Iterator>( loaded_module: &'a Module, extern_vals: I, - tracer: Option>>, ) -> Result, Error> { let module = loaded_module.module(); - let module_ref = ModuleInstance::alloc_module(loaded_module, extern_vals, tracer.clone())?; - - if let Some(tracer) = tracer.clone() { - tracer.borrow_mut().register_module_instance(&module_ref); - } + let module_ref = ModuleInstance::alloc_module(loaded_module, extern_vals)?; for element_segment in module .elements_section() @@ -508,20 +480,6 @@ impl ModuleInstance { .func_by_index(*func_idx) .expect("Due to validation funcs from element segments should exists"); - if let Some(tracer) = tracer.clone() { - if !tracer.borrow().dry_run() { - let func_idx = tracer.borrow().lookup_function(&func); - let type_idx = tracer.borrow().lookup_type_of_func_ref(&func); - - tracer.borrow_mut().push_elem( - DEFAULT_TABLE_INDEX, - offset_val + j as u32, - func_idx as u32, - type_idx as u32, - ); - } - } - table_inst.set(offset_val + j as u32, Some(func))?; } } @@ -542,20 +500,6 @@ impl ModuleInstance { memory_inst.set(offset_val, data_segment.value())?; } - if let Some(tracer) = tracer { - let mut tracer = tracer.borrow_mut(); - - if !tracer.dry_run() { - for (globalidx, globalref) in module_ref.globals().iter().enumerate() { - tracer.push_global(globalidx as u32, globalref); - } - - if let Some(memory_ref) = module_ref.memory_by_index(DEFAULT_MEMORY_INDEX) { - tracer.push_init_memory(memory_ref) - } - } - } - Ok(NotStartedModuleRef { loaded_module, instance: module_ref, @@ -625,7 +569,6 @@ impl ModuleInstance { pub fn new<'m, I: ImportResolver>( loaded_module: &'m Module, imports: &I, - tracer: Option>>, ) -> Result, Error> { let module = loaded_module.module(); @@ -665,7 +608,7 @@ impl ModuleInstance { extern_vals.push(extern_val); } - let module_ref = Self::with_externvals(loaded_module, extern_vals.iter(), tracer.clone()); + let module_ref = Self::with_externvals(loaded_module, extern_vals.iter()); module_ref } @@ -733,17 +676,15 @@ impl ModuleInstance { func_name: &str, args: &[RuntimeValue], externals: &mut E, - tracer: Rc>, + monitor: &mut dyn Monitor, ) -> Result, Error> { - let func_instance = self.func_by_name(func_name)?; - { - let mut tracer = tracer.borrow_mut(); - - tracer.last_jump_eid.push(0); + monitor.invoke_exported_function_pre_hook(); } - FuncInstance::invoke_trace(&func_instance, args, externals, tracer).map_err(Error::Trap) + let func_instance = self.func_by_name(func_name)?; + + FuncInstance::invoke_trace(&func_instance, args, externals, monitor).map_err(Error::Trap) } /// Invoke exported function by a name using recycled stacks. @@ -807,8 +748,8 @@ impl ModuleInstance { /// [`assert_no_start`]: #method.assert_no_start /// [`not_started_instance`]: #method.not_started_instance pub struct NotStartedModuleRef<'a> { - loaded_module: &'a Module, - instance: ModuleRef, + pub loaded_module: &'a Module, + pub instance: ModuleRef, } impl<'a> NotStartedModuleRef<'a> { @@ -849,10 +790,10 @@ impl<'a> NotStartedModuleRef<'a> { pub fn run_start_tracer( self, state: &mut E, - tracer: Rc>, + monitor: &mut dyn Monitor, ) -> Result { { - tracer.borrow_mut().last_jump_eid.push(0); + monitor.invoke_exported_function_pre_hook(); } if let Some(start_fn_idx) = self.loaded_module.module().start_section() { @@ -860,7 +801,7 @@ impl<'a> NotStartedModuleRef<'a> { .instance .func_by_index(start_fn_idx) .expect("Due to validation start function should exists"); - FuncInstance::invoke_trace(&start_func, &[], state, tracer)?; + FuncInstance::invoke_trace(&start_func, &[], state, monitor)?; } Ok(self.instance) } @@ -904,15 +845,9 @@ impl<'a> NotStartedModuleRef<'a> { pub fn has_start(&self) -> bool { self.loaded_module.module().start_section().is_some() } - - pub fn lookup_function_by_name(&self, tracer: Rc>, func_name: &str) -> u32 { - let func_ref = self.instance.func_by_name(func_name).unwrap(); - - tracer.borrow().lookup_function(&func_ref) - } } -fn eval_init_expr(init_expr: &InitExpr, module: &ModuleInstance) -> RuntimeValue { +pub fn eval_init_expr(init_expr: &InitExpr, module: &ModuleInstance) -> RuntimeValue { let code = init_expr.code(); debug_assert!( code.len() == 2, @@ -991,8 +926,7 @@ mod tests { (start $f)) "#, ); - let module = - ModuleInstance::new(&module_with_start, &ImportsBuilder::default(), None).unwrap(); + let module = ModuleInstance::new(&module_with_start, &ImportsBuilder::default()).unwrap(); assert!(!module.has_start()); module.assert_no_start(); } @@ -1014,7 +948,6 @@ mod tests { 0 ),)] .iter(), - None, ) .is_ok()); @@ -1025,15 +958,12 @@ mod tests { ExternVal::Func(FuncInstance::alloc_host(Signature::new(&[][..], None), 0)), ExternVal::Func(FuncInstance::alloc_host(Signature::new(&[][..], None), 1)), ] - .iter(), - None, + .iter() ) .is_err()); // externval vector is shorter than import count. - assert!( - ModuleInstance::with_externvals(&module_with_single_import, [].iter(), None).is_err() - ); + assert!(ModuleInstance::with_externvals(&module_with_single_import, [].iter(),).is_err()); // externval vector has an unexpected type. assert!(ModuleInstance::with_externvals( @@ -1043,7 +973,6 @@ mod tests { 0 ),)] .iter(), - None, ) .is_err()); } diff --git a/src/monitor/mod.rs b/src/monitor/mod.rs new file mode 100644 index 0000000000..56b45cc44c --- /dev/null +++ b/src/monitor/mod.rs @@ -0,0 +1,48 @@ +use parity_wasm::elements::Module; +use wasmi_core::Value; + +use crate::{ + isa::Instruction, + runner::{FunctionContext, InstructionOutcome, ValueStack}, + Error, + ModuleRef, +}; + +pub trait Monitor { + fn register_module( + &mut self, + _module: &Module, + _module_ref: &ModuleRef, + _entry: &str, + ) -> Result<(), Error> { + Ok(()) + } + + /// Called before each exported function(zkmain or start function) is executed. + fn invoke_exported_function_pre_hook(&mut self) {} + + /// Called before each instruction is executed. + fn invoke_instruction_pre_hook( + &mut self, + _value_stack: &ValueStack, + _function_context: &FunctionContext, + _instruction: &Instruction, + ) { + } + /// Called after each instruction is executed. + fn invoke_instruction_post_hook( + &mut self, + _fid: u32, + _iid: u32, + _sp: u32, + _allocated_memory_pages: u32, + _value_stack: &ValueStack, + _function_context: &FunctionContext, + _instruction: &Instruction, + _outcome: &InstructionOutcome, + ) { + } + + /// Called after 'call_host' instruction is executed. + fn invoke_call_host_post_hook(&mut self, _return_value: Option) {} +} diff --git a/src/runner.rs b/src/runner.rs index beafcd8c61..346589f05e 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -3,12 +3,12 @@ use crate::{ func::{FuncInstance, FuncInstanceInternal, FuncRef}, host::Externals, - isa::{self, DropKeep, Keep}, + isa::{self}, memory::MemoryRef, memory_units::Pages, module::ModuleRef, + monitor::Monitor, nan_preserving_float::{F32, F64}, - tracer::{etable::RunInstructionTracePre, Tracer}, value::{ ArithmeticOps, ExtendInto, @@ -26,16 +26,12 @@ use crate::{ ValueType, }; use alloc::{boxed::Box, vec::Vec}; -use core::{cell::RefCell, fmt, ops, u32, usize}; +use core::{fmt, ops, u32, usize}; use parity_wasm::elements::Local; use specs::{ - external_host_call_table::ExternalHostCallSignature, - itable::{BinOp, BitOp, RelOp, ShiftOp, UnaryOp}, - jtable::JumpTableEntry, - mtable::{MemoryReadSize, MemoryStoreSize, VarType}, - step::StepInfo, + mtable::{VarType}, }; -use std::rc::Rc; + use validation::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX}; /// Maximum number of bytes on the value stack. @@ -72,7 +68,7 @@ impl ValueInternal { } } -trait FromValueInternal +pub trait FromValueInternal where Self: Sized, { @@ -191,22 +187,21 @@ enum RunResult { } /// Function interpreter. -pub struct Interpreter { +pub struct Interpreter<'a> { value_stack: ValueStack, call_stack: CallStack, return_type: Option, state: InterpreterState, scratch: Vec, - pub(crate) tracer: Option>>, - mask_tracer: Vec, + pub(crate) monitor: Option<&'a mut dyn Monitor>, } -impl Interpreter { +impl<'m> Interpreter<'m> { pub fn new( func: &FuncRef, args: &[RuntimeValue], mut stack_recycler: Option<&mut StackRecycler>, - ) -> Result { + ) -> Result, Trap> { let mut value_stack = StackRecycler::recreate_value_stack(&mut stack_recycler); for &arg in args { let arg = arg.into(); @@ -229,54 +224,10 @@ impl Interpreter { return_type, state: InterpreterState::Initialized, scratch: Vec::new(), - tracer: None, - mask_tracer: vec![], + monitor: None, }) } - fn get_tracer_if_active(&self) -> Option>> { - if let Some(tracer) = &self.tracer { - if !tracer.borrow().dry_run() && self.mask_tracer.is_empty() { - self.tracer.clone() - } else { - None - } - } else { - None - } - } - - fn inc_trace_counter(&self) { - if !self.mask_tracer.is_empty() { - return; - } - if let Some(tracer) = &self.tracer { - tracer.borrow_mut().inc_counter(); - } - } - - fn push_phantom_frame(&mut self, sp: u32) { - if self.mask_tracer.is_empty() { - self.tracer - .as_ref() - .map(|tracer| tracer.borrow_mut().set_in_phantom()); - } - - self.mask_tracer.push(sp); - } - - fn pop_phantom_frame(&mut self) -> Option { - let r = self.mask_tracer.pop(); - - if self.mask_tracer.is_empty() { - self.tracer - .as_ref() - .map(|tracer| tracer.borrow_mut().set_exit_phantom()); - } - - r - } - pub fn state(&self) -> &InterpreterState { &self.state } @@ -373,35 +324,6 @@ impl Interpreter { FuncInstanceInternal::Internal { .. } => { let nested_context = FunctionContext::new(nested_func.clone()); - if let Some(tracer) = self.get_tracer_if_active() { - let mut tracer = tracer.borrow_mut(); - let callee_fid = tracer.lookup_function(&nested_func); - - let frame_id = tracer.etable.eid; - let last_jump_eid = tracer.last_jump_eid(); - let fid = tracer.lookup_function(&function_context.function); - let iid = function_context.position; - - tracer.jtable.push(JumpTableEntry { - eid: frame_id, - last_jump_eid, - callee_fid, - fid, - iid, - }); - - tracer.push_frame(); - } - - if let Some(tracer) = self.tracer.clone() { - if tracer - .borrow() - .is_phantom_function(&nested_context.function) - { - self.push_phantom_frame(self.value_stack.sp as u32); - } - } - self.call_stack.push(function_context); self.call_stack.push(nested_context); } @@ -443,54 +365,9 @@ impl Interpreter { .map_err(Trap::from)?; } - if let Some(return_val) = return_val { - if let Some(tracer) = self.get_tracer_if_active() { - let mut tracer = (*tracer).borrow_mut(); - - let entry = tracer.etable.entries_mut().last_mut().unwrap(); - - match &entry.step_info { - StepInfo::CallHost { - plugin, - host_function_idx, - function_name, - args, - ret_val, - signature, - op_index_in_plugin, - } => { - assert!(ret_val.is_none()); - entry.step_info = StepInfo::CallHost { - plugin: *plugin, - host_function_idx: *host_function_idx, - function_name: function_name.clone(), - args: args.clone(), - ret_val: Some(from_value_internal_to_u64_with_typ( - signature.return_type.unwrap().into(), - return_val.into(), - )), - signature: signature.clone(), - op_index_in_plugin: *op_index_in_plugin, - } - } - StepInfo::ExternalHostCall { op, sig, .. } => { - if let ExternalHostCallSignature::Return = sig { - entry.step_info = StepInfo::ExternalHostCall { - op: *op, - value: Some( - from_value_internal_to_u64_with_typ( - VarType::I64, - return_val.into(), - ), - ), - sig: *sig, - } - } - } - _ => unreachable!(), - } - } - } + self.monitor + .as_mut() + .map(|monitor| monitor.invoke_call_host_post_hook(return_val)); } } } @@ -498,1523 +375,6 @@ impl Interpreter { } } - fn run_instruction_pre( - &mut self, - function_context: &FunctionContext, - instructions: &isa::Instruction, - ) -> Option { - match *instructions { - isa::Instruction::GetLocal(..) => None, - isa::Instruction::SetLocal(depth, vtype) => { - let value = self.value_stack.top(); - Some(RunInstructionTracePre::SetLocal { - depth, - value: value.clone(), - vtype, - }) - } - isa::Instruction::TeeLocal(..) => None, - isa::Instruction::GetGlobal(..) => None, - isa::Instruction::SetGlobal(idx) => { - let value = self.value_stack.top(); - Some(RunInstructionTracePre::SetGlobal { - idx, - value: value.clone(), - }) - } - - isa::Instruction::Br(_) => None, - isa::Instruction::BrIfEqz(_) => Some(RunInstructionTracePre::BrIfEqz { - value: <_>::from_value_internal(*self.value_stack.top()), - }), - isa::Instruction::BrIfNez(_) => Some(RunInstructionTracePre::BrIfNez { - value: <_>::from_value_internal(*self.value_stack.top()), - }), - isa::Instruction::BrTable(_) => Some(RunInstructionTracePre::BrTable { - index: <_>::from_value_internal(*self.value_stack.top()), - }), - - isa::Instruction::Unreachable => None, - isa::Instruction::Return(..) => None, - - isa::Instruction::Call(func_idx) => { - let func = function_context - .module() - .func_by_index(func_idx) - .expect("Due to validation func should exists"); - - let mut args = vec![]; - let len = func.signature().params().len(); - - for i in 1..=len { - args.push(*self.value_stack.pick(i)); - } - - Some(RunInstructionTracePre::Call { args }) - } - isa::Instruction::CallIndirect(type_idx) => { - let table_idx = DEFAULT_TABLE_INDEX; - let offset = <_>::from_value_internal(*self.value_stack.top()); - - Some(RunInstructionTracePre::CallIndirect { - table_idx, - type_idx, - offset, - }) - } - - isa::Instruction::Drop => Some(RunInstructionTracePre::Drop), - isa::Instruction::Select(vtype) => Some(RunInstructionTracePre::Select { - cond: from_value_internal_to_u64_with_typ(VarType::I32, *self.value_stack.pick(1)), - val2: from_value_internal_to_u64_with_typ(vtype.into(), *self.value_stack.pick(2)), - val1: from_value_internal_to_u64_with_typ(vtype.into(), *self.value_stack.pick(3)), - }), - - isa::Instruction::I32Load(offset) - | isa::Instruction::I32Load8S(offset) - | isa::Instruction::I32Load8U(offset) - | isa::Instruction::I32Load16S(offset) - | isa::Instruction::I32Load16U(offset) => { - let load_size = match *instructions { - isa::Instruction::I32Load(..) => MemoryReadSize::U32, - isa::Instruction::I32Load8S(..) => MemoryReadSize::S8, - isa::Instruction::I32Load8U(..) => MemoryReadSize::U8, - isa::Instruction::I32Load16S(..) => MemoryReadSize::S16, - isa::Instruction::I32Load16U(..) => MemoryReadSize::U16, - _ => unreachable!(), - }; - - let raw_address = <_>::from_value_internal(*self.value_stack.top()); - let address = - effective_address(offset, raw_address).map_or(None, |addr| Some(addr)); - - Some(RunInstructionTracePre::Load { - offset, - raw_address, - effective_address: address, - vtype: parity_wasm::elements::ValueType::I32, - load_size, - }) - } - isa::Instruction::I64Load(offset) - | isa::Instruction::I64Load8S(offset) - | isa::Instruction::I64Load8U(offset) - | isa::Instruction::I64Load16S(offset) - | isa::Instruction::I64Load16U(offset) - | isa::Instruction::I64Load32S(offset) - | isa::Instruction::I64Load32U(offset) => { - let load_size = match *instructions { - isa::Instruction::I64Load(..) => MemoryReadSize::I64, - isa::Instruction::I64Load8S(..) => MemoryReadSize::S8, - isa::Instruction::I64Load8U(..) => MemoryReadSize::U8, - isa::Instruction::I64Load16S(..) => MemoryReadSize::S16, - isa::Instruction::I64Load16U(..) => MemoryReadSize::U16, - isa::Instruction::I64Load32S(..) => MemoryReadSize::S32, - isa::Instruction::I64Load32U(..) => MemoryReadSize::U32, - _ => unreachable!(), - }; - let raw_address = <_>::from_value_internal(*self.value_stack.top()); - let address = - effective_address(offset, raw_address).map_or(None, |addr| Some(addr)); - - Some(RunInstructionTracePre::Load { - offset, - raw_address, - effective_address: address, - vtype: parity_wasm::elements::ValueType::I64, - load_size, - }) - } - isa::Instruction::I32Store(offset) - | isa::Instruction::I32Store8(offset) - | isa::Instruction::I32Store16(offset) => { - let store_size = match *instructions { - isa::Instruction::I32Store8(_) => MemoryStoreSize::Byte8, - isa::Instruction::I32Store16(_) => MemoryStoreSize::Byte16, - isa::Instruction::I32Store(_) => MemoryStoreSize::Byte32, - _ => unreachable!(), - }; - - let value: u32 = <_>::from_value_internal(*self.value_stack.pick(1)); - let raw_address = <_>::from_value_internal(*self.value_stack.pick(2)); - let address = - effective_address(offset, raw_address).map_or(None, |addr| Some(addr)); - - let pre_block_value1 = address.map(|address| { - let mut buf = [0u8; 8]; - function_context - .memory - .clone() - .unwrap() - .get_into(address / 8 * 8, &mut buf) - .unwrap(); - u64::from_le_bytes(buf) - }); - - let pre_block_value2 = address - .map(|address| { - if store_size.byte_size() as u32 + address % 8 > 8 { - let mut buf = [0u8; 8]; - function_context - .memory - .clone() - .unwrap() - .get_into((address / 8 + 1) * 8, &mut buf) - .unwrap(); - Some(u64::from_le_bytes(buf)) - } else { - None - } - }) - .flatten(); - - Some(RunInstructionTracePre::Store { - offset, - raw_address, - effective_address: address, - value: value as u64, - vtype: parity_wasm::elements::ValueType::I32, - store_size, - pre_block_value1, - pre_block_value2, - }) - } - isa::Instruction::I64Store(offset) - | isa::Instruction::I64Store8(offset) - | isa::Instruction::I64Store16(offset) - | isa::Instruction::I64Store32(offset) => { - let store_size = match *instructions { - isa::Instruction::I64Store(..) => MemoryStoreSize::Byte64, - isa::Instruction::I64Store8(..) => MemoryStoreSize::Byte8, - isa::Instruction::I64Store16(..) => MemoryStoreSize::Byte16, - isa::Instruction::I64Store32(..) => MemoryStoreSize::Byte32, - _ => unreachable!(), - }; - - let value = <_>::from_value_internal(*self.value_stack.pick(1)); - let raw_address = <_>::from_value_internal(*self.value_stack.pick(2)); - let address = - effective_address(offset, raw_address).map_or(None, |addr| Some(addr)); - - let pre_block_value1 = address.map(|address| { - let mut buf = [0u8; 8]; - function_context - .memory - .clone() - .unwrap() - .get_into(address / 8 * 8, &mut buf) - .unwrap(); - u64::from_le_bytes(buf) - }); - - let pre_block_value2 = address - .map(|address| { - if store_size.byte_size() as u32 + address % 8 > 8 { - let mut buf = [0u8; 8]; - function_context - .memory - .clone() - .unwrap() - .get_into((address / 8 + 1) * 8, &mut buf) - .unwrap(); - Some(u64::from_le_bytes(buf)) - } else { - None - } - }) - .flatten(); - - Some(RunInstructionTracePre::Store { - offset, - raw_address, - effective_address: address, - value, - vtype: parity_wasm::elements::ValueType::I64, - store_size, - pre_block_value1, - pre_block_value2, - }) - } - - isa::Instruction::CurrentMemory => None, - isa::Instruction::GrowMemory => Some(RunInstructionTracePre::GrowMemory( - <_>::from_value_internal(*self.value_stack.pick(1)), - )), - - isa::Instruction::I32Const(_) => None, - isa::Instruction::I64Const(_) => None, - - isa::Instruction::I32Eqz => Some(RunInstructionTracePre::I32Single( - <_>::from_value_internal(*self.value_stack.pick(1)), - )), - isa::Instruction::I64Eqz => Some(RunInstructionTracePre::I64Single( - <_>::from_value_internal(*self.value_stack.pick(1)), - )), - - isa::Instruction::I32Eq - | isa::Instruction::I32Ne - | isa::Instruction::I32GtS - | isa::Instruction::I32GtU - | isa::Instruction::I32GeS - | isa::Instruction::I32GeU - | isa::Instruction::I32LtU - | isa::Instruction::I32LeU - | isa::Instruction::I32LtS - | isa::Instruction::I32LeS => Some(RunInstructionTracePre::I32Comp { - left: <_>::from_value_internal(*self.value_stack.pick(2)), - right: <_>::from_value_internal(*self.value_stack.pick(1)), - }), - - isa::Instruction::I64Eq - | isa::Instruction::I64Ne - | isa::Instruction::I64GtS - | isa::Instruction::I64GtU - | isa::Instruction::I64GeS - | isa::Instruction::I64GeU - | isa::Instruction::I64LtU - | isa::Instruction::I64LeU - | isa::Instruction::I64LtS - | isa::Instruction::I64LeS => Some(RunInstructionTracePre::I64Comp { - left: <_>::from_value_internal(*self.value_stack.pick(2)), - right: <_>::from_value_internal(*self.value_stack.pick(1)), - }), - - isa::Instruction::I32Add - | isa::Instruction::I32Sub - | isa::Instruction::I32Mul - | isa::Instruction::I32DivS - | isa::Instruction::I32DivU - | isa::Instruction::I32RemS - | isa::Instruction::I32RemU - | isa::Instruction::I32Shl - | isa::Instruction::I32ShrU - | isa::Instruction::I32ShrS - | isa::Instruction::I32And - | isa::Instruction::I32Or - | isa::Instruction::I32Xor - | isa::Instruction::I32Rotl - | isa::Instruction::I32Rotr => Some(RunInstructionTracePre::I32BinOp { - left: <_>::from_value_internal(*self.value_stack.pick(2)), - right: <_>::from_value_internal(*self.value_stack.pick(1)), - }), - - isa::Instruction::I64Add - | isa::Instruction::I64Sub - | isa::Instruction::I64Mul - | isa::Instruction::I64DivS - | isa::Instruction::I64DivU - | isa::Instruction::I64RemS - | isa::Instruction::I64RemU - | isa::Instruction::I64Shl - | isa::Instruction::I64ShrU - | isa::Instruction::I64ShrS - | isa::Instruction::I64And - | isa::Instruction::I64Or - | isa::Instruction::I64Xor - | isa::Instruction::I64Rotl - | isa::Instruction::I64Rotr => Some(RunInstructionTracePre::I64BinOp { - left: <_>::from_value_internal(*self.value_stack.pick(2)), - right: <_>::from_value_internal(*self.value_stack.pick(1)), - }), - - isa::Instruction::I32Ctz | isa::Instruction::I32Clz | isa::Instruction::I32Popcnt => { - Some(RunInstructionTracePre::UnaryOp { - operand: from_value_internal_to_u64_with_typ( - VarType::I32, - *self.value_stack.pick(1), - ), - vtype: VarType::I32, - }) - } - isa::Instruction::I64Ctz | isa::Instruction::I64Clz | isa::Instruction::I64Popcnt => { - Some(RunInstructionTracePre::UnaryOp { - operand: from_value_internal_to_u64_with_typ( - VarType::I64, - *self.value_stack.pick(1), - ), - vtype: VarType::I64, - }) - } - - isa::Instruction::I32WrapI64 => Some(RunInstructionTracePre::I32WrapI64 { - value: <_>::from_value_internal(*self.value_stack.pick(1)), - }), - isa::Instruction::I64ExtendUI32 => Some(RunInstructionTracePre::I64ExtendI32 { - value: <_>::from_value_internal(*self.value_stack.pick(1)), - sign: false, - }), - isa::Instruction::I64ExtendSI32 => Some(RunInstructionTracePre::I64ExtendI32 { - value: <_>::from_value_internal(*self.value_stack.pick(1)), - sign: true, - }), - isa::Instruction::I32Extend8S => Some(RunInstructionTracePre::I32SignExtendI8 { - value: <_>::from_value_internal(*self.value_stack.pick(1)), - }), - isa::Instruction::I32Extend16S => Some(RunInstructionTracePre::I32SignExtendI16 { - value: <_>::from_value_internal(*self.value_stack.pick(1)), - }), - isa::Instruction::I64Extend8S => Some(RunInstructionTracePre::I64SignExtendI8 { - value: <_>::from_value_internal(*self.value_stack.pick(1)), - }), - isa::Instruction::I64Extend16S => Some(RunInstructionTracePre::I64SignExtendI16 { - value: <_>::from_value_internal(*self.value_stack.pick(1)), - }), - isa::Instruction::I64Extend32S => Some(RunInstructionTracePre::I64SignExtendI32 { - value: <_>::from_value_internal(*self.value_stack.pick(1)), - }), - - _ => { - println!("{:?}", *instructions); - unimplemented!() - } - } - } - - fn run_instruction_post( - &mut self, - pre_status: Option, - context: &FunctionContext, - instructions: &isa::Instruction, - ) -> StepInfo { - match *instructions { - isa::Instruction::GetLocal(depth, vtype) => StepInfo::GetLocal { - depth, - value: from_value_internal_to_u64_with_typ(vtype.into(), *self.value_stack.top()), - vtype: vtype.into(), - }, - isa::Instruction::SetLocal(..) => { - if let RunInstructionTracePre::SetLocal { - depth, - value, - vtype, - } = pre_status.unwrap() - { - StepInfo::SetLocal { - depth, - value: from_value_internal_to_u64_with_typ(vtype.into(), value), - vtype: vtype.into(), - } - } else { - unreachable!() - } - } - isa::Instruction::TeeLocal(depth, vtype) => StepInfo::TeeLocal { - depth, - value: from_value_internal_to_u64_with_typ(vtype.into(), *self.value_stack.top()), - vtype: vtype.into(), - }, - isa::Instruction::GetGlobal(idx) => { - let global_ref = context.module().global_by_index(idx).unwrap(); - let is_mutable = global_ref.is_mutable(); - let vtype: VarType = global_ref.value_type().into_elements().into(); - let value = from_value_internal_to_u64_with_typ( - vtype.into(), - ValueInternal::from(global_ref.get()), - ); - - StepInfo::GetGlobal { - idx, - vtype, - is_mutable, - value, - } - } - isa::Instruction::SetGlobal(idx) => { - let global_ref = context.module().global_by_index(idx).unwrap(); - let is_mutable = global_ref.is_mutable(); - let vtype: VarType = global_ref.value_type().into_elements().into(); - let value = from_value_internal_to_u64_with_typ( - vtype.into(), - ValueInternal::from(global_ref.get()), - ); - - StepInfo::SetGlobal { - idx, - vtype, - is_mutable, - value, - } - } - - isa::Instruction::Br(target) => StepInfo::Br { - dst_pc: target.dst_pc, - drop: target.drop_keep.drop, - keep: if let Keep::Single(t) = target.drop_keep.keep { - vec![t.into()] - } else { - vec![] - }, - keep_values: match target.drop_keep.keep { - Keep::Single(t) => vec![from_value_internal_to_u64_with_typ( - t.into(), - *self.value_stack.top(), - )], - Keep::None => vec![], - }, - }, - isa::Instruction::BrIfEqz(target) => { - if let RunInstructionTracePre::BrIfEqz { value } = pre_status.unwrap() { - StepInfo::BrIfEqz { - condition: value, - dst_pc: target.dst_pc, - drop: target.drop_keep.drop, - keep: if let Keep::Single(t) = target.drop_keep.keep { - vec![t.into()] - } else { - vec![] - }, - keep_values: match target.drop_keep.keep { - Keep::Single(t) => vec![from_value_internal_to_u64_with_typ( - t.into(), - *self.value_stack.top(), - )], - Keep::None => vec![], - }, - } - } else { - unreachable!() - } - } - isa::Instruction::BrIfNez(target) => { - if let RunInstructionTracePre::BrIfNez { value } = pre_status.unwrap() { - StepInfo::BrIfNez { - condition: value, - dst_pc: target.dst_pc, - drop: target.drop_keep.drop, - keep: if let Keep::Single(t) = target.drop_keep.keep { - vec![t.into()] - } else { - vec![] - }, - keep_values: match target.drop_keep.keep { - Keep::Single(t) => vec![from_value_internal_to_u64_with_typ( - t.into(), - *self.value_stack.top(), - )], - Keep::None => vec![], - }, - } - } else { - unreachable!() - } - } - isa::Instruction::BrTable(targets) => { - if let RunInstructionTracePre::BrTable { index } = pre_status.unwrap() { - StepInfo::BrTable { - index, - dst_pc: targets.get(index as u32).dst_pc, - drop: targets.get(index as u32).drop_keep.drop, - keep: if let Keep::Single(t) = targets.get(index as u32).drop_keep.keep { - vec![t.into()] - } else { - vec![] - }, - keep_values: match targets.get(index as u32).drop_keep.keep { - Keep::Single(t) => vec![from_value_internal_to_u64_with_typ( - t.into(), - *self.value_stack.top(), - )], - Keep::None => vec![], - }, - } - } else { - unreachable!() - } - } - - isa::Instruction::Return(DropKeep { drop, keep }) => { - let mut drop_values = vec![]; - - for i in 1..=drop { - drop_values.push(*self.value_stack.pick(i as usize)); - } - - StepInfo::Return { - drop, - keep: if let Keep::Single(t) = keep { - vec![t.into()] - } else { - vec![] - }, - keep_values: match keep { - Keep::Single(t) => vec![from_value_internal_to_u64_with_typ( - t.into(), - *self.value_stack.top(), - )], - Keep::None => vec![], - }, - } - } - - isa::Instruction::Drop => { - if let RunInstructionTracePre::Drop = pre_status.unwrap() { - StepInfo::Drop - } else { - unreachable!() - } - } - isa::Instruction::Select(vtype) => { - if let RunInstructionTracePre::Select { val1, val2, cond } = pre_status.unwrap() { - StepInfo::Select { - val1, - val2, - cond, - result: from_value_internal_to_u64_with_typ( - vtype.into(), - *self.value_stack.top(), - ), - vtype: vtype.into(), - } - } else { - unreachable!() - } - } - - isa::Instruction::Call(index) => { - if let RunInstructionTracePre::Call { args: _ } = pre_status.unwrap() { - let tracer = self.tracer.clone().unwrap(); - let tracer = tracer.borrow(); - - let desc = tracer.function_desc.get(&index).unwrap(); - - match &desc.ftype { - specs::types::FunctionType::WasmFunction => StepInfo::Call { index }, - specs::types::FunctionType::HostFunction { - plugin, - function_index: host_function_idx, - function_name, - op_index_in_plugin, - } => { - let params_len = desc.signature.params().len(); - let mut args: Vec = vec![]; - let signature: specs::host_function::Signature = - desc.signature.clone().into(); - let params = signature.params.clone(); - - for i in 0..params_len { - args.push(from_value_internal_to_u64_with_typ( - (params[i]).into(), - *self.value_stack.pick(params_len - i), - )); - } - StepInfo::CallHost { - plugin: *plugin, - host_function_idx: *host_function_idx, - function_name: function_name.clone(), - args, - ret_val: None, - signature, - op_index_in_plugin: *op_index_in_plugin, - } - } - specs::types::FunctionType::HostFunctionExternal { op, sig, .. } => { - StepInfo::ExternalHostCall { - op: *op, - value: match sig { - ExternalHostCallSignature::Argument => { - Some(from_value_internal_to_u64_with_typ( - VarType::I64, - *self.value_stack.top(), - )) - } - ExternalHostCallSignature::Return => None, - }, - sig: *sig, - } - } - } - } else { - unreachable!() - } - } - isa::Instruction::CallIndirect(_) => { - if let RunInstructionTracePre::CallIndirect { - table_idx, - type_idx, - offset, - } = pre_status.unwrap() - { - let tracer = self.tracer.clone().unwrap(); - let tracer = tracer.borrow(); - - let table = context - .module() - .table_by_index(DEFAULT_TABLE_INDEX) - .unwrap(); - let func_ref = table.get(offset).unwrap().unwrap(); - - let func_idx = tracer.lookup_function(&func_ref); - - StepInfo::CallIndirect { - table_index: table_idx, - type_index: type_idx, - offset, - func_index: func_idx, - } - } else { - unreachable!() - } - } - - isa::Instruction::I32Load(..) - | isa::Instruction::I32Load8U(..) - | isa::Instruction::I32Load8S(..) - | isa::Instruction::I32Load16U(..) - | isa::Instruction::I32Load16S(..) - | isa::Instruction::I64Load(..) - | isa::Instruction::I64Load8U(..) - | isa::Instruction::I64Load8S(..) - | isa::Instruction::I64Load16U(..) - | isa::Instruction::I64Load16S(..) - | isa::Instruction::I64Load32U(..) - | isa::Instruction::I64Load32S(..) => { - if let RunInstructionTracePre::Load { - offset, - raw_address, - effective_address, - vtype, - load_size, - } = pre_status.unwrap() - { - let block_value1 = { - let mut buf = [0u8; 8]; - context - .memory - .clone() - .unwrap() - .get_into(effective_address.unwrap() / 8 * 8, &mut buf) - .unwrap(); - u64::from_le_bytes(buf) - }; - - let block_value2 = - if effective_address.unwrap() % 8 + load_size.byte_size() as u32 > 8 { - let mut buf = [0u8; 8]; - context - .memory - .clone() - .unwrap() - .get_into((effective_address.unwrap() / 8 + 1) * 8, &mut buf) - .unwrap(); - u64::from_le_bytes(buf) - } else { - 0 - }; - - StepInfo::Load { - vtype: vtype.into(), - load_size, - offset, - raw_address, - effective_address: effective_address.unwrap(), - value: from_value_internal_to_u64_with_typ( - vtype.into(), - *self.value_stack.top(), - ), - block_value1, - block_value2, - } - } else { - unreachable!() - } - } - isa::Instruction::I32Store(..) - | isa::Instruction::I32Store8(..) - | isa::Instruction::I32Store16(..) - | isa::Instruction::I64Store(..) - | isa::Instruction::I64Store8(..) - | isa::Instruction::I64Store16(..) - | isa::Instruction::I64Store32(..) => { - if let RunInstructionTracePre::Store { - offset, - raw_address, - effective_address, - value, - vtype, - store_size, - pre_block_value1, - pre_block_value2, - } = pre_status.unwrap() - { - let updated_block_value1 = { - let mut buf = [0u8; 8]; - context - .memory - .clone() - .unwrap() - .get_into(effective_address.unwrap() / 8 * 8, &mut buf) - .unwrap(); - u64::from_le_bytes(buf) - }; - - let updated_block_value2 = - if effective_address.unwrap() % 8 + store_size.byte_size() as u32 > 8 { - let mut buf = [0u8; 8]; - context - .memory - .clone() - .unwrap() - .get_into((effective_address.unwrap() / 8 + 1) * 8, &mut buf) - .unwrap(); - u64::from_le_bytes(buf) - } else { - 0 - }; - - StepInfo::Store { - vtype: vtype.into(), - store_size, - offset, - raw_address, - effective_address: effective_address.unwrap(), - value: value as u64, - pre_block_value1: pre_block_value1.unwrap(), - pre_block_value2: pre_block_value2.unwrap_or(0u64), - updated_block_value1, - updated_block_value2, - } - } else { - unreachable!() - } - } - - isa::Instruction::CurrentMemory => StepInfo::MemorySize, - isa::Instruction::GrowMemory => { - if let RunInstructionTracePre::GrowMemory(grow_size) = pre_status.unwrap() { - StepInfo::MemoryGrow { - grow_size, - result: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - - isa::Instruction::I32Const(value) => StepInfo::I32Const { value }, - isa::Instruction::I64Const(value) => StepInfo::I64Const { value }, - - isa::Instruction::I32Eqz => { - if let RunInstructionTracePre::I32Single(value) = pre_status.unwrap() { - StepInfo::Test { - vtype: VarType::I32, - value: value as u32 as u64, - result: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I32Eq => { - if let RunInstructionTracePre::I32Comp { left, right } = pre_status.unwrap() { - StepInfo::I32Comp { - class: RelOp::Eq, - left, - right, - value: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I32Ne => { - if let RunInstructionTracePre::I32Comp { left, right } = pre_status.unwrap() { - StepInfo::I32Comp { - class: RelOp::Ne, - left, - right, - value: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I32GtS => { - if let RunInstructionTracePre::I32Comp { left, right } = pre_status.unwrap() { - StepInfo::I32Comp { - class: RelOp::SignedGt, - left, - right, - value: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I32GtU => { - if let RunInstructionTracePre::I32Comp { left, right } = pre_status.unwrap() { - StepInfo::I32Comp { - class: RelOp::UnsignedGt, - left, - right, - value: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I32GeS => { - if let RunInstructionTracePre::I32Comp { left, right } = pre_status.unwrap() { - StepInfo::I32Comp { - class: RelOp::SignedGe, - left, - right, - value: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I32GeU => { - if let RunInstructionTracePre::I32Comp { left, right } = pre_status.unwrap() { - StepInfo::I32Comp { - class: RelOp::UnsignedGe, - left, - right, - value: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I32LtS => { - if let RunInstructionTracePre::I32Comp { left, right } = pre_status.unwrap() { - StepInfo::I32Comp { - class: RelOp::SignedLt, - left, - right, - value: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I32LtU => { - if let RunInstructionTracePre::I32Comp { left, right } = pre_status.unwrap() { - StepInfo::I32Comp { - class: RelOp::UnsignedLt, - left, - right, - value: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I32LeS => { - if let RunInstructionTracePre::I32Comp { left, right } = pre_status.unwrap() { - StepInfo::I32Comp { - class: RelOp::SignedLe, - left, - right, - value: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I32LeU => { - if let RunInstructionTracePre::I32Comp { left, right } = pre_status.unwrap() { - StepInfo::I32Comp { - class: RelOp::UnsignedLe, - left, - right, - value: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - - isa::Instruction::I64Eqz => { - if let RunInstructionTracePre::I64Single(value) = pre_status.unwrap() { - StepInfo::Test { - vtype: VarType::I64, - value: value as u64, - result: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I64Eq => { - if let RunInstructionTracePre::I64Comp { left, right } = pre_status.unwrap() { - StepInfo::I64Comp { - class: RelOp::Eq, - left, - right, - value: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I64Ne => { - if let RunInstructionTracePre::I64Comp { left, right } = pre_status.unwrap() { - StepInfo::I64Comp { - class: RelOp::Ne, - left, - right, - value: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I64GtS => { - if let RunInstructionTracePre::I64Comp { left, right } = pre_status.unwrap() { - StepInfo::I64Comp { - class: RelOp::SignedGt, - left, - right, - value: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I64GtU => { - if let RunInstructionTracePre::I64Comp { left, right } = pre_status.unwrap() { - StepInfo::I64Comp { - class: RelOp::UnsignedGt, - left, - right, - value: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I64LtU => { - if let RunInstructionTracePre::I64Comp { left, right } = pre_status.unwrap() { - StepInfo::I64Comp { - class: RelOp::UnsignedLt, - left, - right, - value: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I64LtS => { - if let RunInstructionTracePre::I64Comp { left, right } = pre_status.unwrap() { - StepInfo::I64Comp { - class: RelOp::SignedLt, - left, - right, - value: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I64LeU => { - if let RunInstructionTracePre::I64Comp { left, right } = pre_status.unwrap() { - StepInfo::I64Comp { - class: RelOp::UnsignedLe, - left, - right, - value: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I64LeS => { - if let RunInstructionTracePre::I64Comp { left, right } = pre_status.unwrap() { - StepInfo::I64Comp { - class: RelOp::SignedLe, - left, - right, - value: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I64GeU => { - if let RunInstructionTracePre::I64Comp { left, right } = pre_status.unwrap() { - StepInfo::I64Comp { - class: RelOp::UnsignedGe, - left, - right, - value: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I64GeS => { - if let RunInstructionTracePre::I64Comp { left, right } = pre_status.unwrap() { - StepInfo::I64Comp { - class: RelOp::SignedGe, - left, - right, - value: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - - isa::Instruction::I32Add => { - if let RunInstructionTracePre::I32BinOp { left, right } = pre_status.unwrap() { - StepInfo::I32BinOp { - class: BinOp::Add, - left, - right, - value: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I32Sub => { - if let RunInstructionTracePre::I32BinOp { left, right } = pre_status.unwrap() { - StepInfo::I32BinOp { - class: BinOp::Sub, - left, - right, - value: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I32Mul => { - if let RunInstructionTracePre::I32BinOp { left, right } = pre_status.unwrap() { - StepInfo::I32BinOp { - class: BinOp::Mul, - left, - right, - value: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I32DivU => { - if let RunInstructionTracePre::I32BinOp { left, right } = pre_status.unwrap() { - StepInfo::I32BinOp { - class: BinOp::UnsignedDiv, - left, - right, - value: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I32RemU => { - if let RunInstructionTracePre::I32BinOp { left, right } = pre_status.unwrap() { - StepInfo::I32BinOp { - class: BinOp::UnsignedRem, - left, - right, - value: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I32DivS => { - if let RunInstructionTracePre::I32BinOp { left, right } = pre_status.unwrap() { - StepInfo::I32BinOp { - class: BinOp::SignedDiv, - left, - right, - value: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I32RemS => { - if let RunInstructionTracePre::I32BinOp { left, right } = pre_status.unwrap() { - StepInfo::I32BinOp { - class: BinOp::SignedRem, - left, - right, - value: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I32And => { - if let RunInstructionTracePre::I32BinOp { left, right } = pre_status.unwrap() { - StepInfo::I32BinBitOp { - class: BitOp::And, - left, - right, - value: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I32Or => { - if let RunInstructionTracePre::I32BinOp { left, right } = pre_status.unwrap() { - StepInfo::I32BinBitOp { - class: BitOp::Or, - left, - right, - value: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I32Xor => { - if let RunInstructionTracePre::I32BinOp { left, right } = pre_status.unwrap() { - StepInfo::I32BinBitOp { - class: BitOp::Xor, - left, - right, - value: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I32Shl => { - if let RunInstructionTracePre::I32BinOp { left, right } = pre_status.unwrap() { - StepInfo::I32BinShiftOp { - class: ShiftOp::Shl, - left, - right, - value: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I32ShrU => { - if let RunInstructionTracePre::I32BinOp { left, right } = pre_status.unwrap() { - StepInfo::I32BinShiftOp { - class: ShiftOp::UnsignedShr, - left, - right, - value: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I32ShrS => { - if let RunInstructionTracePre::I32BinOp { left, right } = pre_status.unwrap() { - StepInfo::I32BinShiftOp { - class: ShiftOp::SignedShr, - left, - right, - value: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I32Rotl => { - if let RunInstructionTracePre::I32BinOp { left, right } = pre_status.unwrap() { - StepInfo::I32BinShiftOp { - class: ShiftOp::Rotl, - left, - right, - value: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I32Rotr => { - if let RunInstructionTracePre::I32BinOp { left, right } = pre_status.unwrap() { - StepInfo::I32BinShiftOp { - class: ShiftOp::Rotr, - left, - right, - value: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I64Add => { - if let RunInstructionTracePre::I64BinOp { left, right } = pre_status.unwrap() { - StepInfo::I64BinOp { - class: BinOp::Add, - left, - right, - value: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I64Sub => { - if let RunInstructionTracePre::I64BinOp { left, right } = pre_status.unwrap() { - StepInfo::I64BinOp { - class: BinOp::Sub, - left, - right, - value: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I64Mul => { - if let RunInstructionTracePre::I64BinOp { left, right } = pre_status.unwrap() { - StepInfo::I64BinOp { - class: BinOp::Mul, - left, - right, - value: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I64DivU => { - if let RunInstructionTracePre::I64BinOp { left, right } = pre_status.unwrap() { - StepInfo::I64BinOp { - class: BinOp::UnsignedDiv, - left, - right, - value: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I64RemU => { - if let RunInstructionTracePre::I64BinOp { left, right } = pre_status.unwrap() { - StepInfo::I64BinOp { - class: BinOp::UnsignedRem, - left, - right, - value: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I64DivS => { - if let RunInstructionTracePre::I64BinOp { left, right } = pre_status.unwrap() { - StepInfo::I64BinOp { - class: BinOp::SignedDiv, - left, - right, - value: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I64RemS => { - if let RunInstructionTracePre::I64BinOp { left, right } = pre_status.unwrap() { - StepInfo::I64BinOp { - class: BinOp::SignedRem, - left, - right, - value: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I64And => { - if let RunInstructionTracePre::I64BinOp { left, right } = pre_status.unwrap() { - StepInfo::I64BinBitOp { - class: BitOp::And, - left, - right, - value: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I64Or => { - if let RunInstructionTracePre::I64BinOp { left, right } = pre_status.unwrap() { - StepInfo::I64BinBitOp { - class: BitOp::Or, - left, - right, - value: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I64Xor => { - if let RunInstructionTracePre::I64BinOp { left, right } = pre_status.unwrap() { - StepInfo::I64BinBitOp { - class: BitOp::Xor, - left, - right, - value: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I64Shl => { - if let RunInstructionTracePre::I64BinOp { left, right } = pre_status.unwrap() { - StepInfo::I64BinShiftOp { - class: ShiftOp::Shl, - left, - right, - value: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I64ShrU => { - if let RunInstructionTracePre::I64BinOp { left, right } = pre_status.unwrap() { - StepInfo::I64BinShiftOp { - class: ShiftOp::UnsignedShr, - left, - right, - value: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I64ShrS => { - if let RunInstructionTracePre::I64BinOp { left, right } = pre_status.unwrap() { - StepInfo::I64BinShiftOp { - class: ShiftOp::SignedShr, - left, - right, - value: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I64Rotl => { - if let RunInstructionTracePre::I64BinOp { left, right } = pre_status.unwrap() { - StepInfo::I64BinShiftOp { - class: ShiftOp::Rotl, - left, - right, - value: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I64Rotr => { - if let RunInstructionTracePre::I64BinOp { left, right } = pre_status.unwrap() { - StepInfo::I64BinShiftOp { - class: ShiftOp::Rotr, - left, - right, - value: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - - isa::Instruction::I32Ctz - | isa::Instruction::I32Clz - | isa::Instruction::I32Popcnt - | isa::Instruction::I64Ctz - | isa::Instruction::I64Clz - | isa::Instruction::I64Popcnt => { - if let RunInstructionTracePre::UnaryOp { operand, vtype } = pre_status.unwrap() { - StepInfo::UnaryOp { - class: UnaryOp::from(instructions.clone()), - vtype, - operand, - result: from_value_internal_to_u64_with_typ(vtype, *self.value_stack.top()), - } - } else { - unreachable!() - } - } - - isa::Instruction::I32WrapI64 => { - if let RunInstructionTracePre::I32WrapI64 { value } = pre_status.unwrap() { - StepInfo::I32WrapI64 { - value, - result: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I64ExtendSI32 | isa::Instruction::I64ExtendUI32 => { - if let RunInstructionTracePre::I64ExtendI32 { value, sign } = pre_status.unwrap() { - StepInfo::I64ExtendI32 { - value, - result: <_>::from_value_internal(*self.value_stack.top()), - sign, - } - } else { - unreachable!() - } - } - isa::Instruction::I32Extend8S => { - if let RunInstructionTracePre::I32SignExtendI8 { value } = pre_status.unwrap() { - StepInfo::I32SignExtendI8 { - value, - result: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I32Extend16S => { - if let RunInstructionTracePre::I32SignExtendI16 { value } = pre_status.unwrap() { - StepInfo::I32SignExtendI16 { - value, - result: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I64Extend8S => { - if let RunInstructionTracePre::I64SignExtendI8 { value } = pre_status.unwrap() { - StepInfo::I64SignExtendI8 { - value, - result: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I64Extend16S => { - if let RunInstructionTracePre::I64SignExtendI16 { value } = pre_status.unwrap() { - StepInfo::I64SignExtendI16 { - value, - result: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - isa::Instruction::I64Extend32S => { - if let RunInstructionTracePre::I64SignExtendI32 { value } = pre_status.unwrap() { - StepInfo::I64SignExtendI32 { - value, - result: <_>::from_value_internal(*self.value_stack.top()), - } - } else { - unreachable!() - } - } - - _ => { - println!("{:?}", instructions); - unimplemented!() - } - } - } - fn do_run_function( &mut self, function_context: &mut FunctionContext, @@ -2031,8 +391,12 @@ impl Interpreter { return or an implicit block `end`.", ); - let pre_status = self.get_tracer_if_active().map_or(None, |_| { - self.run_instruction_pre(function_context, &instruction) + self.monitor.as_mut().map(|monitor| { + monitor.invoke_instruction_pre_hook( + &self.value_stack, + &function_context, + &instruction, + ) }); let current_memory = { @@ -2041,80 +405,34 @@ impl Interpreter { .map_or(0usize, |m| m.current_size().0) }; - macro_rules! trace_post { - () => {{ - self.inc_trace_counter(); - if let Some(tracer) = self.get_tracer_if_active() { - let post_status = - self.run_instruction_post(pre_status, function_context, &instruction); - - let mut tracer = tracer.borrow_mut(); + let outcome = self.run_instruction(function_context, &instruction)?; - let function = tracer.lookup_function(&function_context.function); - - let last_jump_eid = tracer.last_jump_eid(); - - tracer.etable.push( - function, - pc, - sp.try_into().unwrap(), - current_memory.try_into().unwrap(), - last_jump_eid, - post_status, - ); - } - }}; - } + self.monitor.as_mut().map(|monitor| { + monitor.invoke_instruction_post_hook( + function_context + .module + .func_index_by_func_ref(&function_context.function), + pc, + sp.try_into().unwrap(), + current_memory.try_into().unwrap(), + &self.value_stack, + &function_context, + &instruction, + &outcome, + ) + }); - match self.run_instruction(function_context, &instruction)? { - InstructionOutcome::RunNextInstruction => { - trace_post!(); - } + match outcome { + InstructionOutcome::RunNextInstruction => {} InstructionOutcome::Branch(target) => { - trace_post!(); iter = instructions.iterate_from(target.dst_pc); self.value_stack.drop_keep(target.drop_keep); } InstructionOutcome::ExecuteCall(func_ref) => { - // We don't record updated pc, the value should be recorded in the next trace log. - trace_post!(); - function_context.position = iter.position(); return Ok(RunResult::NestedCall(func_ref)); } InstructionOutcome::Return(drop_keep) => { - trace_post!(); - - if let Some(tracer) = self.tracer.clone() { - if tracer - .borrow() - .is_phantom_function(&function_context.function) - { - let sp_before = self.pop_phantom_frame().unwrap(); - - if self.mask_tracer.is_empty() { - tracer.borrow_mut().fill_trace( - sp_before, - current_memory as u32, - &function_context.function, - function_context.function.signature(), - if let isa::Keep::Single(t) = drop_keep.keep { - Some(from_value_internal_to_u64_with_typ( - t.into(), - *self.value_stack.top(), - )) - } else { - None - }, - ); - } - } - } - - if let Some(tracer) = self.get_tracer_if_active() { - tracer.borrow_mut().pop_frame(); - } - self.value_stack.drop_keep(drop_keep); break; } @@ -3011,7 +1329,7 @@ impl Interpreter { } /// Function execution context. -struct FunctionContext { +pub struct FunctionContext { /// Is context initialized. pub is_initialized: bool, /// Internal function reference. @@ -3077,7 +1395,7 @@ impl fmt::Debug for FunctionContext { } } -fn effective_address(address: u32, offset: u32) -> Result { +pub fn effective_address(address: u32, offset: u32) -> Result { match offset.checked_add(address) { None => Err(TrapCode::MemoryAccessOutOfBounds), Some(address) => Ok(address), @@ -3118,7 +1436,7 @@ pub fn check_function_args(signature: &Signature, args: &[RuntimeValue]) -> Resu Ok(()) } -struct ValueStack { +pub struct ValueStack { buf: Box<[ValueInternal]>, /// Index of the first free place in the stack. sp: usize, @@ -3174,11 +1492,11 @@ impl ValueStack { } #[inline] - fn top(&self) -> &ValueInternal { + pub fn top(&self) -> &ValueInternal { self.pick(1) } - fn pick(&self, depth: usize) -> &ValueInternal { + pub fn pick(&self, depth: usize) -> &ValueInternal { &self.buf[self.sp - depth] } @@ -3215,7 +1533,7 @@ impl ValueStack { } #[inline] - fn len(&self) -> usize { + pub fn len(&self) -> usize { self.sp } diff --git a/src/tracer/etable.rs b/src/tracer/etable.rs index 5d3e3f8b08..c6455b701e 100644 --- a/src/tracer/etable.rs +++ b/src/tracer/etable.rs @@ -8,117 +8,6 @@ use specs::{ use crate::{runner::ValueInternal, DEFAULT_VALUE_STACK_LIMIT}; -pub enum RunInstructionTracePre { - BrIfEqz { - value: i32, - }, - BrIfNez { - value: i32, - }, - BrTable { - index: i32, - }, - - Call { - args: Vec, - }, - CallIndirect { - table_idx: u32, - type_idx: u32, - offset: u32, - }, - - SetLocal { - depth: u32, - value: ValueInternal, - vtype: ValueType, - }, - SetGlobal { - idx: u32, - value: ValueInternal, - }, - - Load { - offset: u32, - raw_address: u32, - effective_address: Option, // use option in case of memory out of bound - vtype: ValueType, - load_size: MemoryReadSize, - }, - Store { - offset: u32, - raw_address: u32, - effective_address: Option, - value: u64, - vtype: ValueType, - store_size: MemoryStoreSize, - pre_block_value1: Option, - pre_block_value2: Option, - }, - - GrowMemory(i32), - - I32BinOp { - left: i32, - right: i32, - }, - I32BinShiftOp { - left: u64, - right: u64, - }, - - I64BinOp { - left: i64, - right: i64, - }, - - I32Single(i32), - I32Comp { - left: i32, - right: i32, - }, - I64Single(i64), - I64Comp { - left: i64, - right: i64, - }, - - I32WrapI64 { - value: i64, - }, - I64ExtendI32 { - value: i32, - sign: bool, - }, - I32SignExtendI8 { - value: i32, - }, - I32SignExtendI16 { - value: i32, - }, - I64SignExtendI8 { - value: i64, - }, - I64SignExtendI16 { - value: i64, - }, - I64SignExtendI32 { - value: i64, - }, - - UnaryOp { - operand: u64, - vtype: VarType, - }, - - Drop, - Select { - val1: u64, - val2: u64, - cond: u64, - }, -} - pub struct ETable { pub(crate) eid: u32, slices: Vec, diff --git a/src/tracer/mod.rs b/src/tracer/mod.rs index 13f2c12b2a..7e0897ea8d 100644 --- a/src/tracer/mod.rs +++ b/src/tracer/mod.rs @@ -1,32 +1,6 @@ -use std::collections::HashMap; +use specs::types::FunctionType; -use regex::Regex; -use specs::{ - brtable::{ElemEntry, ElemTable}, - configure_table::ConfigureTable, - host_function::HostFunctionDesc, - itable::InstructionTableInternal, - jtable::{JumpTable, StaticFrameEntry}, - mtable::VarType, - types::FunctionType, - TraceBackend, -}; - -use crate::{ - func::FuncInstanceInternal, - runner::{from_value_internal_to_u64_with_typ, ValueInternal}, - FuncRef, - GlobalRef, - MemoryRef, - ModuleRef, - Signature, -}; - -use self::{etable::ETable, imtable::IMTable, phantom::PhantomFunction}; - -pub mod etable; -pub mod imtable; -pub mod phantom; +use crate::Signature; #[derive(Debug)] pub struct FuncDesc { @@ -34,333 +8,8 @@ pub struct FuncDesc { pub signature: Signature, } -#[derive(Debug)] +#[derive(Debug, Default)] pub struct Observer { pub counter: usize, pub is_in_phantom: bool, } - -pub struct Tracer { - pub itable: InstructionTableInternal, - pub imtable: IMTable, - pub etable: ETable, - pub jtable: JumpTable, - pub elem_table: ElemTable, - pub configure_table: ConfigureTable, - type_of_func_ref: Vec<(FuncRef, u32)>, - function_lookup: HashMap, - pub(crate) function_lookup_name: HashMap, - pub(crate) last_jump_eid: Vec, - pub(crate) function_desc: HashMap, - pub host_function_index_lookup: HashMap, - pub static_jtable_entries: Vec, - pub phantom_functions: Vec, - pub phantom_functions_ref: Vec, - // Wasm Image Function Idx - pub wasm_input_func_idx: Option, - pub wasm_input_func_ref: Option, - dry_run: bool, - - pub observer: Observer, -} - -impl Tracer { - /// Create an empty tracer - pub fn new( - host_plugin_lookup: HashMap, - phantom_functions: &Vec, - dry_run: bool, - backend: TraceBackend, - capacity: u32, - ) -> Self { - Tracer { - itable: InstructionTableInternal::default(), - imtable: IMTable::default(), - etable: ETable::new(capacity, backend), - last_jump_eid: vec![], - jtable: JumpTable::default(), - elem_table: ElemTable::default(), - configure_table: ConfigureTable::default(), - type_of_func_ref: vec![], - function_lookup: HashMap::default(), - function_desc: Default::default(), - function_lookup_name: Default::default(), - host_function_index_lookup: host_plugin_lookup, - static_jtable_entries: vec![], - phantom_functions: phantom_functions.clone(), - phantom_functions_ref: vec![], - wasm_input_func_ref: None, - wasm_input_func_idx: None, - dry_run, - - observer: Observer { - counter: 0, - is_in_phantom: false, - }, - } - } - - pub fn push_frame(&mut self) { - self.last_jump_eid.push(self.etable.eid); - } - - pub fn pop_frame(&mut self) { - self.last_jump_eid.pop().unwrap(); - } - - pub fn last_jump_eid(&self) -> u32 { - *self.last_jump_eid.last().unwrap() - } - - fn lookup_host_plugin(&self, function_index: usize) -> HostFunctionDesc { - self.host_function_index_lookup - .get(&function_index) - .unwrap() - .clone() - } - - pub fn inc_counter(&mut self) { - self.observer.counter += 1; - } - - pub fn set_in_phantom(&mut self) { - self.observer.is_in_phantom = true; - } - - pub fn set_exit_phantom(&mut self) { - self.observer.is_in_phantom = false; - } - - pub fn dry_run(&self) -> bool { - self.dry_run - } -} - -impl Tracer { - pub(crate) fn push_init_memory(&mut self, memref: MemoryRef) { - // one page contains 64KB*1024/8=8192 u64 entries - const ENTRIES: u32 = 8192; - - let pages = (*memref).limits().initial(); - for i in 0..(pages * ENTRIES) { - let mut buf = [0u8; 8]; - (*memref).get_into(i * 8, &mut buf).unwrap(); - - let v = u64::from_le_bytes(buf); - - if v != 0 { - self.imtable - .push(false, true, i, VarType::I64, u64::from_le_bytes(buf)); - } - } - } - - pub(crate) fn push_global(&mut self, globalidx: u32, globalref: &GlobalRef) { - let vtype = globalref.elements_value_type().into(); - - self.imtable.push( - true, - globalref.is_mutable(), - globalidx, - vtype, - from_value_internal_to_u64_with_typ(vtype, ValueInternal::from(globalref.get())), - ); - } - - pub(crate) fn push_elem(&mut self, table_idx: u32, offset: u32, func_idx: u32, type_idx: u32) { - self.elem_table.insert(ElemEntry { - table_idx, - type_idx, - offset, - func_idx, - }) - } - - pub(crate) fn push_type_of_func_ref(&mut self, func: FuncRef, type_idx: u32) { - self.type_of_func_ref.push((func, type_idx)) - } - - #[allow(dead_code)] - pub(crate) fn statistics_instructions<'a>(&mut self, module_instance: &ModuleRef) { - let mut func_index = 0; - let mut insts = vec![]; - - loop { - if let Some(func) = module_instance.func_by_index(func_index) { - let body = func.body().unwrap(); - - let code = &body.code.vec; - - for inst in code { - if insts.iter().position(|i| i == inst).is_none() { - insts.push(inst.clone()) - } - } - } else { - break; - } - - func_index = func_index + 1; - } - - for inst in insts { - println!("{:?}", inst); - } - } - - pub(crate) fn lookup_type_of_func_ref(&self, func_ref: &FuncRef) -> u32 { - self.type_of_func_ref - .iter() - .find(|&f| f.0 == *func_ref) - .unwrap() - .1 - } - - pub(crate) fn register_module_instance(&mut self, module_instance: &ModuleRef) { - { - let mut func_index = 0; - - loop { - if let Some(func) = module_instance.func_by_index(func_index) { - if Some(&func) == self.wasm_input_func_ref.as_ref() { - self.wasm_input_func_idx = Some(func_index) - } - - let ftype = match *func.as_internal() { - crate::func::FuncInstanceInternal::Internal { .. } => { - FunctionType::WasmFunction - } - crate::func::FuncInstanceInternal::Host { - host_func_index, .. - } => { - let plugin_desc = self.lookup_host_plugin(host_func_index); - - match plugin_desc { - HostFunctionDesc::Internal { - name, - op_index_in_plugin, - plugin, - } => FunctionType::HostFunction { - plugin, - function_index: host_func_index, - function_name: name, - op_index_in_plugin, - }, - HostFunctionDesc::External { name, op, sig } => { - FunctionType::HostFunctionExternal { - function_name: name, - op, - sig, - } - } - } - } - }; - - self.function_lookup.insert(func.clone(), func_index); - self.function_desc.insert( - func_index, - FuncDesc { - ftype, - signature: func.signature().clone(), - }, - ); - func_index = func_index + 1; - } else { - break; - } - } - } - - { - let phantom_functions = self.phantom_functions.clone(); - - for func_name_regex in phantom_functions { - let re = Regex::new(&func_name_regex).unwrap(); - - for (export_name, export) in module_instance.exports.borrow().iter() { - if re.is_match(export_name) && export.as_func().is_some() { - self.push_phantom_function(export.as_func().unwrap().clone()); - } - } - } - } - - // make dry_run ignore itable - if self.dry_run() { - return; - } - - { - let mut func_index = 0; - - loop { - if let Some(func) = module_instance.func_by_index(func_index) { - let funcdesc = self.function_desc.get(&func_index).unwrap(); - let function_name = self.lookup_function_name(func_index); - - if self.is_phantom_function(&func) { - let instructions = PhantomFunction::build_phantom_function_instructions( - &funcdesc.signature, - self.wasm_input_func_idx.unwrap(), - ); - - for (iid, inst) in instructions.into_iter().enumerate() { - self.itable.push( - func_index, - function_name.clone(), - iid as u32, - inst.into(&self.function_desc), - ) - } - } else { - if let Some(body) = func.body() { - let code = &body.code; - let mut iter = code.iterate_from(0); - loop { - let pc = iter.position(); - if let Some(instruction) = iter.next() { - let _ = self.itable.push( - func_index, - function_name.clone(), - pc, - instruction.into(&self.function_desc), - ); - } else { - break; - } - } - } - } - - func_index = func_index + 1; - } else { - break; - } - } - } - } - - pub fn lookup_function_name(&self, function: u32) -> String { - if let Some(name) = self.function_lookup_name.get(&function) { - name.to_owned() - } else { - function.to_string() - } - } - - pub fn lookup_function(&self, function: &FuncRef) -> u32 { - match function.as_internal() { - FuncInstanceInternal::Internal { index, .. } => *index as u32, - FuncInstanceInternal::Host { .. } => *self.function_lookup.get(function).unwrap(), - } - } - - pub fn push_phantom_function(&mut self, function: FuncRef) { - self.phantom_functions_ref.push(function) - } - - pub fn is_phantom_function(&self, func: &FuncRef) -> bool { - self.phantom_functions_ref.contains(func) - } -} diff --git a/src/tracer/phantom.rs b/src/tracer/phantom.rs deleted file mode 100644 index e6260f5661..0000000000 --- a/src/tracer/phantom.rs +++ /dev/null @@ -1,147 +0,0 @@ -use specs::{host_function::HostPlugin, step::StepInfo, types::ValueType}; - -use super::Tracer; -use crate::{ - func::FuncRef, - isa::{DropKeep, Instruction, Keep}, - Signature, -}; - -pub struct PhantomFunction; - -impl PhantomFunction { - pub fn build_phantom_function_instructions( - sig: &Signature, - // Wasm Image Function Id - wasm_input_function_idx: u32, - ) -> Vec> { - let mut instructions = vec![]; - - if sig.return_type().is_some() { - instructions.push(Instruction::I32Const(0)); - - instructions.push(Instruction::Call(wasm_input_function_idx)); - - if sig.return_type() != Some(wasmi_core::ValueType::I64) { - instructions.push(Instruction::I32WrapI64); - } - } - - instructions.push(Instruction::Return(DropKeep { - drop: sig.params().len() as u32, - keep: if let Some(t) = sig.return_type() { - Keep::Single(t.into_elements()) - } else { - Keep::None - }, - })); - - instructions - } -} - -impl Tracer { - pub fn fill_trace( - &mut self, - current_sp: u32, - allocated_memory_pages: u32, - callee_func_ref: &FuncRef, - callee_sig: &Signature, - keep_value: Option, - ) { - let has_return_value = callee_sig.return_type().is_some(); - - if self.dry_run() { - if has_return_value { - self.inc_counter(); - self.inc_counter(); - if callee_sig.return_type() != Some(wasmi_core::ValueType::I64) { - self.inc_counter(); - } - } - self.inc_counter(); - return; - } - - let last_jump_eid = self.last_jump_eid(); - let fid = self.lookup_function(callee_func_ref); - - let mut iid = 0; - - let wasm_input_host_function_ref = self.wasm_input_func_ref.clone().unwrap(); - let wasm_input_host_func_index = match wasm_input_host_function_ref.as_internal() { - crate::func::FuncInstanceInternal::Internal { .. } => unreachable!(), - crate::func::FuncInstanceInternal::Host { - host_func_index, .. - } => host_func_index, - }; - - if has_return_value { - self.etable.push( - fid, - iid, - current_sp, - allocated_memory_pages, - last_jump_eid, - StepInfo::I32Const { value: 0 }, - ); - - iid += 1; - - self.etable.push( - fid, - iid, - current_sp + 1, - allocated_memory_pages, - last_jump_eid, - StepInfo::CallHost { - plugin: HostPlugin::HostInput, - host_function_idx: *wasm_input_host_func_index, - function_name: "wasm_input".to_owned(), - signature: specs::host_function::Signature { - params: vec![ValueType::I32], - return_type: Some(ValueType::I64), - }, - args: vec![0], - ret_val: Some(keep_value.unwrap()), - op_index_in_plugin: 0, - }, - ); - - iid += 1; - - if callee_sig.return_type() != Some(wasmi_core::ValueType::I64) { - self.etable.push( - fid, - iid, - current_sp + 1, - allocated_memory_pages, - last_jump_eid, - StepInfo::I32WrapI64 { - value: keep_value.unwrap() as i64, - result: keep_value.unwrap() as i32, - }, - ); - - iid += 1; - } - } - - self.etable.push( - fid, - iid, - current_sp + has_return_value as u32, - allocated_memory_pages, - last_jump_eid, - StepInfo::Return { - drop: callee_sig.params().len() as u32, - keep: if let Some(t) = callee_sig.return_type() { - vec![t.into_elements().into()] - } else { - vec![] - }, - keep_values: keep_value.map_or(vec![], |v| vec![v]), - }, - ); - } -} diff --git a/tests/e2e/v0/host.rs b/tests/e2e/v0/host.rs index a75ecf4243..d742a43444 100644 --- a/tests/e2e/v0/host.rs +++ b/tests/e2e/v0/host.rs @@ -267,13 +267,9 @@ fn call_host_func() { let mut env = TestHost::new(); - let instance = ModuleInstance::new( - &module, - &ImportsBuilder::new().with_resolver("env", &env), - None, - ) - .expect("Failed to instantiate module") - .assert_no_start(); + let instance = ModuleInstance::new(&module, &ImportsBuilder::new().with_resolver("env", &env)) + .expect("Failed to instantiate module") + .assert_no_start(); assert_eq!( instance @@ -302,13 +298,9 @@ fn resume_call_host_func() { let mut env = TestHost::new(); - let instance = ModuleInstance::new( - &module, - &ImportsBuilder::new().with_resolver("env", &env), - None, - ) - .expect("Failed to instantiate module") - .assert_no_start(); + let instance = ModuleInstance::new(&module, &ImportsBuilder::new().with_resolver("env", &env)) + .expect("Failed to instantiate module") + .assert_no_start(); let export = instance.export_by_name("test").unwrap(); let func_instance = export.as_func().unwrap(); @@ -350,13 +342,10 @@ fn resume_call_host_func_type_mismatch() { let mut env = TestHost::new(); - let instance = ModuleInstance::new( - &module, - &ImportsBuilder::new().with_resolver("env", &env), - None, - ) - .expect("Failed to instantiate module") - .assert_no_start(); + let instance = + ModuleInstance::new(&module, &ImportsBuilder::new().with_resolver("env", &env)) + .expect("Failed to instantiate module") + .assert_no_start(); let export = instance.export_by_name("test").unwrap(); let func_instance = export.as_func().unwrap(); @@ -406,13 +395,9 @@ fn host_err() { let mut env = TestHost::new(); - let instance = ModuleInstance::new( - &module, - &ImportsBuilder::new().with_resolver("env", &env), - None, - ) - .expect("Failed to instantiate module") - .assert_no_start(); + let instance = ModuleInstance::new(&module, &ImportsBuilder::new().with_resolver("env", &env)) + .expect("Failed to instantiate module") + .assert_no_start(); let error = instance .invoke_export("test", &[], &mut env) @@ -448,13 +433,9 @@ fn modify_mem_with_host_funcs() { let mut env = TestHost::new(); - let instance = ModuleInstance::new( - &module, - &ImportsBuilder::new().with_resolver("env", &env), - None, - ) - .expect("Failed to instantiate module") - .assert_no_start(); + let instance = ModuleInstance::new(&module, &ImportsBuilder::new().with_resolver("env", &env)) + .expect("Failed to instantiate module") + .assert_no_start(); instance .invoke_export("modify_mem", &[], &mut env) @@ -496,13 +477,9 @@ fn pull_internal_mem_from_module() { trap_sub_result: None, }; - let instance = ModuleInstance::new( - &module, - &ImportsBuilder::new().with_resolver("env", &env), - None, - ) - .expect("Failed to instantiate module") - .assert_no_start(); + let instance = ModuleInstance::new(&module, &ImportsBuilder::new().with_resolver("env", &env)) + .expect("Failed to instantiate module") + .assert_no_start(); // Get memory instance exported by name 'mem' from the module instance. let internal_mem = instance @@ -551,13 +528,9 @@ fn recursion() { let mut env = TestHost::new(); - let instance = ModuleInstance::new( - &module, - &ImportsBuilder::new().with_resolver("env", &env), - None, - ) - .expect("Failed to instantiate module") - .assert_no_start(); + let instance = ModuleInstance::new(&module, &ImportsBuilder::new().with_resolver("env", &env)) + .expect("Failed to instantiate module") + .assert_no_start(); // Put instance into the env, because $recurse function expects // attached module instance. @@ -665,7 +638,6 @@ fn defer_providing_externals() { let instance = ModuleInstance::new( &module, &ImportsBuilder::new().with_resolver("host", &host_import_resolver), - None, ) .expect("Failed to instantiate module") .assert_no_start(); @@ -780,7 +752,6 @@ fn two_envs_one_externals() { let trusted_instance = ModuleInstance::new( &trusted_module, &ImportsBuilder::new().with_resolver("env", &PrivilegedResolver), - None, ) .expect("Failed to instantiate module") .assert_no_start(); @@ -790,7 +761,6 @@ fn two_envs_one_externals() { &ImportsBuilder::new() .with_resolver("env", &OrdinaryResolver) .with_resolver("trusted", &trusted_instance), - None, ) .expect("Failed to instantiate module") .assert_no_start(); @@ -898,7 +868,6 @@ fn dynamically_add_host_func() { let instance = ModuleInstance::new( &module, &ImportsBuilder::new().with_resolver("env", &host_externals), - None, ) .expect("Failed to instantiate module") .assert_no_start(); diff --git a/tests/e2e/v0/wasm.rs b/tests/e2e/v0/wasm.rs index 410f187c86..a148733463 100644 --- a/tests/e2e/v0/wasm.rs +++ b/tests/e2e/v0/wasm.rs @@ -113,13 +113,9 @@ fn interpreter_inc_i32() { let env = Env::new(); - let instance = ModuleInstance::new( - &module, - &ImportsBuilder::new().with_resolver("env", &env), - None, - ) - .expect("Failed to instantiate module") - .assert_no_start(); + let instance = ModuleInstance::new(&module, &ImportsBuilder::new().with_resolver("env", &env)) + .expect("Failed to instantiate module") + .assert_no_start(); let i32_val = 42; // the functions expects a single i32 parameter @@ -145,13 +141,9 @@ fn interpreter_accumulate_u8() { let module = load_from_file(WASM_FILE); let env = Env::new(); - let instance = ModuleInstance::new( - &module, - &ImportsBuilder::new().with_resolver("env", &env), - None, - ) - .expect("Failed to instantiate module") - .assert_no_start(); + let instance = ModuleInstance::new(&module, &ImportsBuilder::new().with_resolver("env", &env)) + .expect("Failed to instantiate module") + .assert_no_start(); let env_memory = env.memory; diff --git a/tests/spec/v0/run.rs b/tests/spec/v0/run.rs index 39e962f40a..c29aead5de 100644 --- a/tests/spec/v0/run.rs +++ b/tests/spec/v0/run.rs @@ -283,7 +283,7 @@ fn try_load_module(wasm: &[u8]) -> Result { fn try_load(wasm: &[u8], spec_driver: &mut SpecDriver) -> Result<(), Error> { let module = try_load_module(wasm)?; - let instance = ModuleInstance::new(&module, &ImportsBuilder::default(), None)?; + let instance = ModuleInstance::new(&module, &ImportsBuilder::default())?; instance .run_start(spec_driver.spec_module()) .map_err(Error::Start)?; @@ -296,7 +296,7 @@ fn load_module( spec_driver: &mut SpecDriver, ) -> Result { let module = try_load_module(wasm)?; - let instance = ModuleInstance::new(&module, spec_driver, None) + let instance = ModuleInstance::new(&module, spec_driver) .map_err(|e| Error::Load(e.to_string()))? .run_start(spec_driver.spec_module()) .map_err(Error::Start)?; From 2043f60951ec751a5b453fc55a7cbed41c713e99 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Thu, 28 Mar 2024 09:05:44 +0000 Subject: [PATCH 128/129] add memory snapshot for phantom call --- src/memory/mod.rs | 59 +++++++++++++++++++++++++++++++++++++++++++++-- src/runner.rs | 5 +--- 2 files changed, 58 insertions(+), 6 deletions(-) diff --git a/src/memory/mod.rs b/src/memory/mod.rs index d49cabbcb6..c391274960 100644 --- a/src/memory/mod.rs +++ b/src/memory/mod.rs @@ -12,6 +12,7 @@ use core::{ u32, }; use parity_wasm::elements::ResizableLimits; +use std::collections::HashMap; #[cfg(all(feature = "virtual_memory", target_pointer_width = "64"))] #[path = "mmap_bytebuf.rs"] @@ -65,6 +66,8 @@ pub struct MemoryInstance { limits: ResizableLimits, /// Linear memory buffer with lazy allocation. buffer: RefCell, + /// Origin memory size at phantom entry, and a hashmap to track the modified memory. + pub buffer_cache: RefCell)>>, initial: Pages, current_size: Cell, maximum: Option, @@ -149,6 +152,7 @@ impl MemoryInstance { Ok(MemoryInstance { limits, buffer: RefCell::new(ByteBuf::new(initial_size.0).map_err(Error::Memory)?), + buffer_cache: RefCell::new(None), initial, current_size: Cell::new(initial_size.0), maximum, @@ -215,7 +219,21 @@ impl MemoryInstance { let mut buffer = self.buffer.borrow_mut(); let region = self.checked_region(&mut buffer, offset as usize, size)?; - Ok(buffer.as_slice_mut()[region.range()].to_vec()) + let mut buffer = buffer.as_slice_mut()[region.range()].to_vec(); + + let buf_cache = self.buffer_cache.borrow(); + if buf_cache.is_some() { + let mut index = 0; + + for offset in region.range() { + if let Some(value) = buf_cache.as_ref().unwrap().1.get(&offset) { + buffer[index] = *value; + } + index += 1; + } + } + + Ok(buffer) } /// Copy data from given offset in the memory into `target` slice. @@ -229,6 +247,18 @@ impl MemoryInstance { target.copy_from_slice(&buffer.as_slice_mut()[region.range()]); + let buf_cache = self.buffer_cache.borrow(); + if buf_cache.is_some() { + let mut index = 0; + + for offset in region.range() { + if let Some(value) = buf_cache.as_ref().unwrap().1.get(&offset) { + target[index] = *value; + } + index += 1; + } + } + Ok(()) } @@ -239,7 +269,18 @@ impl MemoryInstance { .checked_region(&mut buffer, offset as usize, value.len())? .range(); - buffer.as_slice_mut()[range].copy_from_slice(value); + let mut buf_cache = self.buffer_cache.borrow_mut(); + if buf_cache.is_some() { + let mut index = 0; + + for offset in range { + buf_cache.as_mut().unwrap().1.insert(offset, value[index]); + + index += 1; + } + } else { + buffer.as_slice_mut()[range].copy_from_slice(value); + } Ok(()) } @@ -291,6 +332,20 @@ impl MemoryInstance { Ok(size_before_grow) } + pub fn shrink(&self, origin: Pages) -> Result<(), Error> { + let new_size: Pages = origin; + + let new_buffer_length: Bytes = new_size.into(); + self.buffer + .borrow_mut() + .realloc(new_buffer_length.0) + .map_err(Error::Memory)?; + + self.current_size.set(new_buffer_length.0); + + Ok(()) + } + fn checked_region( &self, buffer: &mut ByteBuf, diff --git a/src/runner.rs b/src/runner.rs index 346589f05e..68a06a83c9 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -28,10 +28,7 @@ use crate::{ use alloc::{boxed::Box, vec::Vec}; use core::{fmt, ops, u32, usize}; use parity_wasm::elements::Local; -use specs::{ - mtable::{VarType}, -}; - +use specs::mtable::VarType; use validation::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX}; /// Maximum number of bytes on the value stack. From 7b715a2dd7af3330e4f3bab46137cb38fd9cb4a2 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Fri, 26 Apr 2024 06:16:33 +0000 Subject: [PATCH 129/129] remove unused code --- Cargo.toml | 1 - src/func.rs | 2 +- src/global.rs | 4 +- src/isa.rs | 182 +------------------------------------- src/lib.rs | 2 - src/memory/mod.rs | 3 +- src/memory/vec_bytebuf.rs | 1 - src/module.rs | 11 +-- src/prepare/compile.rs | 1 - src/runner.rs | 1 - src/table.rs | 3 +- src/tracer/etable.rs | 89 ------------------- src/tracer/imtable.rs | 35 -------- src/tracer/mod.rs | 15 ---- 14 files changed, 9 insertions(+), 341 deletions(-) delete mode 100644 src/tracer/etable.rs delete mode 100644 src/tracer/imtable.rs delete mode 100644 src/tracer/mod.rs diff --git a/Cargo.toml b/Cargo.toml index 38c2921d36..ab5bdd2ba7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,6 @@ exclude = [ "/res/*", "/tests/*", "/fuzz/*", "/benches/*" ] wasmi_core = { version = "0.1", path = "core", default-features = false } validation = { package = "wasmi-validation", version = "0.4", path = "validation", default-features = false } parity-wasm = { version = "0.42.0", features = ["sign_ext"] } -regex = "1.10.2" specs = { path = "../../crates/specs" } [dev-dependencies] diff --git a/src/func.rs b/src/func.rs index 889273d128..5a686d21ba 100644 --- a/src/func.rs +++ b/src/func.rs @@ -418,7 +418,7 @@ impl<'a, 'args> FuncInvocation<'a, 'args> { } } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug)] pub struct FuncBody { pub locals: Vec, pub code: isa::Instructions, diff --git a/src/global.rs b/src/global.rs index 16f7a772d5..12bfa48643 100644 --- a/src/global.rs +++ b/src/global.rs @@ -8,7 +8,7 @@ use parity_wasm::elements::ValueType as EValueType; /// This reference has a reference-counting semantics. /// /// [`GlobalInstance`]: struct.GlobalInstance.html -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug)] pub struct GlobalRef(Rc); impl ::core::ops::Deref for GlobalRef { @@ -29,7 +29,7 @@ impl ::core::ops::Deref for GlobalRef { /// /// [`I32`]: enum.Value.html#variant.I32 /// [`I64`]: enum.Value.html#variant.I64 -#[derive(Debug, PartialEq)] +#[derive(Debug)] pub struct GlobalInstance { val: Cell, mutable: bool, diff --git a/src/isa.rs b/src/isa.rs index 204352b86a..8882d6cce9 100644 --- a/src/isa.rs +++ b/src/isa.rs @@ -360,186 +360,6 @@ impl<'a> From> for UnaryOp { } } -impl<'a> Into for Instruction<'a> { - fn into(self) -> u32 { - match self { - Instruction::GetLocal(..) => 0, - Instruction::SetLocal(..) => 1, - Instruction::TeeLocal(..) => 2, - Instruction::Br(_) => 3, - Instruction::BrIfEqz(_) => 4, - Instruction::BrIfNez(_) => 5, - Instruction::BrTable(_) => 6, - Instruction::Unreachable => 7, - Instruction::Return(..) => 8, - Instruction::Call(_) => 9, - Instruction::CallIndirect(_) => 10, - Instruction::Drop => 11, - Instruction::Select(..) => 12, - Instruction::GetGlobal(_) => 13, - Instruction::SetGlobal(_) => 14, - Instruction::I32Load(_) => 15, - - Instruction::I64Load(_) => 16, - Instruction::F32Load(_) => 17, - Instruction::F64Load(_) => 18, - Instruction::I32Load8S(_) => 19, - Instruction::I32Load8U(_) => 20, - Instruction::I32Load16S(_) => 21, - Instruction::I32Load16U(_) => 22, - Instruction::I64Load8S(_) => 23, - Instruction::I64Load8U(_) => 24, - Instruction::I64Load16S(_) => 25, - Instruction::I64Load16U(_) => 26, - Instruction::I64Load32S(_) => 27, - Instruction::I64Load32U(_) => 28, - Instruction::I32Store(_) => 29, - Instruction::I64Store(_) => 30, - Instruction::F32Store(_) => 31, - Instruction::F64Store(_) => 32, - Instruction::I32Store8(_) => 33, - Instruction::I32Store16(_) => 34, - Instruction::I64Store8(_) => 35, - Instruction::I64Store16(_) => 36, - Instruction::I64Store32(_) => 37, - Instruction::CurrentMemory => 38, - Instruction::GrowMemory => 39, - Instruction::I32Const(_) => 40, - Instruction::I64Const(_) => 41, - Instruction::F32Const(_) => 42, - Instruction::F64Const(_) => 43, - Instruction::I32Eqz => 44, - Instruction::I32Eq => 45, - Instruction::I32Ne => 46, - Instruction::I32LtS => 47, - Instruction::I32LtU => 48, - Instruction::I32GtS => 49, - Instruction::I32GtU => 50, - Instruction::I32LeS => 51, - Instruction::I32LeU => 52, - Instruction::I32GeS => 53, - Instruction::I32GeU => 54, - Instruction::I64Eqz => 55, - Instruction::I64Eq => 56, - Instruction::I64Ne => 57, - Instruction::I64LtS => 58, - Instruction::I64LtU => 59, - Instruction::I64GtS => 60, - Instruction::I64GtU => 61, - Instruction::I64LeS => 62, - Instruction::I64LeU => 63, - Instruction::I64GeS => 64, - Instruction::I64GeU => 65, - Instruction::F32Eq => 66, - Instruction::F32Ne => 67, - Instruction::F32Lt => 68, - Instruction::F32Gt => 69, - Instruction::F32Le => 70, - Instruction::F32Ge => 71, - Instruction::F64Eq => 72, - Instruction::F64Ne => 73, - Instruction::F64Lt => 74, - Instruction::F64Gt => 75, - Instruction::F64Le => 76, - Instruction::F64Ge => 77, - Instruction::I32Clz => 78, - Instruction::I32Ctz => 79, - Instruction::I32Popcnt => 80, - Instruction::I32Add => 81, - Instruction::I32Sub => 82, - Instruction::I32Mul => 83, - Instruction::I32DivS => 84, - Instruction::I32DivU => 85, - Instruction::I32RemS => 86, - Instruction::I32RemU => 87, - Instruction::I32And => 88, - Instruction::I32Or => 89, - Instruction::I32Xor => 90, - Instruction::I32Shl => 91, - Instruction::I32ShrS => 92, - Instruction::I32ShrU => 93, - Instruction::I32Rotl => 94, - Instruction::I32Rotr => 95, - Instruction::I64Clz => 96, - Instruction::I64Ctz => 97, - Instruction::I64Popcnt => 98, - Instruction::I64Add => 99, - Instruction::I64Sub => 100, - Instruction::I64Mul => 101, - Instruction::I64DivS => 102, - Instruction::I64DivU => 103, - Instruction::I64RemS => 104, - Instruction::I64RemU => 105, - Instruction::I64And => 106, - Instruction::I64Or => 107, - Instruction::I64Xor => 108, - Instruction::I64Shl => 109, - Instruction::I64ShrS => 110, - Instruction::I64ShrU => 111, - Instruction::I64Rotl => 112, - Instruction::I64Rotr => 113, - Instruction::F32Abs => 114, - Instruction::F32Neg => 115, - Instruction::F32Ceil => 116, - Instruction::F32Floor => 117, - Instruction::F32Trunc => 118, - Instruction::F32Nearest => 119, - Instruction::F32Sqrt => 120, - Instruction::F32Add => 121, - Instruction::F32Sub => 122, - Instruction::F32Mul => 123, - Instruction::F32Div => 124, - Instruction::F32Min => 125, - Instruction::F32Max => 126, - Instruction::F32Copysign => 127, - Instruction::F64Abs => 128, - Instruction::F64Neg => 129, - Instruction::F64Ceil => 130, - Instruction::F64Floor => 131, - Instruction::F64Trunc => 132, - Instruction::F64Nearest => 133, - Instruction::F64Sqrt => 134, - Instruction::F64Add => 135, - Instruction::F64Sub => 136, - Instruction::F64Mul => 137, - Instruction::F64Div => 138, - Instruction::F64Min => 139, - Instruction::F64Max => 140, - Instruction::F64Copysign => 141, - Instruction::I32WrapI64 => 142, - Instruction::I32TruncSF32 => 143, - Instruction::I32TruncUF32 => 144, - Instruction::I32TruncSF64 => 145, - Instruction::I32TruncUF64 => 146, - Instruction::I64ExtendSI32 => 147, - Instruction::I64ExtendUI32 => 148, - Instruction::I64TruncSF32 => 149, - Instruction::I64TruncUF32 => 150, - Instruction::I64TruncSF64 => 151, - Instruction::I64TruncUF64 => 152, - Instruction::F32ConvertSI32 => 153, - Instruction::F32ConvertUI32 => 154, - Instruction::F32ConvertSI64 => 155, - Instruction::F32ConvertUI64 => 156, - Instruction::F32DemoteF64 => 157, - Instruction::F64ConvertSI32 => 158, - Instruction::F64ConvertUI32 => 159, - Instruction::F64ConvertSI64 => 160, - Instruction::F64ConvertUI64 => 161, - Instruction::F64PromoteF32 => 162, - Instruction::I32ReinterpretF32 => 163, - Instruction::I64ReinterpretF64 => 164, - Instruction::F32ReinterpretI32 => 165, - Instruction::F64ReinterpretI64 => 166, - Instruction::I32Extend8S => 167, - Instruction::I32Extend16S => 168, - Instruction::I64Extend8S => 169, - Instruction::I64Extend16S => 170, - Instruction::I64Extend32S => 171, - } - } -} - /// 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 @@ -742,7 +562,7 @@ pub enum InstructionInternal { I64Extend32S, } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone)] pub struct Instructions { pub(crate) vec: Vec, } diff --git a/src/lib.rs b/src/lib.rs index af809716e8..22527e1fdf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -271,8 +271,6 @@ mod types; pub mod isa; pub mod monitor; -/// Tracer lib for zkWasm -pub mod tracer; pub use self::{ func::{FuncInstance, FuncInvocation, FuncRef, ResumableError}, diff --git a/src/memory/mod.rs b/src/memory/mod.rs index c391274960..bcc1de9438 100644 --- a/src/memory/mod.rs +++ b/src/memory/mod.rs @@ -37,7 +37,7 @@ pub const LINEAR_MEMORY_PAGE_SIZE: Bytes = Bytes(65536); /// /// [`MemoryInstance`]: struct.MemoryInstance.html /// -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug)] pub struct MemoryRef(Rc); impl ::core::ops::Deref for MemoryRef { @@ -60,7 +60,6 @@ impl ::core::ops::Deref for MemoryRef { /// At the moment, wasm doesn't provide any way to shrink the memory. /// /// [`LINEAR_MEMORY_PAGE_SIZE`]: constant.LINEAR_MEMORY_PAGE_SIZE.html -#[derive(PartialEq)] pub struct MemoryInstance { /// Memory limits. limits: ResizableLimits, diff --git a/src/memory/vec_bytebuf.rs b/src/memory/vec_bytebuf.rs index 6719d7fc63..45dcb214b0 100644 --- a/src/memory/vec_bytebuf.rs +++ b/src/memory/vec_bytebuf.rs @@ -2,7 +2,6 @@ use alloc::{string::String, vec::Vec}; -#[derive(PartialEq)] pub struct ByteBuf { buf: Vec, } diff --git a/src/module.rs b/src/module.rs index fd8aa42513..d78baff2e7 100644 --- a/src/module.rs +++ b/src/module.rs @@ -46,7 +46,7 @@ use validation::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX}; /// should be retained. /// /// [`ModuleInstance`]: struct.ModuleInstance.html -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug)] pub struct ModuleRef(pub(crate) Rc); impl ::core::ops::Deref for ModuleRef { @@ -58,7 +58,6 @@ impl ::core::ops::Deref for ModuleRef { /// An external value is the runtime representation of an entity /// that can be imported or exported. -#[derive(PartialEq)] pub enum ExternVal { /// [Function][`FuncInstance`]. /// @@ -165,7 +164,7 @@ impl ExternVal { /// [`TableInstance`]: struct.TableInstance.html /// [`GlobalInstance`]: struct.GlobalInstance.html /// [`invoke_export`]: #method.invoke_export -#[derive(Debug, PartialEq)] +#[derive(Debug)] pub struct ModuleInstance { pub(crate) signatures: RefCell>>, tables: RefCell>, @@ -255,10 +254,8 @@ impl ModuleInstance { fn alloc_module<'i, I: Iterator>( loaded_module: &Module, extern_vals: I, - //tracer: Option>>, ) -> Result { let module = loaded_module.module(); - let instance = ModuleRef(Rc::new(ModuleInstance::default())); for &Type::Function(ref ty) in module.type_section().map(|ts| ts.types()).unwrap_or(&[]) { @@ -608,9 +605,7 @@ impl ModuleInstance { extern_vals.push(extern_val); } - let module_ref = Self::with_externvals(loaded_module, extern_vals.iter()); - - module_ref + Self::with_externvals(loaded_module, extern_vals.iter()) } /// Invoke exported function by a name. diff --git a/src/prepare/compile.rs b/src/prepare/compile.rs index 52ef4f4707..ee34e51e60 100644 --- a/src/prepare/compile.rs +++ b/src/prepare/compile.rs @@ -319,7 +319,6 @@ impl Compiler { `drop_keep_return` can't fail; qed", ); - self.sink.emit(isa::InstructionInternal::Return(drop_keep)); } Call(index) => { diff --git a/src/runner.rs b/src/runner.rs index 68a06a83c9..6ec8f93c7c 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -320,7 +320,6 @@ impl<'m> Interpreter<'m> { match *nested_func.as_internal() { FuncInstanceInternal::Internal { .. } => { let nested_context = FunctionContext::new(nested_func.clone()); - self.call_stack.push(function_context); self.call_stack.push(nested_context); } diff --git a/src/table.rs b/src/table.rs index 9ab4bb7e8e..9100e58be1 100644 --- a/src/table.rs +++ b/src/table.rs @@ -9,7 +9,7 @@ use parity_wasm::elements::ResizableLimits; /// /// [`TableInstance`]: struct.TableInstance.html /// -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug)] pub struct TableRef(Rc); impl ::core::ops::Deref for TableRef { @@ -32,7 +32,6 @@ impl ::core::ops::Deref for TableRef { /// /// [`grow`]: #method.grow /// -#[derive(PartialEq)] pub struct TableInstance { /// Table limits. limits: ResizableLimits, diff --git a/src/tracer/etable.rs b/src/tracer/etable.rs deleted file mode 100644 index c6455b701e..0000000000 --- a/src/tracer/etable.rs +++ /dev/null @@ -1,89 +0,0 @@ -use parity_wasm::elements::ValueType; -use specs::{ - etable::{EventTable, EventTableBackend, EventTableEntry}, - mtable::{MemoryReadSize, MemoryStoreSize, VarType}, - step::StepInfo, - TraceBackend, -}; - -use crate::{runner::ValueInternal, DEFAULT_VALUE_STACK_LIMIT}; - -pub struct ETable { - pub(crate) eid: u32, - slices: Vec, - entries: Vec, - capacity: u32, - backend: TraceBackend, -} - -impl ETable { - pub(crate) fn new(capacity: u32, backend: TraceBackend) -> Self { - Self { - eid: 0, - slices: Vec::default(), - entries: Vec::with_capacity(capacity as usize), - capacity, - backend, - } - } - - fn flush(&mut self) { - let empty = Vec::with_capacity(self.capacity as usize); - let entries = std::mem::replace(&mut self.entries, empty); - - let event_table = match &self.backend { - TraceBackend::File(path_builder) => { - let path = path_builder(self.slices.len(), &EventTable::new(entries)); - - EventTableBackend::Json(path) - } - TraceBackend::Memory => EventTableBackend::Memory(EventTable::new(entries)), - }; - - self.slices.push(event_table); - } - - pub(crate) fn push( - &mut self, - fid: u32, - iid: u32, - sp: u32, - allocated_memory_pages: u32, - last_jump_eid: u32, - step_info: StepInfo, - ) { - if self.entries.len() == self.capacity as usize { - self.flush(); - } - - self.eid += 1; - - let sp = (DEFAULT_VALUE_STACK_LIMIT as u32) - .checked_sub(sp) - .unwrap() - .checked_sub(1) - .unwrap(); - - let eentry = EventTableEntry { - eid: self.eid, - fid, - iid, - sp, - allocated_memory_pages, - last_jump_eid, - step_info, - }; - - self.entries.push(eentry); - } - - pub(crate) fn entries_mut(&mut self) -> &mut Vec { - &mut self.entries - } - - pub fn finalized(mut self) -> Vec { - self.flush(); - - self.slices - } -} diff --git a/src/tracer/imtable.rs b/src/tracer/imtable.rs deleted file mode 100644 index 7fd44c890c..0000000000 --- a/src/tracer/imtable.rs +++ /dev/null @@ -1,35 +0,0 @@ -use specs::{ - imtable::{InitMemoryTable, InitMemoryTableEntry}, - mtable::{LocationType, VarType}, -}; - -#[derive(Debug, Default)] -pub struct IMTable(Vec); - -impl IMTable { - pub fn push( - &mut self, - is_global: bool, - is_mutable: bool, - offset: u32, - vtype: VarType, - value: u64, - ) { - self.0.push(InitMemoryTableEntry { - is_mutable, - ltype: if is_global { - LocationType::Global - } else { - LocationType::Heap - }, - offset, - vtype, - value, - eid: 0, - }) - } - - pub fn finalized(&self) -> InitMemoryTable { - InitMemoryTable::new(self.0.clone()) - } -} diff --git a/src/tracer/mod.rs b/src/tracer/mod.rs deleted file mode 100644 index 7e0897ea8d..0000000000 --- a/src/tracer/mod.rs +++ /dev/null @@ -1,15 +0,0 @@ -use specs::types::FunctionType; - -use crate::Signature; - -#[derive(Debug)] -pub struct FuncDesc { - pub ftype: FunctionType, - pub signature: Signature, -} - -#[derive(Debug, Default)] -pub struct Observer { - pub counter: usize, - pub is_in_phantom: bool, -}