diff --git a/CHANGELOG.md b/CHANGELOG.md index 858d8288dd..899cf9da7f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## Perf +### 2025-06-30 + +- Use a stack pool [#3386](https://github.com/lambdaclass/ethrex/pull/3386) + ### 2025-06-27 - Reduce handle_debug runtime cost [#3356](https://github.com/lambdaclass/ethrex/pull/3356) diff --git a/crates/vm/levm/src/call_frame.rs b/crates/vm/levm/src/call_frame.rs index 6005b4371b..f1c6389a9e 100644 --- a/crates/vm/levm/src/call_frame.rs +++ b/crates/vm/levm/src/call_frame.rs @@ -102,6 +102,10 @@ impl Stack { self.values.swap(self.offset, index); Ok(()) } + + pub fn clear(&mut self) { + self.offset = STACK_LIMIT; + } } impl Default for Stack { @@ -231,6 +235,7 @@ impl CallFrame { is_create: bool, ret_offset: U256, ret_size: usize, + stack: Stack, ) -> Self { let invalid_jump_destinations = get_invalid_jump_destinations(&bytecode).unwrap_or_default(); @@ -250,6 +255,7 @@ impl CallFrame { is_create, ret_offset, ret_size, + stack, ..Default::default() } } diff --git a/crates/vm/levm/src/opcode_handlers/system.rs b/crates/vm/levm/src/opcode_handlers/system.rs index 2b51fac568..e7ea6771c8 100644 --- a/crates/vm/levm/src/opcode_handlers/system.rs +++ b/crates/vm/levm/src/opcode_handlers/system.rs @@ -684,6 +684,9 @@ impl<'a> VM<'a> { return Ok(OpcodeResult::Continue { pc_increment: 1 }); } + let mut stack = self.stack_pool.pop().unwrap_or_default(); + stack.clear(); + let new_call_frame = CallFrame::new( deployer, new_address, @@ -698,6 +701,7 @@ impl<'a> VM<'a> { true, U256::zero(), 0, + stack, ); self.call_frames.push(new_call_frame); @@ -752,6 +756,9 @@ impl<'a> VM<'a> { return Ok(OpcodeResult::Continue { pc_increment: 1 }); } + let mut stack = self.stack_pool.pop().unwrap_or_default(); + stack.clear(); + let new_call_frame = CallFrame::new( msg_sender, to, @@ -766,6 +773,7 @@ impl<'a> VM<'a> { false, ret_offset, ret_size, + stack, ); self.call_frames.push(new_call_frame); @@ -859,6 +867,11 @@ impl<'a> VM<'a> { }; self.tracer.exit_context(ctx_result, false)?; + + let mut stack = executed_call_frame.stack; + stack.clear(); + self.stack_pool.push(stack); + Ok(()) } @@ -901,6 +914,11 @@ impl<'a> VM<'a> { }; self.tracer.exit_context(ctx_result, false)?; + + let mut stack = executed_call_frame.stack; + stack.clear(); + self.stack_pool.push(stack); + Ok(()) } diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index 43bba22964..80aa077e3c 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -1,6 +1,6 @@ use crate::{ TransientStorage, - call_frame::CallFrame, + call_frame::{CallFrame, Stack}, db::gen_db::GeneralizedDatabase, debug::DebugMode, environment::Environment, @@ -59,6 +59,8 @@ pub struct VM<'a> { pub tracer: LevmCallTracer, /// Mode for printing some useful stuff, only used in development! pub debug_mode: DebugMode, + /// A pool of stacks to avoid reallocating too much when creating new call frames. + pub stack_pool: Vec, pub vm_type: VMType, } @@ -83,6 +85,7 @@ impl<'a> VM<'a> { storage_original_values: HashMap::new(), tracer, debug_mode: DebugMode::disabled(), + stack_pool: Vec::new(), vm_type, } } @@ -111,6 +114,7 @@ impl<'a> VM<'a> { is_create, U256::zero(), 0, + Stack::default(), ); self.call_frames.push(initial_call_frame);