From 7b92b7c7dcb711cdcc26ab60597d28cae4f64b0c Mon Sep 17 00:00:00 2001 From: Xuejie Xiao Date: Fri, 21 Mar 2025 03:07:22 +0000 Subject: [PATCH 1/2] feat: Add new DefaultMachineRunner trait for initialization work Previously, all different machines in ckb-vm might use slightly different initialization process. This commit introduces a new DefaultMachineRunner trait, so the same initialization & usage workflow can be used for all types implementing this trait. This is a cherry-pick of https://github.com/nervosnetwork/ckb-vm/pull/469 to the develop branch. 2 more changes are applied on the develop branch: * Since AsmCoreMachine is now constant, we can simply use AsmCoreMachine instead of `Box`. * https://github.com/nervosnetwork/ckb-vm/pull/343 was mostly reverted. Upon more thinking, I think the change earlier does not make sense now. It's better we provide unified initialization for the whole machine, not just for the memory part. Due to the new InstDecoder / TraceDecoder structure introduced in develop branch, more changes are required in the develop branch than 0.24.x releases. Some of those changes include: * Assembly machines now require TraceDecoder instead of InstDecoder. This means we cannot use DefaultMachineBuilder to build DefaultMachine structures for both types of VMs. The assembly machine types require more constraints. Given this consideration, DefaultMachineBuilder is removed in this commit. 2 new types RustDefaultMachineBuilder and AsmDefaultMachineBuilder are added for 2 types of VMs respectively. * A new set of types that begin with `Abstract`, such as AbstractDefaultMachineBuilder, AbstractAsmMachine, AbstractTraceMachine are introduced. One is only expected to use those types when one wants to tweak the inst/trace decoder used. Otherwise, one is safe to pick AsmMachine/AsmDefaultMachineBuilder or TraceMachine/RustDefaultMachineBuilder. So the current workflow is like following: 1. Pick a type implementing DefaultMachineRunner traits. Most likely, one would pick either AsmMachine or TraceMachine. 2. Instantiate a core machine using DefaultMachineRunner::Inner::new. 3. Based on the type picked in step 1, use AsmDefaultMachineBuilder or RustDefaultMachineBuilder to build a default machine with possible instruction cycle func, syscalls and debugger plugin. 4. Finally, use DefaultMachineRunner::new to create the final runnable machine from the default machine. For advanced usages where the decoder is customized, one can use AbstractAsmMachine or AbstractTraceMachine type. Then use AbstractDefaultMachineBuilder to build the default machine. And finally create the runnable machine. All those types accept an additional InstDecoder / TraceDecoder trait impl that allows one to customize the decoder for optimizations. --- .github/workflows/develop.yml | 4 +- benches/vm_benchmark.rs | 30 ++-- definitions/src/asm.rs | 50 +----- definitions/src/generate_asm_constants.rs | 11 +- examples/check_real_memory.rs | 26 ++- examples/ckb_vm_runner.rs | 10 +- src/decoder.rs | 40 +++-- src/lib.rs | 26 +-- src/machine/asm/mod.rs | 181 ++++++++++++------- src/machine/asm/traces.rs | 72 ++++---- src/machine/mod.rs | 205 +++++++++++++++------- src/machine/trace.rs | 83 +++++---- src/memory/flat.rs | 31 +--- src/memory/mod.rs | 2 +- src/memory/sparse.rs | 28 +-- src/memory/wxorx.rs | 16 +- tests/machine_build.rs | 9 +- tests/test_a_extension.rs | 2 +- tests/test_asm.rs | 148 +++++++++------- tests/test_auipc_fusion.rs | 36 ++-- tests/test_b_extension.rs | 2 + tests/test_dy_memory.rs | 28 ++- tests/test_misc.rs | 41 +++-- tests/test_mop.rs | 5 +- tests/test_reset.rs | 14 +- tests/test_resume.rs | 36 ++-- tests/test_resume2.rs | 20 ++- tests/test_signal_pause.rs | 2 +- tests/test_simple.rs | 12 +- tests/test_spawn.rs | 14 +- tests/test_versions.rs | 33 ++-- 31 files changed, 661 insertions(+), 556 deletions(-) diff --git a/.github/workflows/develop.yml b/.github/workflows/develop.yml index a8067ed9..bf8116b0 100644 --- a/.github/workflows/develop.yml +++ b/.github/workflows/develop.yml @@ -89,7 +89,7 @@ jobs: ln -snf .. ckb-vm-test-suite/ckb-vm docker run --rm -v `pwd`:/code nervos/ckb-riscv-gnu-toolchain:bionic-20210804 cp -r /riscv /code/riscv cd ckb-vm-test-suite - git checkout 898edc351eeb4de974ca4f0ff8d1e4943a95aecb + git checkout 2be7dcb0fda7ab41932813632fd1904e8cecf1f0 git submodule update --init --recursive RISCV=`pwd`/../riscv ./test.sh @@ -161,7 +161,7 @@ jobs: ln -snf .. ckb-vm-test-suite/ckb-vm docker run --rm -v `pwd`:/code nervos/ckb-riscv-gnu-toolchain:bionic-20210804 cp -r /riscv /code/riscv cd ckb-vm-test-suite - git checkout 898edc351eeb4de974ca4f0ff8d1e4943a95aecb + git checkout 2be7dcb0fda7ab41932813632fd1904e8cecf1f0 git submodule update --init --recursive RISCV=`pwd`/../riscv ./test.sh --build-only cd .. diff --git a/benches/vm_benchmark.rs b/benches/vm_benchmark.rs index e2e14960..e9db7cc3 100644 --- a/benches/vm_benchmark.rs +++ b/benches/vm_benchmark.rs @@ -4,13 +4,13 @@ extern crate criterion; use bytes::Bytes; #[cfg(has_asm)] use ckb_vm::{ - decoder::build_decoder, + decoder::{DefaultDecoder, InstDecoder}, machine::{ asm::{ traces::{MemoizedDynamicTraceDecoder, MemoizedFixedTraceDecoder}, - AsmCoreMachine, AsmMachine, + AbstractAsmMachine, AsmCoreMachine, AsmDefaultMachineBuilder, AsmMachine, }, - DefaultMachineBuilder, VERSION0, VERSION2, + AbstractDefaultMachineBuilder, DefaultMachineRunner, SupportMachine, VERSION0, VERSION2, }, ISA_B, ISA_IMC, ISA_MOP, }; @@ -45,7 +45,7 @@ fn asm_benchmark(c: &mut Criterion) { ].into_iter().map(|a| Ok(a.into())); b.iter(|| { let asm_core = AsmCoreMachine::new(ISA_IMC, VERSION0, u64::MAX); - let core = DefaultMachineBuilder::new(asm_core).build(); + let core = AsmDefaultMachineBuilder::new(asm_core).build(); let mut machine = AsmMachine::new(core); machine.load_program(&buffer, args.clone()).unwrap(); machine.run().unwrap() @@ -66,7 +66,7 @@ fn mop_benchmark(c: &mut Criterion) { ].into_iter().map(|a| Ok(a.into())); b.iter(|| { let asm_core = AsmCoreMachine::new(ISA_IMC | ISA_B | ISA_MOP, VERSION2, u64::MAX); - let core = DefaultMachineBuilder::>::new(asm_core) + let core = AsmDefaultMachineBuilder::new(asm_core) .build(); let mut machine = AsmMachine::new(core); machine.load_program(&buffer, args.clone()).unwrap(); @@ -88,19 +88,19 @@ fn mop_memoized_benchmark(c: &mut Criterion) { "foo", "bar", ].into_iter().map(|a| Ok(a.into())); - let mut decoder = MemoizedFixedTraceDecoder::new(build_decoder::(isa, version)); + let mut decoder = MemoizedFixedTraceDecoder::new::(isa, version); let asm_core = AsmCoreMachine::new(isa, version, u64::MAX); - let core = DefaultMachineBuilder::>::new(asm_core) + let core = AbstractDefaultMachineBuilder::<_, MemoizedFixedTraceDecoder>::new(asm_core) .build(); - let mut machine = AsmMachine::new(core); + let mut machine = AbstractAsmMachine::new(core); machine.load_program(&buffer, args.clone()).unwrap(); machine.run_with_decoder(&mut decoder).unwrap(); b.iter(|| { let asm_core = AsmCoreMachine::new(isa, version, u64::MAX); - let core = DefaultMachineBuilder::>::new(asm_core) + let core = AbstractDefaultMachineBuilder::<_, MemoizedFixedTraceDecoder>::new(asm_core) .build(); - let mut machine = AsmMachine::new(core); + let mut machine = AbstractAsmMachine::new(core); machine.load_program(&buffer, args.clone()).unwrap(); decoder.clear_traces(); machine.run_with_decoder(&mut decoder).unwrap() @@ -121,19 +121,19 @@ fn mop_memoized_dynamic_benchmark(c: &mut Criterion) { "foo", "bar", ].into_iter().map(|a| Ok(a.into())); - let mut decoder = MemoizedDynamicTraceDecoder::new(build_decoder::(isa, version)); + let mut decoder = MemoizedDynamicTraceDecoder::new::(isa, version); let asm_core = AsmCoreMachine::new(isa, version, u64::MAX); - let core = DefaultMachineBuilder::>::new(asm_core) + let core = AbstractDefaultMachineBuilder::<_, MemoizedDynamicTraceDecoder>::new(asm_core) .build(); - let mut machine = AsmMachine::new(core); + let mut machine = AbstractAsmMachine::new(core); machine.load_program(&buffer, args.clone()).unwrap(); machine.run_with_decoder(&mut decoder).unwrap(); b.iter(|| { let asm_core = AsmCoreMachine::new(isa, version, u64::MAX); - let core = DefaultMachineBuilder::>::new(asm_core) + let core = AbstractDefaultMachineBuilder::<_, MemoizedDynamicTraceDecoder>::new(asm_core) .build(); - let mut machine = AsmMachine::new(core); + let mut machine = AbstractAsmMachine::new(core); machine.load_program(&buffer, args.clone()).unwrap(); decoder.clear_traces(); machine.run_with_decoder(&mut decoder).unwrap() diff --git a/definitions/src/asm.rs b/definitions/src/asm.rs index 7a99e5c3..060e7fe8 100644 --- a/definitions/src/asm.rs +++ b/definitions/src/asm.rs @@ -1,8 +1,5 @@ -use crate::{ - instructions::Instruction, DEFAULT_MEMORY_SIZE, MEMORY_FRAMESIZE, MEMORY_FRAME_SHIFTS, - RISCV_GENERAL_REGISTER_NUMBER, RISCV_PAGESIZE, -}; -use std::alloc::{alloc, alloc_zeroed, dealloc, Layout}; +use crate::{instructions::Instruction, RISCV_GENERAL_REGISTER_NUMBER}; +use std::alloc::{dealloc, Layout}; // The number of trace items to keep pub const TRACE_SIZE: usize = 8192; @@ -117,49 +114,6 @@ impl Drop for AsmCoreMachine { } impl AsmCoreMachine { - pub fn new(isa: u8, version: u32, max_cycles: u64) -> Box { - Self::new_with_memory(isa, version, max_cycles, DEFAULT_MEMORY_SIZE) - } - - pub fn new_with_memory( - isa: u8, - version: u32, - max_cycles: u64, - memory_size: usize, - ) -> Box { - assert_ne!(memory_size, 0); - assert_eq!(memory_size % RISCV_PAGESIZE, 0); - assert_eq!(memory_size % (1 << MEMORY_FRAME_SHIFTS), 0); - let mut machine = unsafe { - let layout = Layout::new::(); - let raw_allocation = alloc_zeroed(layout) as *mut AsmCoreMachine; - Box::from_raw(raw_allocation) - }; - machine.max_cycles = max_cycles; - if cfg!(feature = "enable-chaos-mode-by-default") { - machine.chaos_mode = 1; - } - machine.load_reservation_address = u64::MAX; - machine.version = version; - machine.isa = isa; - - machine.memory_size = memory_size as u64; - machine.frames_size = (memory_size / MEMORY_FRAMESIZE) as u64; - machine.flags_size = (memory_size / RISCV_PAGESIZE) as u64; - - machine.last_read_frame = u64::MAX; - machine.last_write_page = u64::MAX; - - let memory_layout = Layout::array::(machine.memory_size as usize).unwrap(); - machine.memory_ptr = unsafe { alloc(memory_layout) } as u64; - let flags_layout = Layout::array::(machine.flags_size as usize).unwrap(); - machine.flags_ptr = unsafe { alloc_zeroed(flags_layout) } as u64; - let frames_layout = Layout::array::(machine.frames_size as usize).unwrap(); - machine.frames_ptr = unsafe { alloc_zeroed(frames_layout) } as u64; - - machine - } - pub fn set_max_cycles(&mut self, cycles: u64) { self.max_cycles = cycles; } diff --git a/definitions/src/generate_asm_constants.rs b/definitions/src/generate_asm_constants.rs index 8735c5a0..4e8fe2b0 100644 --- a/definitions/src/generate_asm_constants.rs +++ b/definitions/src/generate_asm_constants.rs @@ -11,6 +11,7 @@ use ckb_vm_definitions::{ MEMORY_FRAMESIZE, MEMORY_FRAME_PAGE_SHIFTS, MEMORY_FRAME_SHIFTS, RISCV_PAGESIZE, RISCV_PAGE_SHIFTS, }; +use std::alloc::{alloc, Layout}; use std::mem::{size_of, zeroed}; macro_rules! print_inst_label { @@ -129,7 +130,15 @@ fn main() { ); println!(); - let m: Box = AsmCoreMachine::new(0, 0, 0); + // We don't need a fully initialized AsmCoreMachine, only a dummy + // structure here will do. + let m: Box = unsafe { + let machine_size = std::mem::size_of::(); + + let layout = Layout::array::(machine_size).unwrap(); + let raw_allocation = alloc(layout) as *mut AsmCoreMachine; + Box::from_raw(raw_allocation) + }; let m_address = &*m as *const AsmCoreMachine as usize; println!( "#define CKB_VM_ASM_ASM_CORE_MACHINE_OFFSET_REGISTERS {}", diff --git a/examples/check_real_memory.rs b/examples/check_real_memory.rs index c3a7b9fd..a2ee6ef4 100644 --- a/examples/check_real_memory.rs +++ b/examples/check_real_memory.rs @@ -7,8 +7,8 @@ use std::process::{id, Command}; #[cfg(has_asm)] use ckb_vm::{ machine::{ - asm::{AsmCoreMachine, AsmMachine}, - DefaultMachineBuilder, VERSION0, + asm::{AsmCoreMachine, AsmDefaultMachineBuilder, AsmMachine}, + DefaultMachineRunner, SupportMachine, VERSION0, }, ISA_IMC, }; @@ -126,7 +126,7 @@ fn check_interpreter(memory_size: usize) -> Result<(), ()> { let result = run_with_memory::>( &Bytes::from(BIN_PATH_BUFFER), &vec![Bytes::from(BIN_NAME)], - SparseMemory::new_with_memory(memory_size), + memory_size, ); assert!(result.is_ok()); assert_eq!(result.unwrap(), 0); @@ -146,7 +146,7 @@ fn check_falt(memory_size: usize) -> Result<(), ()> { let result = run_with_memory::>( &Bytes::from(BIN_PATH_BUFFER), &vec![Bytes::from(BIN_NAME)], - FlatMemory::new_with_memory(memory_size), + memory_size, ); assert!(result.is_ok()); assert_eq!(result.unwrap(), 0); @@ -164,8 +164,13 @@ fn check_asm(memory_size: usize) -> Result<(), ()> { ); println!("Base memory: {}", get_current_memory()); for _ in 0..G_CHECK_LOOP { - let asm_core = AsmCoreMachine::new_with_memory(ISA_IMC, VERSION0, u64::MAX, memory_size); - let core = DefaultMachineBuilder::new(asm_core).build(); + let asm_core = ::new_with_memory( + ISA_IMC, + VERSION0, + u64::MAX, + memory_size, + ); + let core = AsmDefaultMachineBuilder::new(asm_core).build(); let mut machine = AsmMachine::new(core); machine .load_program( @@ -191,8 +196,13 @@ fn check_asm_in_thread(memory_size: usize) -> Result<(), ()> { ); println!("Base memory: {}", get_current_memory()); for _ in 0..G_CHECK_LOOP { - let asm_core = AsmCoreMachine::new_with_memory(ISA_IMC, VERSION0, u64::MAX, memory_size); - let core = DefaultMachineBuilder::new(asm_core).build(); + let asm_core = ::new_with_memory( + ISA_IMC, + VERSION0, + u64::MAX, + memory_size, + ); + let core = AsmDefaultMachineBuilder::new(asm_core).build(); let mut machine = AsmMachine::new(core); machine .load_program( diff --git a/examples/ckb_vm_runner.rs b/examples/ckb_vm_runner.rs index ac539e82..6e6a096c 100644 --- a/examples/ckb_vm_runner.rs +++ b/examples/ckb_vm_runner.rs @@ -1,6 +1,8 @@ use ckb_vm::cost_model::estimate_cycles; use ckb_vm::registers::{A0, A7}; -use ckb_vm::{Bytes, CoreMachine, Memory, Register, SupportMachine, Syscalls}; +use ckb_vm::{ + Bytes, CoreMachine, DefaultMachineRunner, Memory, Register, SupportMachine, Syscalls, +}; pub struct DebugSyscall {} @@ -39,12 +41,12 @@ impl Syscalls for DebugSyscall { #[cfg(has_asm)] fn main_asm(code: Bytes, args: Vec) -> Result<(), Box> { - let asm_core = ckb_vm::machine::asm::AsmCoreMachine::new( + let asm_core = ::new( ckb_vm::ISA_IMC | ckb_vm::ISA_B | ckb_vm::ISA_MOP, ckb_vm::machine::VERSION2, u64::MAX, ); - let core = ckb_vm::DefaultMachineBuilder::new(asm_core) + let core = ckb_vm::machine::asm::AsmDefaultMachineBuilder::new(asm_core) .instruction_cycle_func(Box::new(estimate_cycles)) .syscall(Box::new(DebugSyscall {})) .build(); @@ -68,7 +70,7 @@ fn main_int(code: Bytes, args: Vec) -> Result<(), Box(isa: u8, version: u32) -> Self; fn decode(&mut self, memory: &mut M, pc: u64) -> Result; fn reset_instructions_cache(&mut self) -> Result<(), Error>; } -pub struct Decoder { +pub struct DefaultDecoder { factories: Vec, mop: bool, version: u32, @@ -30,9 +31,10 @@ pub struct Decoder { instructions_cache: Vec<(u64, u64)>, } -impl Decoder { - pub fn new(mop: bool, version: u32) -> Decoder { - Decoder { +impl DefaultDecoder { + /// Creates an empty decoder with no instruction factory + pub fn empty(mop: bool, version: u32) -> Self { + Self { factories: vec![], mop, version, @@ -860,7 +862,21 @@ impl Decoder { } } -impl InstDecoder for Decoder { +impl InstDecoder for DefaultDecoder { + fn new(isa: u8, version: u32) -> Self { + let mut decoder = Self::empty(isa & ISA_MOP != 0, version); + decoder.add_instruction_factory(rvc::factory::); + decoder.add_instruction_factory(i::factory::); + decoder.add_instruction_factory(m::factory::); + if isa & ISA_B != 0 { + decoder.add_instruction_factory(b::factory::); + } + if isa & ISA_A != 0 { + decoder.add_instruction_factory(a::factory::); + } + decoder + } + fn decode(&mut self, memory: &mut M, pc: u64) -> Result { if self.mop { self.decode_mop(memory, pc) @@ -874,17 +890,3 @@ impl InstDecoder for Decoder { Ok(()) } } - -pub fn build_decoder(isa: u8, version: u32) -> Decoder { - let mut decoder = Decoder::new(isa & ISA_MOP != 0, version); - decoder.add_instruction_factory(rvc::factory::); - decoder.add_instruction_factory(i::factory::); - decoder.add_instruction_factory(m::factory::); - if isa & ISA_B != 0 { - decoder.add_instruction_factory(b::factory::); - } - if isa & ISA_A != 0 { - decoder.add_instruction_factory(a::factory::); - } - decoder -} diff --git a/src/lib.rs b/src/lib.rs index 2bd98eca..06608028 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,8 +21,9 @@ pub use crate::{ debugger::Debugger, instructions::{Instruction, Register}, machine::{ - trace::TraceMachine, CoreMachine, DefaultCoreMachine, DefaultMachine, - DefaultMachineBuilder, FlattenedArgsReader, InstructionCycleFunc, Machine, SupportMachine, + trace::TraceMachine, CoreMachine, DefaultCoreMachine, DefaultMachine, DefaultMachineRunner, + FlattenedArgsReader, InstructionCycleFunc, Machine, RustDefaultMachineBuilder, + SupportMachine, }, memory::{flat::FlatMemory, sparse::SparseMemory, wxorx::WXorXMemory, Memory}, syscalls::Syscalls, @@ -36,33 +37,22 @@ pub use ckb_vm_definitions::{ pub use error::Error; -pub fn run + Default>( - program: &Bytes, - args: &[Bytes], -) -> Result { - let core_machine = DefaultCoreMachine::>::new_with_memory( - ISA_IMC | ISA_B | ISA_MOP, - machine::VERSION2, - u64::MAX, - WXorXMemory::new(M::default()), - ); - let mut machine = TraceMachine::new(DefaultMachineBuilder::new(core_machine).build()); - machine.load_program(program, args.iter().map(|e| Ok(e.clone())))?; - machine.run() +pub fn run>(program: &Bytes, args: &[Bytes]) -> Result { + run_with_memory::(program, args, DEFAULT_MEMORY_SIZE) } pub fn run_with_memory>( program: &Bytes, args: &[Bytes], - memory: M, + memory_size: usize, ) -> Result { let core_machine = DefaultCoreMachine::>::new_with_memory( ISA_IMC | ISA_B | ISA_MOP, machine::VERSION2, u64::MAX, - WXorXMemory::new(memory), + memory_size, ); - let mut machine = TraceMachine::new(DefaultMachineBuilder::new(core_machine).build()); + let mut machine = TraceMachine::new(RustDefaultMachineBuilder::new(core_machine).build()); machine.load_program(program, args.iter().map(|e| Ok(e.clone())))?; machine.run() } diff --git a/src/machine/asm/mod.rs b/src/machine/asm/mod.rs index c0f6a0fb..d5185ab8 100644 --- a/src/machine/asm/mod.rs +++ b/src/machine/asm/mod.rs @@ -9,29 +9,32 @@ use ckb_vm_definitions::{ RET_EBREAK, RET_ECALL, RET_INVALID_PERMISSION, RET_MAX_CYCLES_EXCEEDED, RET_OUT_OF_BOUND, RET_PAUSE, RET_SLOWPATH, }, - ISA_MOP, MEMORY_FRAME_PAGE_SHIFTS, RISCV_GENERAL_REGISTER_NUMBER, RISCV_PAGE_SHIFTS, + ISA_MOP, MEMORY_FRAMESIZE, MEMORY_FRAME_PAGE_SHIFTS, RISCV_GENERAL_REGISTER_NUMBER, + RISCV_PAGE_SHIFTS, }; use rand::{prelude::RngCore, SeedableRng}; +use std::alloc::{alloc, alloc_zeroed, Layout}; +use std::marker::PhantomData; +use std::mem::MaybeUninit; use std::os::raw::c_uchar; use crate::{ - decoder::{build_decoder, InstDecoder}, elf::ProgramMetadata, error::OutOfBoundKind, instructions::execute_instruction, machine::{ asm::traces::{decode_fixed_trace, SimpleFixedTraceDecoder, TraceDecoder}, - VERSION0, + AbstractDefaultMachineBuilder, VERSION0, }, memory::{ check_no_overflow, fill_page_data, get_page_indices, memset, round_page_down, round_page_up, FLAG_DIRTY, FLAG_EXECUTABLE, FLAG_FREEZED, FLAG_WRITABLE, FLAG_WXORX_BIT, }, - CoreMachine, DefaultMachine, Error, Machine, Memory, SupportMachine, MEMORY_FRAME_SHIFTS, - RISCV_PAGESIZE, + CoreMachine, DefaultMachine, DefaultMachineRunner, Error, Machine, Memory, SupportMachine, + MEMORY_FRAME_SHIFTS, RISCV_PAGESIZE, }; -impl CoreMachine for Box { +impl CoreMachine for AsmCoreMachine { type REG = u64; type MEM = Self; @@ -119,7 +122,7 @@ fn check_permission(memory: &mut M, page: u64, flag: u8) -> Result<() // check whether a memory address is writable or not and mark it as dirty, `size` should be 1, 2, 4 or 8 fn check_memory_writable( - machine: &mut Box, + machine: &mut AsmCoreMachine, addr: u64, size: usize, ) -> Result<(), Error> { @@ -152,7 +155,7 @@ fn check_memory_writable( // check whether a memory address is executable, `size` should be 2 or 4 fn check_memory_executable( - machine: &mut Box, + machine: &mut AsmCoreMachine, addr: u64, size: usize, ) -> Result<(), Error> { @@ -183,11 +186,7 @@ fn check_memory_executable( } // check whether a memory address is initialized, `size` should be 1, 2, 4 or 8 -fn check_memory_inited( - machine: &mut Box, - addr: u64, - size: usize, -) -> Result<(), Error> { +fn check_memory_inited(machine: &mut AsmCoreMachine, addr: u64, size: usize) -> Result<(), Error> { debug_assert!(size == 1 || size == 2 || size == 4 || size == 8); let page = addr >> RISCV_PAGE_SHIFTS; if page as usize >= machine.memory_pages() { @@ -213,7 +212,7 @@ fn check_memory_inited( // A newtype supporting fast store_byte / store_bytes without memory // permission checking -struct FastMemory<'a>(&'a mut Box); +struct FastMemory<'a>(&'a mut AsmCoreMachine); impl<'a> FastMemory<'a> { fn prepare_memory(&mut self, addr: u64, size: u64) -> Result<(), Error> { @@ -251,6 +250,10 @@ impl<'a> FastMemory<'a> { impl<'a> Memory for FastMemory<'a> { type REG = u64; + fn new(_memory_size: usize) -> Self { + unreachable!() + } + fn store_bytes(&mut self, addr: u64, value: &[u8]) -> Result<(), Error> { if value.is_empty() { return Ok(()); @@ -271,10 +274,6 @@ impl<'a> Memory for FastMemory<'a> { Ok(()) } - fn reset_memory(&mut self) -> Result<(), Error> { - unreachable!() - } - fn init_pages( &mut self, _addr: u64, @@ -355,18 +354,11 @@ impl<'a> Memory for FastMemory<'a> { } } -impl Memory for Box { +impl Memory for AsmCoreMachine { type REG = u64; - fn reset_memory(&mut self) -> Result<(), Error> { - let slice = cast_ptr_to_slice_mut(self, self.flags_ptr, 0, self.flags_size as usize); - memset(slice, 0); - let slice = cast_ptr_to_slice_mut(self, self.frames_ptr, 0, self.frames_size as usize); - memset(slice, 0); - self.load_reservation_address = u64::MAX; - self.last_read_frame = u64::MAX; - self.last_write_page = u64::MAX; - Ok(()) + fn new(_memory_size: usize) -> Self { + unreachable!() } fn init_pages( @@ -600,7 +592,44 @@ impl Memory for Box { } } -impl SupportMachine for Box { +impl SupportMachine for AsmCoreMachine { + fn new_with_memory( + isa: u8, + version: u32, + max_cycles: u64, + memory_size: usize, + ) -> AsmCoreMachine { + assert_ne!(memory_size, 0); + assert_eq!(memory_size % RISCV_PAGESIZE, 0); + assert_eq!(memory_size % (1 << MEMORY_FRAME_SHIFTS), 0); + + let mut machine: AsmCoreMachine = unsafe { MaybeUninit::zeroed().assume_init() }; + + machine.max_cycles = max_cycles; + if cfg!(feature = "enable-chaos-mode-by-default") { + machine.chaos_mode = 1; + } + machine.load_reservation_address = u64::MAX; + machine.version = version; + machine.isa = isa; + + machine.memory_size = memory_size as u64; + machine.frames_size = (memory_size / MEMORY_FRAMESIZE) as u64; + machine.flags_size = (memory_size / RISCV_PAGESIZE) as u64; + + machine.last_read_frame = u64::MAX; + machine.last_write_page = u64::MAX; + + let memory_layout = Layout::array::(machine.memory_size as usize).unwrap(); + machine.memory_ptr = unsafe { alloc(memory_layout) } as u64; + let flags_layout = Layout::array::(machine.flags_size as usize).unwrap(); + machine.flags_ptr = unsafe { alloc_zeroed(flags_layout) } as u64; + let frames_layout = Layout::array::(machine.frames_size as usize).unwrap(); + machine.frames_ptr = unsafe { alloc_zeroed(frames_layout) } as u64; + + machine + } + fn cycles(&self) -> u64 { self.cycles } @@ -623,7 +652,17 @@ impl SupportMachine for Box { self.cycles = 0; self.max_cycles = max_cycles; self.reset_signal = 1; - self.reset_memory() + + // Reset memory + let slice = cast_ptr_to_slice_mut(self, self.flags_ptr, 0, self.flags_size as usize); + memset(slice, 0); + let slice = cast_ptr_to_slice_mut(self, self.frames_ptr, 0, self.frames_size as usize); + memset(slice, 0); + self.load_reservation_address = u64::MAX; + self.last_read_frame = u64::MAX; + self.last_write_page = u64::MAX; + + Ok(()) } fn reset_signal(&mut self) -> bool { @@ -653,44 +692,38 @@ extern "C" { pub fn ckb_vm_asm_labels(); } -pub struct AsmMachine { - pub machine: DefaultMachine>, -} +/// This builder only works with assembly VMs +pub type AsmDefaultMachineBuilder = + AbstractDefaultMachineBuilder; +pub type AsmDefaultMachine = DefaultMachine; -impl AsmMachine { - pub fn new(machine: DefaultMachine>) -> Self { - Self { machine } - } +pub type AsmMachine = AbstractAsmMachine; - pub fn set_max_cycles(&mut self, cycles: u64) { - self.machine.inner.max_cycles = cycles; - } +pub struct AbstractAsmMachine { + pub machine: DefaultMachine, + phantom: PhantomData, +} - pub fn load_program( - &mut self, - program: &Bytes, - args: impl ExactSizeIterator>, - ) -> Result { - self.machine.load_program(program, args) +impl DefaultMachineRunner for AbstractAsmMachine { + type Inner = AsmCoreMachine; + type Decoder = Decoder; + + fn new(machine: DefaultMachine) -> Self { + Self { + machine, + phantom: PhantomData, + } } - pub fn load_program_with_metadata( - &mut self, - program: &Bytes, - metadata: &ProgramMetadata, - args: impl ExactSizeIterator>, - ) -> Result { - self.machine - .load_program_with_metadata(program, metadata, args) + fn machine(&self) -> &DefaultMachine { + &self.machine } - pub fn run(&mut self) -> Result { - let decoder = build_decoder::(self.machine.isa(), self.machine.version()); - let mut decoder = SimpleFixedTraceDecoder::new(decoder); - self.run_with_decoder(&mut decoder) + fn machine_mut(&mut self) -> &mut DefaultMachine { + &mut self.machine } - pub fn run_with_decoder(&mut self, decoder: &mut D) -> Result { + fn run_with_decoder(&mut self, decoder: &mut Self::Decoder) -> Result { if self.machine.isa() & ISA_MOP != 0 && self.machine.version() == VERSION0 { return Err(Error::InvalidVersion); } @@ -706,7 +739,7 @@ impl AsmMachine { fixed_traces: decoder.fixed_traces(), fixed_trace_mask: decoder.fixed_trace_size().wrapping_sub(1), }; - ckb_vm_x64_execute(&mut **self.machine.inner_mut(), &data as *const _) + ckb_vm_x64_execute(&mut *self.machine.inner_mut(), &data as *const _) }; match result { RET_DECODE_TRACE => decoder.prepare_traces(&mut self.machine)?, @@ -740,8 +773,32 @@ impl AsmMachine { } Ok(self.machine.exit_code()) } +} + +impl AbstractAsmMachine { + pub fn set_max_cycles(&mut self, cycles: u64) { + self.machine.inner.max_cycles = cycles; + } + + pub fn load_program( + &mut self, + program: &Bytes, + args: impl ExactSizeIterator>, + ) -> Result { + self.machine.load_program(program, args) + } + + pub fn load_program_with_metadata( + &mut self, + program: &Bytes, + metadata: &ProgramMetadata, + args: impl ExactSizeIterator>, + ) -> Result { + self.machine + .load_program_with_metadata(program, metadata, args) + } - pub fn step(&mut self, decoder: &mut D) -> Result<(), Error> { + pub fn step(&mut self, decoder: &mut Decoder) -> Result<(), Error> { // Decode only one instruction into a trace let (trace, _) = decode_fixed_trace(decoder, &mut self.machine, Some(1))?; @@ -751,7 +808,7 @@ impl AsmMachine { fixed_traces: &trace as *const FixedTrace, fixed_trace_mask: 0, }; - ckb_vm_x64_execute(&mut **self.machine.inner_mut(), &data as *const _) + ckb_vm_x64_execute(&mut *self.machine.inner_mut(), &data as *const _) }; match result { RET_DECODE_TRACE => (), diff --git a/src/machine/asm/traces.rs b/src/machine/asm/traces.rs index edcc603f..099cf884 100644 --- a/src/machine/asm/traces.rs +++ b/src/machine/asm/traces.rs @@ -5,7 +5,7 @@ use crate::{ Instruction, InstructionOpcode, OP_CUSTOM_ASM_TRACE_JUMP, OP_CUSTOM_TRACE_END, }, }, - decoder::InstDecoder, + decoder::{DefaultDecoder, InstDecoder}, error::Error, instructions::{ blank_instruction, extract_opcode, instruction_length, is_basic_block_end_instruction, @@ -16,6 +16,7 @@ use crate::{ CoreMachine, DefaultMachine, }, memory::Memory, + Register, }; use std::alloc::{alloc, alloc_zeroed, Layout}; use std::collections::HashMap; @@ -25,8 +26,10 @@ pub trait TraceDecoder: InstDecoder { fn fixed_trace_size(&self) -> u64; fn prepare_traces( &mut self, - machine: &mut DefaultMachine>, - ) -> Result<(), Error>; + machine: &mut DefaultMachine, + ) -> Result<(), Error> + where + Self: Sized; fn reset(&mut self) -> Result<(), Error>; } @@ -38,9 +41,9 @@ pub fn label_from_fastpath_opcode(opcode: InstructionOpcode) -> u64 { } } -pub fn decode_fixed_trace( +pub fn decode_fixed_trace( decoder: &mut D, - machine: &mut DefaultMachine>, + machine: &mut DefaultMachine, maximum_insts: Option, ) -> Result<(FixedTrace, usize), Error> { let pc = *machine.pc(); @@ -80,21 +83,12 @@ pub fn decode_fixed_trace( /// A simple and naive trace decoder that only works with 8192 fixed traces. /// It serves as the default implementation. -pub struct SimpleFixedTraceDecoder { +pub struct SimpleFixedTraceDecoder { traces: Box<[FixedTrace; TRACE_SIZE]>, decoder: D, } impl SimpleFixedTraceDecoder { - pub fn new(decoder: D) -> Self { - let traces = unsafe { - let layout = Layout::array::(TRACE_SIZE).unwrap(); - let raw_allocation = alloc_zeroed(layout) as *mut _; - Box::from_raw(raw_allocation) - }; - Self { decoder, traces } - } - pub fn clear_traces(&mut self) { for i in 0..TRACE_SIZE { self.traces[i] = FixedTrace::default(); @@ -113,7 +107,7 @@ impl TraceDecoder for SimpleFixedTraceDecoder { fn prepare_traces( &mut self, - machine: &mut DefaultMachine>, + machine: &mut DefaultMachine, ) -> Result<(), Error> { let (trace, _) = decode_fixed_trace(&mut self.decoder, machine, None)?; let slot = calculate_slot(*machine.pc()); @@ -128,6 +122,16 @@ impl TraceDecoder for SimpleFixedTraceDecoder { } impl InstDecoder for SimpleFixedTraceDecoder { + fn new(isa: u8, version: u32) -> Self { + let decoder = D::new::(isa, version); + let traces = unsafe { + let layout = Layout::array::(TRACE_SIZE).unwrap(); + let raw_allocation = alloc_zeroed(layout) as *mut _; + Box::from_raw(raw_allocation) + }; + Self { decoder, traces } + } + fn decode(&mut self, memory: &mut M, pc: u64) -> Result { self.decoder.decode(memory, pc) } @@ -144,13 +148,6 @@ pub struct MemoizedFixedTraceDecoder { } impl MemoizedFixedTraceDecoder { - pub fn new(decoder: D) -> Self { - Self { - inner: SimpleFixedTraceDecoder::new(decoder), - cache: HashMap::default(), - } - } - pub fn clear_traces(&mut self) { self.inner.clear_traces(); } @@ -167,7 +164,7 @@ impl TraceDecoder for MemoizedFixedTraceDecoder { fn prepare_traces( &mut self, - machine: &mut DefaultMachine>, + machine: &mut DefaultMachine, ) -> Result<(), Error> { let pc = *machine.pc(); let slot = calculate_slot(pc); @@ -190,6 +187,13 @@ impl TraceDecoder for MemoizedFixedTraceDecoder { } impl InstDecoder for MemoizedFixedTraceDecoder { + fn new(isa: u8, version: u32) -> Self { + Self { + inner: SimpleFixedTraceDecoder::new::(isa, version), + cache: HashMap::default(), + } + } + fn decode(&mut self, memory: &mut M, pc: u64) -> Result { self.inner.decode(memory, pc) } @@ -286,14 +290,6 @@ pub struct MemoizedDynamicTraceDecoder { } impl MemoizedDynamicTraceDecoder { - pub fn new(decoder: D) -> Self { - Self { - inner: SimpleFixedTraceDecoder::new(decoder), - fixed_cache: HashMap::default(), - dynamic_cache: HashMap::default(), - } - } - pub fn clear_traces(&mut self) { self.inner.clear_traces(); } @@ -301,7 +297,7 @@ impl MemoizedDynamicTraceDecoder { fn find_or_build_dynamic_trace( &mut self, pc: u64, - machine: &mut DefaultMachine>, + machine: &mut DefaultMachine, ) -> Result<*const DynamicTrace, Error> { if let Some(trace) = self.dynamic_cache.get(&pc) { return Ok(trace.as_ref() as *const DynamicTrace); @@ -334,7 +330,7 @@ impl TraceDecoder for MemoizedDynamicTraceDecoder { fn prepare_traces( &mut self, - machine: &mut DefaultMachine>, + machine: &mut DefaultMachine, ) -> Result<(), Error> { let pc = *machine.pc(); let slot = calculate_slot(pc); @@ -374,6 +370,14 @@ impl TraceDecoder for MemoizedDynamicTraceDecoder { } impl InstDecoder for MemoizedDynamicTraceDecoder { + fn new(isa: u8, version: u32) -> Self { + Self { + inner: SimpleFixedTraceDecoder::new::(isa, version), + fixed_cache: HashMap::default(), + dynamic_cache: HashMap::default(), + } + } + fn decode(&mut self, memory: &mut M, pc: u64) -> Result { self.inner.decode(memory, pc) } diff --git a/src/machine/mod.rs b/src/machine/mod.rs index 7f8d4c68..7145cb23 100644 --- a/src/machine/mod.rs +++ b/src/machine/mod.rs @@ -3,20 +3,21 @@ pub mod asm; pub mod trace; use std::fmt::{self, Display}; +use std::marker::PhantomData; use std::sync::atomic::{AtomicU8, Ordering}; use std::sync::Arc; use bytes::Bytes; use super::debugger::Debugger; -use super::decoder::{build_decoder, InstDecoder}; +use super::decoder::{DefaultDecoder, InstDecoder}; use super::elf::{parse_elf, LoadingAction, ProgramMetadata}; use super::instructions::{execute, Instruction, Register}; use super::memory::{load_c_string_byte_by_byte, Memory}; use super::syscalls::Syscalls; use super::{ registers::{A0, A7, REGISTER_ABI_NAMES, SP}, - Error, ISA_MOP, RISCV_GENERAL_REGISTER_NUMBER, + Error, DEFAULT_MEMORY_SIZE, ISA_MOP, RISCV_GENERAL_REGISTER_NUMBER, }; // Version 0 is the initial launched CKB VM, it is used in CKB Lina mainnet @@ -62,6 +63,19 @@ pub trait Machine: CoreMachine { /// such as ELF range, cycles which might be needed on Rust side of the logic, /// such as runner or syscall implementations. pub trait SupportMachine: CoreMachine { + /// Instantiate using default memory size + fn new(isa: u8, version: u32, max_cycles: u64) -> Self + where + Self: Sized, + { + Self::new_with_memory(isa, version, max_cycles, DEFAULT_MEMORY_SIZE) + } + + /// Instantiation function + fn new_with_memory(isa: u8, version: u32, max_cycles: u64, memory_size: usize) -> Self + where + Self: Sized; + // Current execution cycles, it's up to the actual implementation to // call add_cycles for each instruction/operation to provide cycles. // The implementation might also choose not to do this to ignore this @@ -262,6 +276,58 @@ pub trait SupportMachine: CoreMachine { fn code(&self) -> &Bytes; } +/// A runner trait providing APIs to drive the included DefaultMachine +pub trait DefaultMachineRunner { + type Inner: SupportMachine; + type Decoder: InstDecoder; + + /// Creates a new runner + fn new(machine: DefaultMachine) -> Self; + + /// Fetches DefaultMachine + fn machine(&self) -> &DefaultMachine; + + /// Fetches mutable DefaultMachine + fn machine_mut(&mut self) -> &mut DefaultMachine; + + /// Runs the VM till paused with a custom decoder + fn run_with_decoder(&mut self, decoder: &mut Self::Decoder) -> Result; + + /// Runs the VM till paused + fn run(&mut self) -> Result { + let mut decoder = Self::Decoder::new::<::REG>( + self.machine().isa(), + self.machine().version(), + ); + self.run_with_decoder(&mut decoder) + } + + /// Fetches the inner SupportMachine for more processing + fn inner_mut(&mut self) -> &mut Self::Inner { + self.machine_mut().inner_mut() + } + + /// Loads program + fn load_program( + &mut self, + program: &Bytes, + args: impl ExactSizeIterator>, + ) -> Result { + self.machine_mut().load_program(program, args) + } + + /// Loads program with lazy loading metadata + fn load_program_with_metadata( + &mut self, + program: &Bytes, + metadata: &ProgramMetadata, + args: impl ExactSizeIterator>, + ) -> Result { + self.machine_mut() + .load_program_with_metadata(program, metadata, args) + } +} + #[derive(Default)] pub struct DefaultCoreMachine { registers: [R; RISCV_GENERAL_REGISTER_NUMBER], @@ -319,6 +385,23 @@ impl> CoreMachine for DefaultCoreMachine { } impl> SupportMachine for DefaultCoreMachine { + fn new_with_memory(isa: u8, version: u32, max_cycles: u64, memory_size: usize) -> Self { + Self { + registers: Default::default(), + pc: Default::default(), + next_pc: Default::default(), + reset_signal: Default::default(), + memory: M::new(memory_size), + cycles: Default::default(), + max_cycles, + running: Default::default(), + isa, + version, + #[cfg(feature = "pprof")] + code: Default::default(), + } + } + fn cycles(&self) -> u64 { self.cycles } @@ -338,7 +421,7 @@ impl> SupportMachine for DefaultCoreMachine Result<(), Error> { self.registers = Default::default(); self.pc = Default::default(); - self.memory.reset_memory()?; + self.memory = M::new(self.memory().memory_size()); self.cycles = 0; self.max_cycles = max_cycles; self.reset_signal = true; @@ -387,30 +470,7 @@ impl> SupportMachine for DefaultCoreMachine DefaultCoreMachine { - pub fn new(isa: u8, version: u32, max_cycles: u64) -> Self { - Self::new_with_memory(isa, version, max_cycles, M::default()) - } -} - impl DefaultCoreMachine { - pub fn new_with_memory(isa: u8, version: u32, max_cycles: u64, memory: M) -> Self { - Self { - registers: Default::default(), - pc: Default::default(), - next_pc: Default::default(), - reset_signal: Default::default(), - memory, - cycles: Default::default(), - max_cycles, - running: Default::default(), - isa, - version, - #[cfg(feature = "pprof")] - code: Default::default(), - } - } - pub fn set_max_cycles(&mut self, cycles: u64) { self.max_cycles = cycles; } @@ -422,7 +482,7 @@ impl DefaultCoreMachine { pub type InstructionCycleFunc = dyn Fn(Instruction) -> u64 + Send + Sync; -pub struct DefaultMachine { +pub struct DefaultMachine { inner: Inner, pause: Pause, @@ -434,9 +494,10 @@ pub struct DefaultMachine { debugger: Option>>, syscalls: Vec>>, exit_code: i8, + phantom: PhantomData, } -impl CoreMachine for DefaultMachine { +impl CoreMachine for DefaultMachine { type REG = ::REG; type MEM = ::MEM; @@ -477,7 +538,11 @@ impl CoreMachine for DefaultMachine { } } -impl SupportMachine for DefaultMachine { +impl SupportMachine for DefaultMachine { + fn new_with_memory(_isa: u8, _version: u32, _max_cycles: u64, _memory_size: usize) -> Self { + panic!("Please instantiate DefaultMachine using DefaultMachineBuilder!"); + } + fn cycles(&self) -> u64 { self.inner.cycles() } @@ -529,7 +594,7 @@ impl SupportMachine for DefaultMachine { } } -impl Machine for DefaultMachine { +impl Machine for DefaultMachine { fn ecall(&mut self) -> Result<(), Error> { let code = self.registers()[A7].to_u64(); match code { @@ -565,7 +630,7 @@ impl Machine for DefaultMachine { } } -impl Display for DefaultMachine { +impl Display for DefaultMachine { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { writeln!(f, "pc : 0x{:16X}", self.pc().to_u64())?; for (i, name) in REGISTER_ABI_NAMES.iter().enumerate() { @@ -580,7 +645,44 @@ impl Display for DefaultMachine { } } -impl DefaultMachine { +impl DefaultMachineRunner + for DefaultMachine +{ + type Inner = Inner; + type Decoder = Decoder; + + fn new(machine: DefaultMachine) -> Self { + machine + } + + fn machine(&self) -> &DefaultMachine { + self + } + + fn machine_mut(&mut self) -> &mut DefaultMachine { + self + } + + fn run_with_decoder(&mut self, decoder: &mut Self::Decoder) -> Result { + if self.isa() & ISA_MOP != 0 && self.version() == VERSION0 { + return Err(Error::InvalidVersion); + } + self.set_running(true); + while self.running() { + if self.pause.has_interrupted() { + self.pause.free(); + return Err(Error::Pause); + } + if self.reset_signal() { + decoder.reset_instructions_cache()?; + } + self.step(decoder)?; + } + Ok(self.exit_code()) + } +} + +impl DefaultMachine { pub fn load_program( &mut self, program: &Bytes, @@ -657,33 +759,6 @@ impl DefaultMachine { &mut self.inner } - // This is the most naive way of running the VM, it only decodes each - // instruction and run it, no optimization is performed here. It might - // not be practical in production, but it serves as a baseline and - // reference implementation - pub fn run(&mut self) -> Result { - let mut decoder = build_decoder::(self.isa(), self.version()); - self.run_with_decoder(&mut decoder) - } - - pub fn run_with_decoder(&mut self, decoder: &mut D) -> Result { - if self.isa() & ISA_MOP != 0 && self.version() == VERSION0 { - return Err(Error::InvalidVersion); - } - self.set_running(true); - while self.running() { - if self.pause.has_interrupted() { - self.pause.free(); - return Err(Error::Pause); - } - if self.reset_signal() { - decoder.reset_instructions_cache()?; - } - self.step(decoder)?; - } - Ok(self.exit_code()) - } - pub fn step(&mut self, decoder: &mut D) -> Result<(), Error> { let instruction = { let pc = self.pc().to_u64(); @@ -696,15 +771,19 @@ impl DefaultMachine { } } -pub struct DefaultMachineBuilder { +/// This builder only works with Rust VMs +pub type RustDefaultMachineBuilder = AbstractDefaultMachineBuilder; + +pub struct AbstractDefaultMachineBuilder { inner: Inner, instruction_cycle_func: Box, debugger: Option>>, syscalls: Vec>>, pause: Pause, + phantom: PhantomData, } -impl DefaultMachineBuilder { +impl AbstractDefaultMachineBuilder { pub fn new(inner: Inner) -> Self { Self { inner, @@ -712,6 +791,7 @@ impl DefaultMachineBuilder { debugger: None, syscalls: vec![], pause: Pause::new(), + phantom: PhantomData, } } @@ -738,7 +818,7 @@ impl DefaultMachineBuilder { self } - pub fn build(self) -> DefaultMachine { + pub fn build(self) -> DefaultMachine { DefaultMachine { inner: self.inner, pause: self.pause, @@ -746,6 +826,7 @@ impl DefaultMachineBuilder { debugger: self.debugger, syscalls: self.syscalls, exit_code: 0, + phantom: PhantomData, } } } diff --git a/src/machine/trace.rs b/src/machine/trace.rs index 7978272b..ca34143e 100644 --- a/src/machine/trace.rs +++ b/src/machine/trace.rs @@ -1,6 +1,6 @@ use super::{ super::{ - decoder::{build_decoder, InstDecoder}, + decoder::{DefaultDecoder, InstDecoder}, elf::ProgramMetadata, instructions::{ execute_with_thread, extract_opcode, handle_invalid_op, instruction_length, @@ -8,9 +8,10 @@ use super::{ }, Error, }, - CoreMachine, DefaultMachine, Machine, SupportMachine, VERSION2, + CoreMachine, DefaultMachine, DefaultMachineRunner, Machine, SupportMachine, VERSION2, }; use bytes::Bytes; +use std::marker::PhantomData; // The number of trace items to keep const TRACE_SIZE: usize = 8192; @@ -46,14 +47,17 @@ fn calculate_slot(addr: u64) -> usize { (addr as usize >> TRACE_ADDRESS_SHIFTS) & TRACE_MASK } -pub struct TraceMachine { - pub machine: DefaultMachine, +pub type TraceMachine = AbstractTraceMachine; - factory: ThreadFactory>, - traces: Vec>>, +pub struct AbstractTraceMachine { + pub machine: DefaultMachine, + + factory: ThreadFactory>, + traces: Vec>>, + phantom: PhantomData, } -impl CoreMachine for TraceMachine { +impl CoreMachine for AbstractTraceMachine { type REG = ::REG; type MEM = ::MEM; @@ -94,7 +98,7 @@ impl CoreMachine for TraceMachine { } } -impl Machine for TraceMachine { +impl Machine for AbstractTraceMachine { fn ecall(&mut self) -> Result<(), Error> { self.machine.ecall() } @@ -104,43 +108,30 @@ impl Machine for TraceMachine { } } -impl TraceMachine { - pub fn new(machine: DefaultMachine) -> Self { +impl DefaultMachineRunner + for AbstractTraceMachine +{ + type Inner = Inner; + type Decoder = Decoder; + + fn new(machine: DefaultMachine) -> Self { Self { machine, factory: ThreadFactory::create(), traces: vec![], + phantom: PhantomData, } } - pub fn load_program( - &mut self, - program: &Bytes, - args: impl ExactSizeIterator>, - ) -> Result { - self.machine.load_program(program, args) + fn machine(&self) -> &DefaultMachine { + &self.machine } - pub fn load_program_with_metadata( - &mut self, - program: &Bytes, - metadata: &ProgramMetadata, - args: impl ExactSizeIterator>, - ) -> Result { - self.machine - .load_program_with_metadata(program, metadata, args) + fn machine_mut(&mut self) -> &mut DefaultMachine { + &mut self.machine } - pub fn set_max_cycles(&mut self, cycles: u64) { - self.machine.inner_mut().set_max_cycles(cycles) - } - - pub fn run(&mut self) -> Result { - let mut decoder = build_decoder::(self.isa(), self.version()); - self.run_with_decoder(&mut decoder) - } - - pub fn run_with_decoder(&mut self, decoder: &mut D) -> Result { + fn run_with_decoder(&mut self, decoder: &mut Self::Decoder) -> Result { self.machine.set_running(true); // For current trace size this is acceptable, however we might want // to tweak the code here if we choose to use a larger trace size or @@ -199,6 +190,30 @@ impl TraceMachine { } } +impl AbstractTraceMachine { + pub fn load_program( + &mut self, + program: &Bytes, + args: impl ExactSizeIterator>, + ) -> Result { + self.machine.load_program(program, args) + } + + pub fn load_program_with_metadata( + &mut self, + program: &Bytes, + metadata: &ProgramMetadata, + args: impl ExactSizeIterator>, + ) -> Result { + self.machine + .load_program_with_metadata(program, metadata, args) + } + + pub fn set_max_cycles(&mut self, cycles: u64) { + self.machine.inner_mut().set_max_cycles(cycles) + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/src/memory/flat.rs b/src/memory/flat.rs index 07160584..b7d6f541 100644 --- a/src/memory/flat.rs +++ b/src/memory/flat.rs @@ -1,6 +1,4 @@ -use super::super::{ - error::OutOfBoundKind, Error, Register, DEFAULT_MEMORY_SIZE, RISCV_PAGESIZE, RISCV_PAGE_SHIFTS, -}; +use super::super::{error::OutOfBoundKind, Error, Register, RISCV_PAGESIZE, RISCV_PAGE_SHIFTS}; use super::{check_no_overflow, fill_page_data, get_page_indices, memset, set_dirty, Memory}; use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; @@ -32,8 +30,12 @@ impl DerefMut for FlatMemory { } } -impl FlatMemory { - pub fn new_with_memory(memory_size: usize) -> Self { +/// A flat chunk of memory used for RISC-V machine, it lacks all the permission +/// checking logic. +impl Memory for FlatMemory { + type REG = R; + + fn new(memory_size: usize) -> Self { assert!(memory_size % RISCV_PAGESIZE == 0); Self { data: vec![0; memory_size], @@ -44,25 +46,6 @@ impl FlatMemory { _inner: PhantomData, } } -} - -impl Default for FlatMemory { - fn default() -> Self { - Self::new_with_memory(DEFAULT_MEMORY_SIZE) - } -} - -/// A flat chunk of memory used for RISC-V machine, it lacks all the permission -/// checking logic. -impl Memory for FlatMemory { - type REG = R; - - fn reset_memory(&mut self) -> Result<(), Error> { - memset(&mut self.data, 0); - memset(&mut self.flags, 0); - self.load_reservation_address = R::from_u64(u64::MAX); - Ok(()) - } fn init_pages( &mut self, diff --git a/src/memory/mod.rs b/src/memory/mod.rs index e184497d..d72349d0 100644 --- a/src/memory/mod.rs +++ b/src/memory/mod.rs @@ -31,7 +31,7 @@ pub type Page = [u8; RISCV_PAGESIZE]; pub trait Memory { type REG: Register; - fn reset_memory(&mut self) -> Result<(), Error>; + fn new(memory_size: usize) -> Self; fn init_pages( &mut self, diff --git a/src/memory/sparse.rs b/src/memory/sparse.rs index 09cf9178..8c4d54ba 100644 --- a/src/memory/sparse.rs +++ b/src/memory/sparse.rs @@ -1,6 +1,4 @@ -use super::super::{ - error::OutOfBoundKind, Error, Register, DEFAULT_MEMORY_SIZE, RISCV_PAGESIZE, RISCV_PAGE_SHIFTS, -}; +use super::super::{error::OutOfBoundKind, Error, Register, RISCV_PAGESIZE, RISCV_PAGE_SHIFTS}; use super::{check_no_overflow, fill_page_data, memset, round_page_down, Memory, Page, FLAG_DIRTY}; use bytes::Bytes; @@ -67,8 +65,12 @@ impl SparseMemory { } Ok(value) } +} + +impl Memory for SparseMemory { + type REG = R; - pub fn new_with_memory(memory_size: usize) -> Self { + fn new(memory_size: usize) -> Self { assert!(memory_size % RISCV_PAGESIZE == 0); Self { indices: vec![INVALID_PAGE_INDEX; memory_size / RISCV_PAGESIZE], @@ -80,24 +82,6 @@ impl SparseMemory { _inner: PhantomData, } } -} - -impl Default for SparseMemory { - fn default() -> Self { - Self::new_with_memory(DEFAULT_MEMORY_SIZE) - } -} - -impl Memory for SparseMemory { - type REG = R; - - fn reset_memory(&mut self) -> Result<(), Error> { - self.indices = vec![INVALID_PAGE_INDEX; self.indices.len()]; - memset(&mut self.flags, 0); - self.pages.clear(); - self.load_reservation_address = R::from_u64(u64::MAX); - Ok(()) - } fn init_pages( &mut self, diff --git a/src/memory/wxorx.rs b/src/memory/wxorx.rs index 8d773852..e1993c25 100644 --- a/src/memory/wxorx.rs +++ b/src/memory/wxorx.rs @@ -14,23 +14,15 @@ impl WXorXMemory { pub fn inner_mut(&mut self) -> &mut M { &mut self.inner } - - pub fn new(inner: M) -> Self { - Self { inner } - } -} - -impl Default for WXorXMemory { - fn default() -> Self { - Self::new(M::default()) - } } impl Memory for WXorXMemory { type REG = M::REG; - fn reset_memory(&mut self) -> Result<(), Error> { - self.inner.reset_memory() + fn new(memory_size: usize) -> Self { + Self { + inner: M::new(memory_size), + } } fn init_pages( diff --git a/tests/machine_build.rs b/tests/machine_build.rs index 2c50704f..00742108 100644 --- a/tests/machine_build.rs +++ b/tests/machine_build.rs @@ -1,11 +1,12 @@ use bytes::Bytes; use ckb_vm::cost_model::constant_cycles; #[cfg(has_asm)] -use ckb_vm::machine::asm::{AsmCoreMachine, AsmMachine}; +use ckb_vm::machine::asm::{AsmCoreMachine, AsmDefaultMachineBuilder, AsmMachine}; use ckb_vm::machine::{trace::TraceMachine, DefaultCoreMachine}; use ckb_vm::registers::{A0, A7}; use ckb_vm::{ - DefaultMachineBuilder, Error, Register, SparseMemory, SupportMachine, Syscalls, WXorXMemory, + DefaultMachineRunner, Error, Register, RustDefaultMachineBuilder, SparseMemory, SupportMachine, + Syscalls, WXorXMemory, }; pub struct SleepSyscall {} @@ -32,7 +33,7 @@ impl Syscalls for SleepSyscall { pub fn asm(path: &str, args: Vec, version: u32, isa: u8) -> AsmMachine { let buffer: Bytes = std::fs::read(path).unwrap().into(); let asm_core = AsmCoreMachine::new(isa, version, u64::MAX); - let core = DefaultMachineBuilder::>::new(asm_core) + let core = AsmDefaultMachineBuilder::new(asm_core) .instruction_cycle_func(Box::new(constant_cycles)) .syscall(Box::new(SleepSyscall {})) .build(); @@ -53,7 +54,7 @@ pub fn int( let core_machine = DefaultCoreMachine::>>::new(isa, version, u64::MAX); let mut machine = TraceMachine::new( - DefaultMachineBuilder::new(core_machine) + RustDefaultMachineBuilder::new(core_machine) .instruction_cycle_func(Box::new(constant_cycles)) .syscall(Box::new(SleepSyscall {})) .build(), diff --git a/tests/test_a_extension.rs b/tests/test_a_extension.rs index 9ea49d2e..1e8afe41 100644 --- a/tests/test_a_extension.rs +++ b/tests/test_a_extension.rs @@ -1,4 +1,4 @@ -use ckb_vm::{machine::VERSION2, Error, ISA_A, ISA_IMC}; +use ckb_vm::{machine::VERSION2, DefaultMachineRunner, Error, ISA_A, ISA_IMC}; #[cfg(has_asm)] use ckb_vm::{CoreMachine, Memory}; pub mod machine_build; diff --git a/tests/test_asm.rs b/tests/test_asm.rs index d57a63e4..f6a8586b 100644 --- a/tests/test_asm.rs +++ b/tests/test_asm.rs @@ -1,13 +1,17 @@ #![cfg(has_asm)] use ckb_vm::cost_model::constant_cycles; -use ckb_vm::decoder::build_decoder; +use ckb_vm::decoder::{DefaultDecoder, InstDecoder}; use ckb_vm::error::OutOfBoundKind; -use ckb_vm::machine::asm::traces::{MemoizedDynamicTraceDecoder, MemoizedFixedTraceDecoder}; -use ckb_vm::machine::asm::{AsmCoreMachine, AsmMachine}; -use ckb_vm::machine::{CoreMachine, VERSION0, VERSION1, VERSION2}; +use ckb_vm::machine::asm::traces::{ + MemoizedDynamicTraceDecoder, MemoizedFixedTraceDecoder, SimpleFixedTraceDecoder, +}; +use ckb_vm::machine::asm::{ + AbstractAsmMachine, AsmCoreMachine, AsmDefaultMachineBuilder, AsmMachine, +}; +use ckb_vm::machine::{AbstractDefaultMachineBuilder, CoreMachine, VERSION0, VERSION1, VERSION2}; use ckb_vm::memory::Memory; use ckb_vm::registers::{A0, A1, A2, A3, A4, A5, A7}; -use ckb_vm::{Debugger, DefaultMachineBuilder, Error, Register, SupportMachine, Syscalls, ISA_IMC}; +use ckb_vm::{Debugger, DefaultMachineRunner, Error, Register, SupportMachine, Syscalls, ISA_IMC}; use std::fs; use std::sync::atomic::{AtomicU8, Ordering}; use std::sync::Arc; @@ -17,8 +21,8 @@ pub mod machine_build; #[test] pub fn test_asm_simple64() { let buffer = fs::read("tests/programs/simple64").unwrap().into(); - let asm_core = AsmCoreMachine::new(ISA_IMC, VERSION0, u64::MAX); - let core = DefaultMachineBuilder::new(asm_core).build(); + let asm_core = ::new(ISA_IMC, VERSION0, u64::MAX); + let core = AsmDefaultMachineBuilder::new(asm_core).build(); let mut machine = AsmMachine::new(core); machine .load_program(&buffer, [Ok("simple".into())].into_iter()) @@ -54,8 +58,8 @@ impl Syscalls for CustomSyscall { #[test] pub fn test_asm_with_custom_syscall() { let buffer = fs::read("tests/programs/syscall64").unwrap().into(); - let asm_core = AsmCoreMachine::new(ISA_IMC, VERSION0, u64::MAX); - let core = DefaultMachineBuilder::new(asm_core) + let asm_core = ::new(ISA_IMC, VERSION0, u64::MAX); + let core = AsmDefaultMachineBuilder::new(asm_core) .syscall(Box::new(CustomSyscall {})) .build(); let mut machine = AsmMachine::new(core); @@ -88,8 +92,8 @@ pub fn test_asm_ebreak() { let buffer = fs::read("tests/programs/ebreak64").unwrap().into(); let value = Arc::new(AtomicU8::new(0)); - let asm_core = AsmCoreMachine::new(ISA_IMC, VERSION0, u64::MAX); - let core = DefaultMachineBuilder::new(asm_core) + let asm_core = ::new(ISA_IMC, VERSION0, u64::MAX); + let core = AsmDefaultMachineBuilder::new(asm_core) .debugger(Box::new(CustomDebugger { value: Arc::clone(&value), })) @@ -107,8 +111,8 @@ pub fn test_asm_ebreak() { #[test] pub fn test_asm_simple_cycles() { let buffer = fs::read("tests/programs/simple64").unwrap().into(); - let asm_core = AsmCoreMachine::new(ISA_IMC, VERSION0, 708); - let core = DefaultMachineBuilder::new(asm_core) + let asm_core = ::new(ISA_IMC, VERSION0, 708); + let core = AsmDefaultMachineBuilder::new(asm_core) .instruction_cycle_func(Box::new(constant_cycles)) .build(); let mut machine = AsmMachine::new(core); @@ -126,8 +130,8 @@ pub fn test_asm_simple_cycles() { pub fn test_asm_simple_max_cycles_reached() { let buffer = fs::read("tests/programs/simple64").unwrap().into(); // Running simple64 should consume 708 cycles using dummy cycle func - let asm_core = AsmCoreMachine::new(ISA_IMC, VERSION0, 700); - let core = DefaultMachineBuilder::>::new(asm_core) + let asm_core = ::new(ISA_IMC, VERSION0, 700); + let core = AsmDefaultMachineBuilder::new(asm_core) .instruction_cycle_func(Box::new(constant_cycles)) .build(); let mut machine = AsmMachine::new(core); @@ -142,8 +146,8 @@ pub fn test_asm_simple_max_cycles_reached() { #[test] pub fn test_asm_trace() { let buffer = fs::read("tests/programs/trace64").unwrap().into(); - let asm_core = AsmCoreMachine::new(ISA_IMC, VERSION0, u64::MAX); - let core = DefaultMachineBuilder::new(asm_core).build(); + let asm_core = ::new(ISA_IMC, VERSION0, u64::MAX); + let core = AsmDefaultMachineBuilder::new(asm_core).build(); let mut machine = AsmMachine::new(core); machine .load_program(&buffer, [Ok("simple".into())].into_iter()) @@ -156,8 +160,8 @@ pub fn test_asm_trace() { #[test] pub fn test_asm_jump0() { let buffer = fs::read("tests/programs/jump0_64").unwrap().into(); - let asm_core = AsmCoreMachine::new(ISA_IMC, VERSION0, u64::MAX); - let core = DefaultMachineBuilder::new(asm_core).build(); + let asm_core = ::new(ISA_IMC, VERSION0, u64::MAX); + let core = AsmDefaultMachineBuilder::new(asm_core).build(); let mut machine = AsmMachine::new(core); machine .load_program(&buffer, [Ok("jump0_64".into())].into_iter()) @@ -172,8 +176,8 @@ pub fn test_asm_write_large_address() { let buffer = fs::read("tests/programs/write_large_address64") .unwrap() .into(); - let asm_core = AsmCoreMachine::new(ISA_IMC, VERSION0, u64::MAX); - let core = DefaultMachineBuilder::new(asm_core).build(); + let asm_core = ::new(ISA_IMC, VERSION0, u64::MAX); + let core = AsmDefaultMachineBuilder::new(asm_core).build(); let mut machine = AsmMachine::new(core); machine .load_program(&buffer, [Ok("write_large_address64".into())].into_iter()) @@ -189,8 +193,8 @@ pub fn test_asm_write_large_address() { #[test] pub fn test_misaligned_jump64() { let buffer = fs::read("tests/programs/misaligned_jump64").unwrap().into(); - let asm_core = AsmCoreMachine::new(ISA_IMC, VERSION0, u64::MAX); - let core = DefaultMachineBuilder::new(asm_core).build(); + let asm_core = ::new(ISA_IMC, VERSION0, u64::MAX); + let core = AsmDefaultMachineBuilder::new(asm_core).build(); let mut machine = AsmMachine::new(core); machine .load_program(&buffer, [Ok("misaligned_jump64".into())].into_iter()) @@ -202,8 +206,8 @@ pub fn test_misaligned_jump64() { #[test] pub fn test_mulw64() { let buffer = fs::read("tests/programs/mulw64").unwrap().into(); - let asm_core = AsmCoreMachine::new(ISA_IMC, VERSION0, u64::MAX); - let core = DefaultMachineBuilder::new(asm_core).build(); + let asm_core = ::new(ISA_IMC, VERSION0, u64::MAX); + let core = AsmDefaultMachineBuilder::new(asm_core).build(); let mut machine = AsmMachine::new(core); machine .load_program(&buffer, [Ok("mulw64".into())].into_iter()) @@ -216,8 +220,8 @@ pub fn test_mulw64() { #[test] pub fn test_invalid_read64() { let buffer = fs::read("tests/programs/invalid_read64").unwrap().into(); - let asm_core = AsmCoreMachine::new(ISA_IMC, VERSION0, u64::MAX); - let core = DefaultMachineBuilder::new(asm_core).build(); + let asm_core = ::new(ISA_IMC, VERSION0, u64::MAX); + let core = AsmDefaultMachineBuilder::new(asm_core).build(); let mut machine = AsmMachine::new(core); machine .load_program(&buffer, [Ok("invalid_read64".into())].into_iter()) @@ -236,8 +240,8 @@ pub fn test_invalid_read64() { #[test] pub fn test_asm_load_elf_crash_64() { let buffer = fs::read("tests/programs/load_elf_crash_64").unwrap().into(); - let asm_core = AsmCoreMachine::new(ISA_IMC, VERSION0, u64::MAX); - let core = DefaultMachineBuilder::new(asm_core).build(); + let asm_core = ::new(ISA_IMC, VERSION0, u64::MAX); + let core = AsmDefaultMachineBuilder::new(asm_core).build(); let mut machine = AsmMachine::new(core); machine .load_program(&buffer, [Ok("load_elf_crash_64".into())].into_iter()) @@ -249,8 +253,8 @@ pub fn test_asm_load_elf_crash_64() { #[test] pub fn test_asm_wxorx_crash_64() { let buffer = fs::read("tests/programs/wxorx_crash_64").unwrap().into(); - let asm_core = AsmCoreMachine::new(ISA_IMC, VERSION0, u64::MAX); - let core = DefaultMachineBuilder::new(asm_core).build(); + let asm_core = ::new(ISA_IMC, VERSION0, u64::MAX); + let core = AsmDefaultMachineBuilder::new(asm_core).build(); let mut machine = AsmMachine::new(core); machine .load_program(&buffer, [Ok("wxorx_crash_64".into())].into_iter()) @@ -268,8 +272,8 @@ pub fn test_asm_wxorx_crash_64() { #[test] pub fn test_asm_alloc_many() { let buffer = fs::read("tests/programs/alloc_many").unwrap().into(); - let asm_core = AsmCoreMachine::new(ISA_IMC, VERSION0, u64::MAX); - let core = DefaultMachineBuilder::new(asm_core).build(); + let asm_core = ::new(ISA_IMC, VERSION0, u64::MAX); + let core = AsmDefaultMachineBuilder::new(asm_core).build(); let mut machine = AsmMachine::new(core); machine .load_program(&buffer, [Ok("alloc_many".into())].into_iter()) @@ -281,10 +285,10 @@ pub fn test_asm_alloc_many() { #[test] pub fn test_asm_chaos_seed() { let buffer = fs::read("tests/programs/read_memory").unwrap().into(); - let mut asm_core1 = AsmCoreMachine::new(ISA_IMC, VERSION1, u64::MAX); + let mut asm_core1 = ::new(ISA_IMC, VERSION1, u64::MAX); asm_core1.chaos_mode = 1; asm_core1.chaos_seed = 100; - let core1 = DefaultMachineBuilder::>::new(asm_core1).build(); + let core1 = AsmDefaultMachineBuilder::new(asm_core1).build(); let mut machine1 = AsmMachine::new(core1); machine1 .load_program(&buffer, [Ok("read_memory".into())].into_iter()) @@ -292,10 +296,10 @@ pub fn test_asm_chaos_seed() { let result1 = machine1.run(); let exit1 = result1.unwrap(); - let mut asm_core2 = AsmCoreMachine::new(ISA_IMC, VERSION1, u64::MAX); + let mut asm_core2 = ::new(ISA_IMC, VERSION1, u64::MAX); asm_core2.chaos_mode = 1; asm_core2.chaos_seed = 100; - let core2 = DefaultMachineBuilder::>::new(asm_core2).build(); + let core2 = AsmDefaultMachineBuilder::new(asm_core2).build(); let mut machine2 = AsmMachine::new(core2); machine2 .load_program(&buffer, [Ok("read_memory".into())].into_iter()) @@ -312,8 +316,8 @@ pub fn test_asm_chaos_seed() { #[test] pub fn test_asm_rvc_pageend() { let buffer = fs::read("tests/programs/rvc_pageend").unwrap().into(); - let asm_core = AsmCoreMachine::new(ISA_IMC, VERSION0, u64::MAX); - let core = DefaultMachineBuilder::new(asm_core).build(); + let asm_core = ::new(ISA_IMC, VERSION0, u64::MAX); + let core = AsmDefaultMachineBuilder::new(asm_core).build(); let mut machine = AsmMachine::new(core); machine .load_program(&buffer, [Ok("rvc_pageend".into())].into_iter()) @@ -350,8 +354,8 @@ impl Syscalls for OutOfCyclesSyscall { #[test] pub fn test_asm_outofcycles_in_syscall() { let buffer = fs::read("tests/programs/syscall64").unwrap().into(); - let asm_core = AsmCoreMachine::new(ISA_IMC, VERSION0, 20); - let core = DefaultMachineBuilder::new(asm_core) + let asm_core = ::new(ISA_IMC, VERSION0, 20); + let core = AsmDefaultMachineBuilder::new(asm_core) .instruction_cycle_func(Box::new(constant_cycles)) .syscall(Box::new(OutOfCyclesSyscall {})) .build(); @@ -369,8 +373,8 @@ pub fn test_asm_outofcycles_in_syscall() { #[test] pub fn test_asm_cycles_overflow() { let buffer = fs::read("tests/programs/simple64").unwrap().into(); - let asm_core = AsmCoreMachine::new(ISA_IMC, VERSION0, u64::MAX); - let core = DefaultMachineBuilder::>::new(asm_core) + let asm_core = ::new(ISA_IMC, VERSION0, u64::MAX); + let core = AsmDefaultMachineBuilder::new(asm_core) .instruction_cycle_func(Box::new(constant_cycles)) .build(); let mut machine = AsmMachine::new(core); @@ -388,8 +392,8 @@ pub fn test_decoder_instructions_cache_pc_out_of_bound_timeout() { let buffer = fs::read("tests/programs/decoder_instructions_cache_pc_out_of_bound_timeout") .unwrap() .into(); - let asm_core = AsmCoreMachine::new(ISA_IMC, VERSION0, u64::MAX); - let core = DefaultMachineBuilder::>::new(asm_core) + let asm_core = ::new(ISA_IMC, VERSION0, u64::MAX); + let core = AsmDefaultMachineBuilder::new(asm_core) .instruction_cycle_func(Box::new(constant_cycles)) .build(); let mut machine = AsmMachine::new(core); @@ -408,15 +412,15 @@ pub fn test_decoder_instructions_cache_pc_out_of_bound_timeout() { #[test] fn test_asm_step() { let buffer = fs::read("tests/programs/simple64").unwrap().into(); - let asm_core = AsmCoreMachine::new(ISA_IMC, VERSION0, u64::MAX); - let core = DefaultMachineBuilder::new(asm_core).build(); + let asm_core = ::new(ISA_IMC, VERSION0, u64::MAX); + let core = AsmDefaultMachineBuilder::new(asm_core).build(); let mut machine = AsmMachine::new(core); machine .load_program(&buffer, [Ok("simple64".into())].into_iter()) .unwrap(); let result = || -> Result { - let mut decoder = build_decoder::(ISA_IMC, VERSION0); + let mut decoder = SimpleFixedTraceDecoder::new::(ISA_IMC, VERSION0); machine.machine.set_running(true); while machine.machine.running() { machine.step(&mut decoder)?; @@ -431,8 +435,8 @@ fn test_asm_step() { #[test] fn test_asm_thread_safe() { let buffer = fs::read("tests/programs/mulw64").unwrap().into(); - let asm_core = AsmCoreMachine::new(ISA_IMC, VERSION0, u64::MAX); - let core = DefaultMachineBuilder::new(asm_core).build(); + let asm_core = ::new(ISA_IMC, VERSION0, u64::MAX); + let core = AsmDefaultMachineBuilder::new(asm_core).build(); let mut machine = AsmMachine::new(core); machine .load_program(&buffer, [Ok("mulw64".into())].into_iter()) @@ -448,8 +452,8 @@ fn test_asm_thread_safe() { #[test] fn test_zero_address() { let buffer = fs::read("tests/programs/zero_address").unwrap().into(); - let asm_core = AsmCoreMachine::new(ISA_IMC, VERSION1, u64::MAX); - let core = DefaultMachineBuilder::new(asm_core).build(); + let asm_core = ::new(ISA_IMC, VERSION1, u64::MAX); + let core = AsmDefaultMachineBuilder::new(asm_core).build(); let mut machine = AsmMachine::new(core); machine .load_program(&buffer, [Ok("zero".into())].into_iter()) @@ -464,9 +468,12 @@ fn test_memoized_secp256k1() { let isa = ISA_IMC; let version = VERSION1; let buffer = fs::read("benches/data/secp256k1_bench").unwrap().into(); - let asm_core = AsmCoreMachine::new(isa, version, u64::MAX); - let core = DefaultMachineBuilder::new(asm_core).build(); - let mut machine = AsmMachine::new(core); + let asm_core = ::new(isa, version, u64::MAX); + let core = AbstractDefaultMachineBuilder::<_, MemoizedFixedTraceDecoder>::new( + asm_core, + ) + .build(); + let mut machine = AbstractAsmMachine::new(core); let args = [ "secp256k1_bench", "033f8cf9c4d51a33206a6c1c6b27d2cc5129daa19dbd1fc148d395284f6b26411f", @@ -475,7 +482,7 @@ fn test_memoized_secp256k1() { "bar", ].into_iter().map(|a| Ok(a.into())); machine.load_program(&buffer, args).unwrap(); - let mut decoder = MemoizedFixedTraceDecoder::new(build_decoder::(isa, version)); + let mut decoder = MemoizedFixedTraceDecoder::new::(isa, version); let result = machine.run_with_decoder(&mut decoder); assert_eq!(result.unwrap(), 0); } @@ -485,9 +492,13 @@ fn test_memoized_dynamic_secp256k1() { let isa = ISA_IMC; let version = VERSION1; let buffer = fs::read("benches/data/secp256k1_bench").unwrap().into(); - let asm_core = AsmCoreMachine::new(isa, version, u64::MAX); - let core = DefaultMachineBuilder::new(asm_core).build(); - let mut machine = AsmMachine::new(core); + let asm_core = ::new(isa, version, u64::MAX); + let core = + AbstractDefaultMachineBuilder::<_, MemoizedDynamicTraceDecoder>::new( + asm_core, + ) + .build(); + let mut machine = AbstractAsmMachine::new(core); let args = [ "secp256k1_bench", "033f8cf9c4d51a33206a6c1c6b27d2cc5129daa19dbd1fc148d395284f6b26411f", @@ -496,7 +507,7 @@ fn test_memoized_dynamic_secp256k1() { "bar", ].into_iter().map(|a| Ok(a.into())); machine.load_program(&buffer, args).unwrap(); - let mut decoder = MemoizedDynamicTraceDecoder::new(build_decoder::(isa, version)); + let mut decoder = MemoizedDynamicTraceDecoder::new::(isa, version); let result = machine.run_with_decoder(&mut decoder); assert_eq!(result.unwrap(), 0); } @@ -504,8 +515,13 @@ fn test_memoized_dynamic_secp256k1() { #[test] pub fn test_big_binary() { let buffer = fs::read("tests/programs/big_binary").unwrap().into(); - let asm_core = AsmCoreMachine::new_with_memory(ISA_IMC, VERSION2, u64::MAX, 1024 * 512); - let core = DefaultMachineBuilder::new(asm_core).build(); + let asm_core = ::new_with_memory( + ISA_IMC, + VERSION2, + u64::MAX, + 1024 * 512, + ); + let core = AsmDefaultMachineBuilder::new(asm_core).build(); let mut machine = AsmMachine::new(core); let result = machine.load_program(&buffer, [Ok("simple".into())].into_iter()); assert_eq!( @@ -520,8 +536,8 @@ fn test_fast_memory_initialization_bug() { let isa = ISA_IMC; let version = VERSION1; let buffer = fs::read("benches/data/secp256k1_bench").unwrap().into(); - let asm_core = AsmCoreMachine::new(isa, version, u64::MAX); - let core = DefaultMachineBuilder::new(asm_core).build(); + let asm_core = ::new(isa, version, u64::MAX); + let core = AsmDefaultMachineBuilder::new(asm_core).build(); let mut machine = AsmMachine::new(core); unsafe { let memory = machine.machine.inner_mut().memory_ptr as *mut u8; @@ -534,8 +550,8 @@ fn test_fast_memory_initialization_bug() { #[test] pub fn test_memory_load_crash() { let buffer = fs::read("tests/programs/memory_crash").unwrap().into(); - let asm_core = AsmCoreMachine::new(ISA_IMC, VERSION0, u64::MAX); - let core = DefaultMachineBuilder::new(asm_core).build(); + let asm_core = ::new(ISA_IMC, VERSION0, u64::MAX); + let core = AsmDefaultMachineBuilder::new(asm_core).build(); let mut machine = AsmMachine::new(core); let result = machine.load_program(&buffer, [Ok("memory_crash".into())].into_iter()); assert_eq!(result.unwrap_err(), Error::MemWriteOnExecutablePage(1023)); diff --git a/tests/test_auipc_fusion.rs b/tests/test_auipc_fusion.rs index 65e287c0..b8723a6e 100644 --- a/tests/test_auipc_fusion.rs +++ b/tests/test_auipc_fusion.rs @@ -1,28 +1,29 @@ -use ckb_vm::decoder::{build_decoder, Decoder, InstDecoder}; +use ckb_vm::decoder::{DefaultDecoder, InstDecoder}; use ckb_vm::instructions::{ extract_opcode, instruction_length, set_instruction_length_n, Instruction, Utype, }; #[cfg(has_asm)] -use ckb_vm::machine::asm::{traces::SimpleFixedTraceDecoder, AsmCoreMachine, AsmMachine}; +use ckb_vm::machine::asm::{traces::SimpleFixedTraceDecoder, AbstractAsmMachine, AsmCoreMachine}; use ckb_vm::machine::VERSION1; use ckb_vm::{ - CoreMachine, DefaultCoreMachine, DefaultMachineBuilder, Error, Memory, SparseMemory, ISA_IMC, + machine::AbstractDefaultMachineBuilder, CoreMachine, DefaultCoreMachine, DefaultMachineRunner, + Error, Memory, Register, SparseMemory, SupportMachine, ISA_IMC, }; use ckb_vm_definitions::instructions as insts; use std::fs; // This is simplified from https://github.com/xxuejie/ckb-vm-contrib/blob/main/src/decoder.rs pub struct AuxDecoder { - inner: Decoder, + inner: DefaultDecoder, } -impl AuxDecoder { - pub fn new(inner: Decoder) -> Self { - Self { inner } +impl InstDecoder for AuxDecoder { + fn new(isa: u8, version: u32) -> Self { + Self { + inner: DefaultDecoder::new::(isa, version), + } } -} -impl InstDecoder for AuxDecoder { fn decode(&mut self, memory: &mut M, pc: u64) -> Result { let head_inst = self.inner.decode(memory, pc)?; match extract_opcode(head_inst) { @@ -56,12 +57,12 @@ pub fn test_rust_auipc_fusion() { let core_machine = DefaultCoreMachine::>::new(ISA_IMC, VERSION1, u64::MAX); - let mut machine = DefaultMachineBuilder::new(core_machine).build(); + let mut machine = AbstractDefaultMachineBuilder::<_, AuxDecoder>::new(core_machine).build(); machine .load_program(&buffer, [Ok("auipc_no_sign_extend".into())].into_iter()) .unwrap(); - let mut decoder = AuxDecoder::new(build_decoder::(machine.isa(), machine.version())); + let mut decoder = AuxDecoder::new::(machine.isa(), machine.version()); let result = machine.run_with_decoder(&mut decoder).unwrap(); assert_eq!(result, 0); } @@ -73,18 +74,19 @@ pub fn test_asm_auipc_fusion() { .unwrap() .into(); - let asm_core = AsmCoreMachine::new(ISA_IMC, VERSION1, u64::MAX); - let core = DefaultMachineBuilder::>::new(asm_core).build(); - let mut machine = AsmMachine::new(core); + let asm_core = ::new(ISA_IMC, VERSION1, u64::MAX); + let core = + AbstractDefaultMachineBuilder::<_, SimpleFixedTraceDecoder>::new(asm_core) + .build(); + let mut machine = AbstractAsmMachine::new(core); machine .load_program(&buffer, [Ok("auipc_no_sign_extend".into())].into_iter()) .unwrap(); - let decoder = AuxDecoder::new(build_decoder::( + let mut decoder = SimpleFixedTraceDecoder::::new::( machine.machine.isa(), machine.machine.version(), - )); - let mut decoder = SimpleFixedTraceDecoder::new(decoder); + ); let result = machine.run_with_decoder(&mut decoder).expect("run"); assert_eq!(result, 0); diff --git a/tests/test_b_extension.rs b/tests/test_b_extension.rs index bab7d931..346ee31f 100644 --- a/tests/test_b_extension.rs +++ b/tests/test_b_extension.rs @@ -2,6 +2,8 @@ use ckb_vm::{machine::VERSION1, ISA_B, ISA_IMC}; pub mod machine_build; +use ckb_vm::DefaultMachineRunner; + #[test] pub fn test_clzw_bug() { let mut machine = diff --git a/tests/test_dy_memory.rs b/tests/test_dy_memory.rs index 21094e12..81a83b2a 100644 --- a/tests/test_dy_memory.rs +++ b/tests/test_dy_memory.rs @@ -2,10 +2,10 @@ use ckb_vm::{error::OutOfBoundKind, run_with_memory, FlatMemory, SparseMemory}; #[cfg(has_asm)] use ckb_vm::{ machine::{ - asm::{AsmCoreMachine, AsmMachine}, - DefaultMachineBuilder, VERSION0, VERSION2, + asm::{AsmCoreMachine, AsmDefaultMachineBuilder, AsmMachine}, + VERSION0, VERSION2, }, - ISA_B, ISA_IMC, ISA_MOP, + DefaultMachineRunner, SupportMachine, ISA_B, ISA_IMC, ISA_MOP, }; use std::fs; @@ -14,7 +14,7 @@ fn run_memory_suc(memory_size: usize, bin_path: String, bin_name: String) { let result = run_with_memory::>( &buffer, &vec![bin_name.clone().into()], - SparseMemory::new_with_memory(memory_size), + memory_size, ); assert!(result.is_ok()); assert_eq!(result.unwrap(), 0); @@ -22,7 +22,7 @@ fn run_memory_suc(memory_size: usize, bin_path: String, bin_name: String) { let result = run_with_memory::>( &buffer, &vec![bin_name.clone().into()], - FlatMemory::new_with_memory(memory_size), + memory_size, ); assert!(result.is_ok()); assert_eq!(result.unwrap(), 0); @@ -30,7 +30,7 @@ fn run_memory_suc(memory_size: usize, bin_path: String, bin_name: String) { #[cfg(has_asm)] { let asm_core = AsmCoreMachine::new_with_memory(ISA_IMC, VERSION0, u64::MAX, memory_size); - let core = DefaultMachineBuilder::new(asm_core).build(); + let core = AsmDefaultMachineBuilder::new(asm_core).build(); let mut machine = AsmMachine::new(core); machine .load_program(&buffer, [Ok(bin_name.into())].into_iter()) @@ -54,22 +54,16 @@ fn test_dy_memory() { fn test_memory_out_of_bounds() { let memory_size = 1024 * 256; let buffer = fs::read("tests/programs/alloc_many").unwrap().into(); - let result = run_with_memory::>( - &buffer, - &vec!["alloc_many".into()], - SparseMemory::new_with_memory(memory_size), - ); + let result = + run_with_memory::>(&buffer, &vec!["alloc_many".into()], memory_size); assert!(result.is_err()); assert_eq!( ckb_vm::Error::MemOutOfBound(0xfffffffffff3ffb8, OutOfBoundKind::Memory), result.err().unwrap() ); - let result = run_with_memory::>( - &buffer, - &vec!["alloc_many".into()], - FlatMemory::new_with_memory(memory_size), - ); + let result = + run_with_memory::>(&buffer, &vec!["alloc_many".into()], memory_size); assert!(result.is_err()); assert_eq!( ckb_vm::Error::MemOutOfBound(0xfffffffffff3ffb8, OutOfBoundKind::Memory), @@ -84,7 +78,7 @@ fn test_memory_out_of_bounds() { u64::MAX, memory_size, ); - let core = DefaultMachineBuilder::new(asm_core).build(); + let core = AsmDefaultMachineBuilder::new(asm_core).build(); let mut machine = AsmMachine::new(core); machine .load_program(&buffer, [Ok("alloc_many".into())].into_iter()) diff --git a/tests/test_misc.rs b/tests/test_misc.rs index 3d36f2fe..dad1cb00 100644 --- a/tests/test_misc.rs +++ b/tests/test_misc.rs @@ -3,9 +3,9 @@ use ckb_vm::error::OutOfBoundKind; use ckb_vm::machine::{VERSION0, VERSION1, VERSION2}; use ckb_vm::registers::{A0, A1, A2, A3, A4, A5, A7}; use ckb_vm::{ - run, CoreMachine, Debugger, DefaultCoreMachine, DefaultMachineBuilder, Error, FlatMemory, - Memory, Register, SparseMemory, SupportMachine, Syscalls, WXorXMemory, DEFAULT_MEMORY_SIZE, - ISA_B, ISA_IMC, RISCV_PAGESIZE, + run, CoreMachine, Debugger, DefaultCoreMachine, DefaultMachineRunner, Error, FlatMemory, + Memory, Register, RustDefaultMachineBuilder, SparseMemory, SupportMachine, Syscalls, + WXorXMemory, DEFAULT_MEMORY_SIZE, ISA_B, ISA_IMC, RISCV_PAGESIZE, }; #[cfg(has_asm)] use ckb_vm_definitions::asm::AsmCoreMachine; @@ -59,7 +59,7 @@ pub fn test_custom_syscall() { let buffer = fs::read("tests/programs/syscall64").unwrap().into(); let core_machine = DefaultCoreMachine::>::new(ISA_IMC, VERSION0, u64::MAX); - let mut machine = DefaultMachineBuilder::new(core_machine) + let mut machine = RustDefaultMachineBuilder::new(core_machine) .syscall(Box::new(CustomSyscall {})) .build(); machine @@ -92,7 +92,7 @@ pub fn test_ebreak() { let value = Arc::new(AtomicU8::new(0)); let core_machine = DefaultCoreMachine::>::new(ISA_IMC, VERSION0, u64::MAX); - let mut machine = DefaultMachineBuilder::new(core_machine) + let mut machine = RustDefaultMachineBuilder::new(core_machine) .debugger(Box::new(CustomDebugger { value: Arc::clone(&value), })) @@ -202,7 +202,7 @@ pub fn test_wxorx_crash_64() { pub fn test_flat_crash_64() { let buffer = fs::read("tests/programs/flat_crash_64").unwrap().into(); let core_machine = DefaultCoreMachine::>::new(ISA_IMC, VERSION0, u64::MAX); - let mut machine = DefaultMachineBuilder::new(core_machine).build(); + let mut machine = RustDefaultMachineBuilder::new(core_machine).build(); let result = machine.load_program(&buffer, [Ok("flat_crash_64".into())].into_iter()); assert_eq!( result.err(), @@ -212,11 +212,15 @@ pub fn test_flat_crash_64() { #[test] pub fn test_memory_store_empty_bytes() { - assert_memory_store_empty_bytes(&mut FlatMemory::::default()); - assert_memory_store_empty_bytes(&mut SparseMemory::::default()); - assert_memory_store_empty_bytes(&mut WXorXMemory::>::default()); + assert_memory_store_empty_bytes(&mut FlatMemory::::new(DEFAULT_MEMORY_SIZE)); + assert_memory_store_empty_bytes(&mut SparseMemory::::new(DEFAULT_MEMORY_SIZE)); + assert_memory_store_empty_bytes(&mut WXorXMemory::>::new( + DEFAULT_MEMORY_SIZE, + )); #[cfg(has_asm)] - assert_memory_store_empty_bytes(&mut AsmCoreMachine::new(ISA_IMC, VERSION0, 200_000)); + assert_memory_store_empty_bytes(&mut ::new( + ISA_IMC, VERSION0, 200_000, + )); } fn assert_memory_store_empty_bytes(memory: &mut M) { @@ -242,19 +246,14 @@ fn assert_memory_load_bytes_all( ) { assert_memory_load_bytes( rng, - &mut SparseMemory::::new_with_memory(max_memory), + &mut SparseMemory::::new(max_memory), buf_size, addr, ); + assert_memory_load_bytes(rng, &mut FlatMemory::::new(max_memory), buf_size, addr); assert_memory_load_bytes( rng, - &mut FlatMemory::::new_with_memory(max_memory), - buf_size, - addr, - ); - assert_memory_load_bytes( - rng, - &mut WXorXMemory::new(FlatMemory::::new_with_memory(max_memory)), + &mut WXorXMemory::>::new(max_memory), buf_size, addr, ); @@ -262,7 +261,7 @@ fn assert_memory_load_bytes_all( #[cfg(has_asm)] assert_memory_load_bytes( rng, - &mut AsmCoreMachine::new(ISA_IMC, VERSION0, 200_000), + &mut ::new(ISA_IMC, VERSION0, 200_000), buf_size, addr, ); @@ -367,7 +366,7 @@ pub fn test_rvc_pageend() { let buffer = fs::read("tests/programs/rvc_pageend").unwrap().into(); let core_machine = DefaultCoreMachine::>::new(ISA_IMC, VERSION0, u64::MAX); - let mut machine = DefaultMachineBuilder::new(core_machine).build(); + let mut machine = RustDefaultMachineBuilder::new(core_machine).build(); machine .load_program(&buffer, [Ok("rvc_end".into())].into_iter()) .unwrap(); @@ -418,7 +417,7 @@ impl Syscalls for OutOfCyclesSyscall { pub fn test_outofcycles_in_syscall() { let buffer = fs::read("tests/programs/syscall64").unwrap().into(); let core_machine = DefaultCoreMachine::>::new(ISA_IMC, VERSION0, 20); - let mut machine = DefaultMachineBuilder::new(core_machine) + let mut machine = RustDefaultMachineBuilder::new(core_machine) .instruction_cycle_func(Box::new(constant_cycles)) .syscall(Box::new(OutOfCyclesSyscall {})) .build(); diff --git a/tests/test_mop.rs b/tests/test_mop.rs index d06f5340..1cd39ab9 100644 --- a/tests/test_mop.rs +++ b/tests/test_mop.rs @@ -2,7 +2,10 @@ pub mod machine_build; use bytes::Bytes; use ckb_vm::error::OutOfBoundKind; use ckb_vm::machine::{VERSION1, VERSION2}; -use ckb_vm::{registers::A0, CoreMachine, Error, SupportMachine, ISA_B, ISA_IMC, ISA_MOP}; +use ckb_vm::{ + registers::A0, CoreMachine, DefaultMachineRunner, Error, SupportMachine, ISA_B, ISA_IMC, + ISA_MOP, +}; #[test] #[cfg_attr(miri, ignore)] diff --git a/tests/test_reset.rs b/tests/test_reset.rs index b4eff886..3ec60c2f 100644 --- a/tests/test_reset.rs +++ b/tests/test_reset.rs @@ -1,11 +1,11 @@ use bytes::Bytes; use ckb_vm::cost_model::constant_cycles; #[cfg(has_asm)] -use ckb_vm::machine::asm::{AsmCoreMachine, AsmMachine}; -use ckb_vm::machine::{DefaultCoreMachine, DefaultMachineBuilder, VERSION1}; +use ckb_vm::machine::asm::{AsmCoreMachine, AsmDefaultMachineBuilder, AsmMachine}; +use ckb_vm::machine::{DefaultCoreMachine, RustDefaultMachineBuilder, VERSION1}; use ckb_vm::{ - registers::A7, Error, Register, SparseMemory, SupportMachine, Syscalls, TraceMachine, - WXorXMemory, DEFAULT_MEMORY_SIZE, ISA_IMC, ISA_MOP, + registers::A7, DefaultMachineRunner, Error, Register, SparseMemory, SupportMachine, Syscalls, + TraceMachine, WXorXMemory, DEFAULT_MEMORY_SIZE, ISA_IMC, ISA_MOP, }; #[allow(dead_code)] @@ -48,7 +48,7 @@ fn test_reset_int() { VERSION1, u64::MAX, ); - let mut machine = DefaultMachineBuilder::new(core_machine) + let mut machine = RustDefaultMachineBuilder::new(core_machine) .instruction_cycle_func(Box::new(constant_cycles)) .syscall(Box::new(CustomSyscall {})) .build(); @@ -71,7 +71,7 @@ fn test_reset_int_with_trace() { u64::MAX, ); let mut machine = TraceMachine::new( - DefaultMachineBuilder::new(core_machine) + RustDefaultMachineBuilder::new(core_machine) .instruction_cycle_func(Box::new(constant_cycles)) .syscall(Box::new(CustomSyscall {})) .build(), @@ -91,7 +91,7 @@ fn test_reset_asm() { let code = Bytes::from(code_data); let asm_core = AsmCoreMachine::new(ISA_IMC | ISA_MOP, VERSION1, u64::MAX); - let core = DefaultMachineBuilder::>::new(asm_core) + let core = AsmDefaultMachineBuilder::new(asm_core) .instruction_cycle_func(Box::new(constant_cycles)) .syscall(Box::new(CustomSyscall {})) .build(); diff --git a/tests/test_resume.rs b/tests/test_resume.rs index ee957ef9..d7b32626 100644 --- a/tests/test_resume.rs +++ b/tests/test_resume.rs @@ -2,14 +2,15 @@ pub mod machine_build; use bytes::Bytes; use ckb_vm::cost_model::constant_cycles; -use ckb_vm::machine::asm::{AsmCoreMachine, AsmMachine}; +use ckb_vm::machine::asm::{AsmCoreMachine, AsmDefaultMachineBuilder, AsmMachine}; use ckb_vm::machine::trace::TraceMachine; use ckb_vm::machine::{ - DefaultCoreMachine, DefaultMachine, SupportMachine, VERSION0, VERSION1, VERSION2, + DefaultCoreMachine, DefaultMachine, DefaultMachineRunner, SupportMachine, VERSION0, VERSION1, + VERSION2, }; use ckb_vm::memory::{sparse::SparseMemory, wxorx::WXorXMemory}; use ckb_vm::snapshot::{make_snapshot, resume, Snapshot}; -use ckb_vm::{DefaultMachineBuilder, Error, ISA_A, ISA_IMC}; +use ckb_vm::{Error, RustDefaultMachineBuilder, ISA_A, ISA_IMC}; use std::fs::File; use std::io::Read; @@ -208,8 +209,9 @@ impl MachineTy { fn build(self, version: u32, max_cycles: u64) -> Machine { match self { MachineTy::Asm => { - let asm_core1 = AsmCoreMachine::new(ISA_IMC, version, max_cycles); - let core1 = DefaultMachineBuilder::>::new(asm_core1) + let asm_core1 = + ::new(ISA_IMC, version, max_cycles); + let core1 = AsmDefaultMachineBuilder::new(asm_core1) .instruction_cycle_func(Box::new(constant_cycles)) .build(); Machine::Asm(AsmMachine::new(core1)) @@ -219,9 +221,9 @@ impl MachineTy { ISA_IMC, version, max_cycles, ); Machine::Interpreter( - DefaultMachineBuilder::>>>::new( - core_machine1, - ) + RustDefaultMachineBuilder::< + DefaultCoreMachine>>, + >::new(core_machine1) .instruction_cycle_func(Box::new(constant_cycles)) .build(), ) @@ -230,15 +232,13 @@ impl MachineTy { let core_machine1 = DefaultCoreMachine::>>::new( ISA_IMC, version, max_cycles, ); - Machine::InterpreterWithTrace( - TraceMachine::new( - DefaultMachineBuilder::< - DefaultCoreMachine>>, - >::new(core_machine1) - .instruction_cycle_func(Box::new(constant_cycles)) - .build(), - ), - ) + Machine::InterpreterWithTrace(TraceMachine::new( + RustDefaultMachineBuilder::< + DefaultCoreMachine>>, + >::new(core_machine1) + .instruction_cycle_func(Box::new(constant_cycles)) + .build(), + )) } } } @@ -316,7 +316,7 @@ pub fn test_sc_after_snapshot() { let snap = make_snapshot(&mut machine).unwrap(); let mut machine_new = TraceMachine::new( - DefaultMachineBuilder::new( + RustDefaultMachineBuilder::new( DefaultCoreMachine::>>::new( ISA_IMC | ISA_A, VERSION2, diff --git a/tests/test_resume2.rs b/tests/test_resume2.rs index c898c6da..dfcb1510 100644 --- a/tests/test_resume2.rs +++ b/tests/test_resume2.rs @@ -3,17 +3,18 @@ pub mod machine_build; use bytes::Bytes; use ckb_vm::cost_model::constant_cycles; use ckb_vm::elf::parse_elf; -use ckb_vm::machine::asm::{AsmCoreMachine, AsmMachine}; +use ckb_vm::machine::asm::{AsmCoreMachine, AsmDefaultMachineBuilder, AsmMachine}; use ckb_vm::machine::trace::TraceMachine; use ckb_vm::machine::{ - CoreMachine, DefaultCoreMachine, DefaultMachine, SupportMachine, VERSION0, VERSION1, VERSION2, + CoreMachine, DefaultCoreMachine, DefaultMachine, DefaultMachineRunner, SupportMachine, + VERSION0, VERSION1, VERSION2, }; use ckb_vm::memory::{sparse::SparseMemory, wxorx::WXorXMemory}; use ckb_vm::registers::{A0, A1, A7}; use ckb_vm::snapshot2::{DataSource, Snapshot2, Snapshot2Context}; #[allow(unused_imports)] use ckb_vm::Memory; -use ckb_vm::{DefaultMachineBuilder, Error, Register, Syscalls, ISA_A, ISA_IMC}; +use ckb_vm::{Error, Register, RustDefaultMachineBuilder, Syscalls, ISA_A, ISA_IMC}; use std::collections::HashMap; use std::fs::File; use std::io::Read; @@ -394,8 +395,9 @@ impl MachineTy { match self { MachineTy::Asm => { let context = Arc::new(Mutex::new(Snapshot2Context::new(data_source))); - let asm_core1 = AsmCoreMachine::new(ISA_IMC | ISA_A, version, 0); - let core1 = DefaultMachineBuilder::>::new(asm_core1) + let asm_core1 = + ::new(ISA_IMC | ISA_A, version, 0); + let core1 = AsmDefaultMachineBuilder::new(asm_core1) .instruction_cycle_func(Box::new(constant_cycles)) .syscall(Box::new(InsertDataSyscall(context.clone()))) .build(); @@ -409,9 +411,9 @@ impl MachineTy { 0, ); Machine::Interpreter( - DefaultMachineBuilder::>>>::new( - core_machine1, - ) + RustDefaultMachineBuilder::< + DefaultCoreMachine>>, + >::new(core_machine1) .instruction_cycle_func(Box::new(constant_cycles)) .syscall(Box::new(InsertDataSyscall(context.clone()))) .build(), @@ -427,7 +429,7 @@ impl MachineTy { ); Machine::InterpreterWithTrace( TraceMachine::new( - DefaultMachineBuilder::< + RustDefaultMachineBuilder::< DefaultCoreMachine>>, >::new(core_machine1) .instruction_cycle_func(Box::new(constant_cycles)) diff --git a/tests/test_signal_pause.rs b/tests/test_signal_pause.rs index ff87059c..1b20ce63 100644 --- a/tests/test_signal_pause.rs +++ b/tests/test_signal_pause.rs @@ -1,5 +1,5 @@ use ckb_vm::machine::VERSION2; -use ckb_vm::{Error, SupportMachine, ISA_B, ISA_IMC}; +use ckb_vm::{DefaultMachineRunner, Error, SupportMachine, ISA_B, ISA_IMC}; use std::sync::atomic::{AtomicU32, Ordering}; use std::sync::Arc; pub mod machine_build; diff --git a/tests/test_simple.rs b/tests/test_simple.rs index b32161cf..132d14f7 100644 --- a/tests/test_simple.rs +++ b/tests/test_simple.rs @@ -1,7 +1,7 @@ use ckb_vm::machine::VERSION0; use ckb_vm::{ - run, DefaultCoreMachine, DefaultMachineBuilder, Error, FlatMemory, Instruction, SparseMemory, - SupportMachine, ISA_IMC, + run, DefaultCoreMachine, DefaultMachineRunner, Error, FlatMemory, Instruction, + RustDefaultMachineBuilder, SparseMemory, SupportMachine, ISA_IMC, }; use std::fs; @@ -38,7 +38,7 @@ pub fn test_simple_cycles() { let buffer = fs::read("tests/programs/simple64").unwrap().into(); let core_machine = DefaultCoreMachine::>::new(ISA_IMC, VERSION0, 708); let mut machine = - DefaultMachineBuilder::>>::new(core_machine) + RustDefaultMachineBuilder::>>::new(core_machine) .instruction_cycle_func(Box::new(dummy_cycle_func)) .build(); machine @@ -57,7 +57,7 @@ pub fn test_simple_max_cycles_reached() { // Running simple64 should consume 708 cycles using dummy cycle func let core_machine = DefaultCoreMachine::>::new(ISA_IMC, VERSION0, 700); let mut machine = - DefaultMachineBuilder::>>::new(core_machine) + RustDefaultMachineBuilder::>>::new(core_machine) .instruction_cycle_func(Box::new(dummy_cycle_func)) .build(); machine @@ -81,7 +81,7 @@ pub fn test_simple_loaded_bytes() { let buffer = fs::read("tests/programs/simple64").unwrap().into(); let core_machine = DefaultCoreMachine::>::new(ISA_IMC, VERSION0, u64::MAX); - let mut machine = DefaultMachineBuilder::new(core_machine).build(); + let mut machine = RustDefaultMachineBuilder::new(core_machine).build(); let bytes = machine .load_program(&buffer, [Ok("simple".into())].into_iter()) .unwrap(); @@ -94,7 +94,7 @@ pub fn test_simple_cycles_overflow() { let core_machine = DefaultCoreMachine::>::new(ISA_IMC, VERSION0, u64::MAX); let mut machine = - DefaultMachineBuilder::>>::new(core_machine) + RustDefaultMachineBuilder::>>::new(core_machine) .instruction_cycle_func(Box::new(dummy_cycle_func)) .build(); machine.set_cycles(u64::MAX - 10); diff --git a/tests/test_spawn.rs b/tests/test_spawn.rs index 9f272aca..f126af33 100644 --- a/tests/test_spawn.rs +++ b/tests/test_spawn.rs @@ -1,13 +1,13 @@ use bytes::Bytes; use ckb_vm::cost_model::constant_cycles; #[cfg(has_asm)] -use ckb_vm::machine::asm::{AsmCoreMachine, AsmMachine}; +use ckb_vm::machine::asm::{AsmCoreMachine, AsmDefaultMachineBuilder, AsmMachine}; use ckb_vm::machine::{trace::TraceMachine, DefaultCoreMachine, VERSION2}; use ckb_vm::memory::load_c_string_byte_by_byte; use ckb_vm::registers::{A0, A1, A2, A7}; use ckb_vm::{ - DefaultMachineBuilder, Error, FlattenedArgsReader, Register, SparseMemory, SupportMachine, - Syscalls, WXorXMemory, ISA_B, ISA_IMC, ISA_MOP, + DefaultMachineRunner, Error, FlattenedArgsReader, Register, RustDefaultMachineBuilder, + SparseMemory, SupportMachine, Syscalls, WXorXMemory, ISA_B, ISA_IMC, ISA_MOP, }; use std::sync::{Arc, Mutex}; @@ -57,7 +57,7 @@ impl Syscalls for IntSpawnSyscall { u64::MAX, ); let mut machine_child = TraceMachine::new( - DefaultMachineBuilder::new(machine_core) + RustDefaultMachineBuilder::new(machine_core) .instruction_cycle_func(Box::new(constant_cycles)) .syscall(Box::new(IntSpawnSyscall { min_sp: self.min_sp.clone(), @@ -104,7 +104,7 @@ impl Syscalls for AsmSpawnSyscall { let args_iter = FlattenedArgsReader::new(machine.memory_mut(), argc.clone(), argv); let buffer: Bytes = std::fs::read(path).unwrap().into(); let machine_core_asm = AsmCoreMachine::new(ISA_IMC | ISA_B | ISA_MOP, VERSION2, u64::MAX); - let machine_core = DefaultMachineBuilder::>::new(machine_core_asm) + let machine_core = AsmDefaultMachineBuilder::new(machine_core_asm) .instruction_cycle_func(Box::new(constant_cycles)) .syscall(Box::new(AsmSpawnSyscall { min_sp: self.min_sp.clone(), @@ -129,7 +129,7 @@ pub fn test_spawn_int() { u64::MAX, ); let mut machine = TraceMachine::new( - DefaultMachineBuilder::new(machine_core) + RustDefaultMachineBuilder::new(machine_core) .instruction_cycle_func(Box::new(constant_cycles)) .syscall(Box::new(IntSpawnSyscall { min_sp: min_sp.clone(), @@ -154,7 +154,7 @@ pub fn test_spawn_asm() { let cur_sp = stack_depth(); let min_sp = Arc::new(Mutex::new(u64::MAX)); let machine_core_asm = AsmCoreMachine::new(ISA_IMC | ISA_B | ISA_MOP, VERSION2, u64::MAX); - let machine_core = DefaultMachineBuilder::>::new(machine_core_asm) + let machine_core = AsmDefaultMachineBuilder::new(machine_core_asm) .instruction_cycle_func(Box::new(constant_cycles)) .syscall(Box::new(AsmSpawnSyscall { min_sp: min_sp.clone(), diff --git a/tests/test_versions.rs b/tests/test_versions.rs index 589fd9cf..6a24d360 100644 --- a/tests/test_versions.rs +++ b/tests/test_versions.rs @@ -1,12 +1,13 @@ #![cfg(has_asm)] use ckb_vm::cost_model::constant_cycles; use ckb_vm::error::OutOfBoundKind; -use ckb_vm::machine::asm::{AsmCoreMachine, AsmMachine}; +use ckb_vm::machine::asm::{AsmCoreMachine, AsmDefaultMachineBuilder, AsmMachine}; use ckb_vm::machine::{VERSION0, VERSION1, VERSION2}; use ckb_vm::memory::{FLAG_DIRTY, FLAG_FREEZED}; use ckb_vm::{ - CoreMachine, DefaultCoreMachine, DefaultMachine, DefaultMachineBuilder, Error, Memory, - SparseMemory, TraceMachine, WXorXMemory, ISA_B, ISA_IMC, ISA_MOP, RISCV_PAGESIZE, + CoreMachine, DefaultCoreMachine, DefaultMachine, DefaultMachineRunner, Error, Memory, + RustDefaultMachineBuilder, SparseMemory, SupportMachine, TraceMachine, WXorXMemory, ISA_B, + ISA_IMC, ISA_MOP, RISCV_PAGESIZE, }; use std::fs; @@ -20,7 +21,7 @@ fn create_rust_machine( let buffer = fs::read(path).unwrap().into(); let core_machine = DefaultCoreMachine::::new(ISA_IMC, version, u64::MAX); let mut machine = - DefaultMachineBuilder::>::new(core_machine).build(); + RustDefaultMachineBuilder::>::new(core_machine).build(); machine .load_program(&buffer, [Ok(program.into())].into_iter()) .unwrap(); @@ -30,8 +31,8 @@ fn create_rust_machine( fn create_asm_machine(program: String, version: u32) -> AsmMachine { let path = format!("tests/programs/{}", program); let buffer = fs::read(path).unwrap().into(); - let asm_core = AsmCoreMachine::new(ISA_IMC, version, u64::MAX); - let core = DefaultMachineBuilder::>::new(asm_core).build(); + let asm_core = ::new(ISA_IMC, version, u64::MAX); + let core = AsmDefaultMachineBuilder::new(asm_core).build(); let mut machine = AsmMachine::new(core); machine .load_program(&buffer, [Ok(program.into())].into_iter()) @@ -245,7 +246,7 @@ pub fn test_rust_version0_unaligned64() { .into(); let core_machine = DefaultCoreMachine::::new(ISA_IMC, VERSION0, u64::MAX); let mut machine = - DefaultMachineBuilder::>::new(core_machine).build(); + RustDefaultMachineBuilder::>::new(core_machine).build(); let result = machine.load_program(&buffer, [Ok(program.into())].into_iter()); assert!(result.is_err()); assert_eq!(result.err(), Some(Error::MemWriteOnExecutablePage(16))); @@ -265,8 +266,8 @@ pub fn test_asm_version0_unaligned64() { let buffer = fs::read(format!("tests/programs/{}", program)) .unwrap() .into(); - let asm_core = AsmCoreMachine::new(ISA_IMC, VERSION0, u64::MAX); - let core = DefaultMachineBuilder::>::new(asm_core).build(); + let asm_core = ::new(ISA_IMC, VERSION0, u64::MAX); + let core = AsmDefaultMachineBuilder::new(asm_core).build(); let mut machine = AsmMachine::new(core); let result = machine.load_program(&buffer, [Ok(program.into())].into_iter()); assert!(result.is_err()); @@ -345,8 +346,9 @@ pub fn test_asm_version1_asm_trace_bug() { let buffer = fs::read("tests/programs/asm_trace_bug").unwrap().into(); let mut machine = { - let asm_core = AsmCoreMachine::new(ISA_IMC | ISA_B | ISA_MOP, VERSION1, 2000); - let machine = DefaultMachineBuilder::>::new(asm_core) + let asm_core = + ::new(ISA_IMC | ISA_B | ISA_MOP, VERSION1, 2000); + let machine = AsmDefaultMachineBuilder::new(asm_core) .instruction_cycle_func(Box::new(constant_cycles)) .build(); AsmMachine::new(machine) @@ -362,8 +364,9 @@ pub fn test_asm_version2_asm_trace_bug() { let buffer = fs::read("tests/programs/asm_trace_bug").unwrap().into(); let mut machine = { - let asm_core = AsmCoreMachine::new(ISA_IMC | ISA_B | ISA_MOP, VERSION2, 2000); - let machine = DefaultMachineBuilder::>::new(asm_core) + let asm_core = + ::new(ISA_IMC | ISA_B | ISA_MOP, VERSION2, 2000); + let machine = AsmDefaultMachineBuilder::new(asm_core) .instruction_cycle_func(Box::new(constant_cycles)) .build(); AsmMachine::new(machine) @@ -388,7 +391,7 @@ pub fn test_trace_version1_asm_trace_bug() { 2000, ); TraceMachine::new( - DefaultMachineBuilder::new(core_machine) + RustDefaultMachineBuilder::new(core_machine) .instruction_cycle_func(Box::new(constant_cycles)) .build(), ) @@ -410,7 +413,7 @@ pub fn test_trace_version2_asm_trace_bug() { 2000, ); TraceMachine::new( - DefaultMachineBuilder::new(core_machine) + RustDefaultMachineBuilder::new(core_machine) .instruction_cycle_func(Box::new(constant_cycles)) .build(), ) From c96c4c546f15b5559c8f8249e0049103551ab3ad Mon Sep 17 00:00:00 2001 From: Xuejie Xiao Date: Mon, 24 Mar 2025 05:50:11 +0000 Subject: [PATCH 2/2] chore: Remove unneeded PhantomData --- src/machine/asm/mod.rs | 7 +------ src/machine/trace.rs | 3 --- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/src/machine/asm/mod.rs b/src/machine/asm/mod.rs index d5185ab8..48c1eda6 100644 --- a/src/machine/asm/mod.rs +++ b/src/machine/asm/mod.rs @@ -14,7 +14,6 @@ use ckb_vm_definitions::{ }; use rand::{prelude::RngCore, SeedableRng}; use std::alloc::{alloc, alloc_zeroed, Layout}; -use std::marker::PhantomData; use std::mem::MaybeUninit; use std::os::raw::c_uchar; @@ -701,7 +700,6 @@ pub type AsmMachine = AbstractAsmMachine; pub struct AbstractAsmMachine { pub machine: DefaultMachine, - phantom: PhantomData, } impl DefaultMachineRunner for AbstractAsmMachine { @@ -709,10 +707,7 @@ impl DefaultMachineRunner for AbstractAsmMachine type Decoder = Decoder; fn new(machine: DefaultMachine) -> Self { - Self { - machine, - phantom: PhantomData, - } + Self { machine } } fn machine(&self) -> &DefaultMachine { diff --git a/src/machine/trace.rs b/src/machine/trace.rs index ca34143e..769896e3 100644 --- a/src/machine/trace.rs +++ b/src/machine/trace.rs @@ -11,7 +11,6 @@ use super::{ CoreMachine, DefaultMachine, DefaultMachineRunner, Machine, SupportMachine, VERSION2, }; use bytes::Bytes; -use std::marker::PhantomData; // The number of trace items to keep const TRACE_SIZE: usize = 8192; @@ -54,7 +53,6 @@ pub struct AbstractTraceMachine { factory: ThreadFactory>, traces: Vec>>, - phantom: PhantomData, } impl CoreMachine for AbstractTraceMachine { @@ -119,7 +117,6 @@ impl DefaultMachineRunner machine, factory: ThreadFactory::create(), traces: vec![], - phantom: PhantomData, } }