Skip to content

Commit 90e6622

Browse files
authored
perf(vm): general performance/space improvements (#482)
1 parent 55b01ff commit 90e6622

11 files changed

Lines changed: 73 additions & 71 deletions

File tree

crates/cfg/src/core/graph.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use alloy::primitives::U256;
22
use eyre::{OptionExt, Result};
33
use heimdall_common::utils::strings::encode_hex_reduced;
44
use heimdall_vm::{
5-
core::opcodes::{OpCodeInfo, JUMPDEST},
5+
core::opcodes::{opcode_name, JUMPDEST},
66
ext::exec::VMTrace,
77
};
88
use petgraph::{matrix_graph::NodeIndex, Graph};
@@ -21,7 +21,7 @@ pub fn build_cfg(
2121

2222
// add the current operations to the cfg
2323
for operation in &vm_trace.operations {
24-
let opcode_name = OpCodeInfo::from(operation.last_instruction.opcode).name();
24+
let opcode_name = opcode_name(operation.last_instruction.opcode);
2525

2626
let assembly = format!(
2727
"{} {} {}",

crates/decompile/src/utils/heuristics/arguments.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use alloy::primitives::U256;
44
use eyre::eyre;
55
use heimdall_common::utils::strings::find_balanced_encapsulator;
66
use heimdall_vm::core::{
7-
opcodes::{OpCodeInfo, CALLDATALOAD, ISZERO},
7+
opcodes::{opcode_name, CALLDATALOAD, ISZERO},
88
types::{byte_size_to_type, convert_bitmask},
99
vm::State,
1010
};
@@ -72,7 +72,7 @@ pub fn argument_heuristic(
7272
debug!(
7373
"instruction {} ({}) indicates argument {} is masked to {} bytes",
7474
state.last_instruction.instruction,
75-
OpCodeInfo::from(state.last_instruction.opcode).name(),
75+
opcode_name(state.last_instruction.opcode),
7676
arg_index,
7777
mask_size_bytes
7878
);
@@ -216,7 +216,7 @@ pub fn argument_heuristic(
216216
debug!(
217217
"instruction {} ({}) indicates argument {} may be a numeric type",
218218
state.last_instruction.instruction,
219-
OpCodeInfo::from(state.last_instruction.opcode).name(),
219+
opcode_name(state.last_instruction.opcode),
220220
arg_index
221221
);
222222

@@ -239,7 +239,7 @@ pub fn argument_heuristic(
239239
debug!(
240240
"instruction {} ({}) indicates argument {} may be a bytes type",
241241
state.last_instruction.instruction,
242-
OpCodeInfo::from(state.last_instruction.opcode).name(),
242+
opcode_name(state.last_instruction.opcode),
243243
arg_index
244244
);
245245

@@ -262,7 +262,7 @@ pub fn argument_heuristic(
262262
debug!(
263263
"instruction {} ({}) indicates argument {} may be a boolean",
264264
state.last_instruction.instruction,
265-
OpCodeInfo::from(state.last_instruction.opcode).name(),
265+
opcode_name(state.last_instruction.opcode),
266266
arg_index
267267
);
268268

crates/decompile/src/utils/heuristics/modifiers.rs

Lines changed: 7 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,42 +9,29 @@ use tracing::debug;
99

1010
use crate::{core::analyze::AnalyzerState, interfaces::AnalyzedFunction, Error};
1111

12-
use lazy_static::lazy_static;
13-
14-
lazy_static! {
15-
/// A list of opcodes that are considered non-pure (state accessing)
16-
pub static ref NON_PURE_OPCODES: Vec<u8> = vec![
17-
0x31, 0x32, 0x33, 0x3a, 0x3b, 0x3c, 0x40, 0x41, 0x42,
18-
0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x54, 0x55, 0xf0,
19-
0xf1, 0xf2, 0xf4, 0xf5, 0xfa, 0xff
20-
];
21-
/// A list of opcodes that are considered non-view (state modifying)
22-
pub static ref NON_VIEW_OPCODES: Vec<u8> = vec![
23-
0x55, 0xf0, 0xf1, 0xf2, 0xf4, 0xf5, 0xfa, 0xff
24-
];
25-
}
26-
2712
pub fn modifier_heuristic(
2813
function: &mut AnalyzedFunction,
2914
state: &State,
3015
_: &mut AnalyzerState,
3116
) -> Result<(), Error> {
32-
let opcode_name = OpCodeInfo::from(state.last_instruction.opcode).name();
17+
let opcode_info = OpCodeInfo::from(state.last_instruction.opcode);
3318

3419
// if any instruction is non-pure, the function is non-pure
35-
if function.pure && NON_PURE_OPCODES.contains(&state.last_instruction.opcode) {
20+
if function.pure && !opcode_info.is_pure() {
3621
debug!(
3722
"instruction {} ({}) indicates a non-pure function",
38-
state.last_instruction.instruction, opcode_name
23+
state.last_instruction.instruction,
24+
opcode_info.name()
3925
);
4026
function.pure = false;
4127
}
4228

4329
// if any instruction is non-view, the function is non-view
44-
if function.view && NON_VIEW_OPCODES.contains(&state.last_instruction.opcode) {
30+
if function.view && !opcode_info.is_view() {
4531
debug!(
4632
"instruction {} ({}) indicates a non-view function",
47-
state.last_instruction.instruction, opcode_name
33+
state.last_instruction.instruction,
34+
opcode_info.name()
4835
);
4936
function.view = false;
5037
}

crates/decompile/src/utils/heuristics/solidity.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use alloy::primitives::U256;
22
use alloy_dyn_abi::{DynSolType, DynSolValue};
33
use heimdall_common::utils::strings::encode_hex_reduced;
4-
use heimdall_vm::core::{opcodes::OpCodeInfo, vm::State};
4+
use heimdall_vm::core::{opcodes::opcode_name, vm::State};
55

66
use crate::{
77
core::analyze::AnalyzerState,
@@ -188,7 +188,7 @@ pub fn solidity_heuristic(
188188
function.logic.push(format!(
189189
"(bool success, bytes memory ret0) = address({}).{}{}(abi.encode({}));",
190190
address,
191-
OpCodeInfo::from(instruction.opcode).name().to_lowercase(),
191+
opcode_name(instruction.opcode).to_lowercase(),
192192
modifier,
193193
calldata
194194
.iter()

crates/decompile/src/utils/heuristics/yul.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use heimdall_common::utils::strings::encode_hex_reduced;
2-
use heimdall_vm::core::{opcodes::OpCodeInfo, vm::State};
2+
use heimdall_vm::core::{opcodes::opcode_name, vm::State};
33

44
use crate::{
55
core::analyze::AnalyzerState,
@@ -24,7 +24,7 @@ pub fn yul_heuristic(
2424
function.memory.insert(key, StorageFrame { operation });
2525
function.logic.push(format!(
2626
"{}({}, {})",
27-
OpCodeInfo::from(instruction.opcode).name().to_lowercase(),
27+
opcode_name(instruction.opcode).to_lowercase(),
2828
encode_hex_reduced(key),
2929
instruction.input_operations[1].yulify()
3030
));
@@ -80,7 +80,7 @@ pub fn yul_heuristic(
8080
0xff | 0xA0 | 0xA1 | 0xA2 | 0xA3 | 0xA4 => {
8181
function.logic.push(format!(
8282
"{}({})",
83-
OpCodeInfo::from(instruction.opcode).name().to_lowercase(),
83+
opcode_name(instruction.opcode).to_lowercase(),
8484
instruction
8585
.input_operations
8686
.iter()

crates/disassemble/src/core/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::time::Instant;
33
use crate::{error::Error, interfaces::DisassemblerArgs};
44
use eyre::eyre;
55
use heimdall_common::utils::strings::encode_hex;
6-
use heimdall_vm::core::opcodes::OpCodeInfo;
6+
use heimdall_vm::core::opcodes::opcode_name;
77
use tracing::{debug, info};
88

99
pub async fn disassemble(args: DisassemblerArgs) -> Result<String, Error> {
@@ -45,7 +45,7 @@ pub async fn disassemble(args: DisassemblerArgs) -> Result<String, Error> {
4545
} else {
4646
format!("{:06x}", program_counter)
4747
},
48-
OpCodeInfo::from(opcode).name(),
48+
opcode_name(opcode),
4949
pushed_bytes
5050
)
5151
.as_str(),

crates/vm/benches/bench_ten_thousand_hashes.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ use heimdall_common::utils::strings::decode_hex;
44
use heimdall_vm::core::vm::VM;
55
use tokio::runtime::Runtime;
66

7-
fn test_fib(c: &mut Criterion) {
7+
fn test_ten_thousand_hashes(c: &mut Criterion) {
88
let mut group = c.benchmark_group("heimdall_vm");
99

10-
group.sample_size(500);
10+
group.sample_size(100);
1111
group.bench_function(BenchmarkId::from_parameter("ten_thousand_hashes"), |b| {
1212
b.to_async::<Runtime>(Runtime::new().unwrap()).iter(|| async {
1313
// build the evm
@@ -33,5 +33,5 @@ fn test_fib(c: &mut Criterion) {
3333
group.finish();
3434
}
3535

36-
criterion_group!(benches, test_fib);
36+
criterion_group!(benches, test_ten_thousand_hashes);
3737
criterion_main!(benches);

crates/vm/src/core/opcodes/mod.rs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ impl OpCodeInfo {
7575
impl From<u8> for OpCodeInfo {
7676
#[inline]
7777
fn from(opcode: u8) -> Self {
78-
OPCODE_INFO_JUMPTABLE[opcode as usize].unwrap_or(OpCodeInfo {
78+
OPCODE_INFO_TABLE[opcode as usize].unwrap_or(OpCodeInfo {
7979
name: "unknown",
8080
inputs: 0,
8181
outputs: 0,
@@ -269,7 +269,7 @@ macro_rules! opcodes {
269269
)*
270270

271271
/// Maps each opcode to its info.
272-
pub const OPCODE_INFO_JUMPTABLE: [Option<OpCodeInfo>; 256] = {
272+
pub const OPCODE_INFO_TABLE: [Option<OpCodeInfo>; 256] = {
273273
let mut map = [None; 256];
274274
let mut prev: u8 = 0;
275275
$(
@@ -287,9 +287,24 @@ macro_rules! opcodes {
287287
let _ = prev;
288288
map
289289
};
290+
291+
/// Maps each opcode to its name. (So we dont need to load [`OpCodeInfo`] to get the name)
292+
pub const OPCODE_NAME_TABLE: [&'static str; 256] = {
293+
let mut map = ["unknown"; 256];
294+
$(
295+
map[$val] = stringify!($name);
296+
)*
297+
map
298+
};
290299
}
291300
}
292301

302+
/// Get the name of an opcode.
303+
#[inline]
304+
pub fn opcode_name(opcode: u8) -> &'static str {
305+
OPCODE_NAME_TABLE[opcode as usize]
306+
}
307+
293308
opcodes! {
294309
0x00 => STOP => terminating;
295310

crates/vm/src/core/opcodes/wrapped.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use alloy::primitives::U256;
22

3-
use crate::core::opcodes::OpCodeInfo;
3+
use crate::core::opcodes::opcode_name;
44

55
/// A WrappedInput can contain either a raw U256 value or a WrappedOpcode
66
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
@@ -30,7 +30,7 @@ impl std::fmt::Display for WrappedOpcode {
3030
write!(
3131
f,
3232
"{}({})",
33-
OpCodeInfo::from(self.opcode).name(),
33+
opcode_name(self.opcode),
3434
self.inputs.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(", ")
3535
)
3636
}

0 commit comments

Comments
 (0)