Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

perf(vm): general performance/space improvements #482

Merged
merged 4 commits into from
Aug 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions crates/cfg/src/core/graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use alloy::primitives::U256;
use eyre::{OptionExt, Result};
use heimdall_common::utils::strings::encode_hex_reduced;
use heimdall_vm::{
core::opcodes::{OpCodeInfo, JUMPDEST},
core::opcodes::{opcode_name, JUMPDEST},
ext::exec::VMTrace,
};
use petgraph::{matrix_graph::NodeIndex, Graph};
Expand All @@ -21,7 +21,7 @@ pub fn build_cfg(

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

let assembly = format!(
"{} {} {}",
Expand Down
10 changes: 5 additions & 5 deletions crates/decompile/src/utils/heuristics/arguments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use alloy::primitives::U256;
use eyre::eyre;
use heimdall_common::utils::strings::find_balanced_encapsulator;
use heimdall_vm::core::{
opcodes::{OpCodeInfo, CALLDATALOAD, ISZERO},
opcodes::{opcode_name, CALLDATALOAD, ISZERO},
types::{byte_size_to_type, convert_bitmask},
vm::State,
};
Expand Down Expand Up @@ -72,7 +72,7 @@ pub fn argument_heuristic(
debug!(
"instruction {} ({}) indicates argument {} is masked to {} bytes",
state.last_instruction.instruction,
OpCodeInfo::from(state.last_instruction.opcode).name(),
opcode_name(state.last_instruction.opcode),
arg_index,
mask_size_bytes
);
Expand Down Expand Up @@ -216,7 +216,7 @@ pub fn argument_heuristic(
debug!(
"instruction {} ({}) indicates argument {} may be a numeric type",
state.last_instruction.instruction,
OpCodeInfo::from(state.last_instruction.opcode).name(),
opcode_name(state.last_instruction.opcode),
arg_index
);

Expand All @@ -239,7 +239,7 @@ pub fn argument_heuristic(
debug!(
"instruction {} ({}) indicates argument {} may be a bytes type",
state.last_instruction.instruction,
OpCodeInfo::from(state.last_instruction.opcode).name(),
opcode_name(state.last_instruction.opcode),
arg_index
);

Expand All @@ -262,7 +262,7 @@ pub fn argument_heuristic(
debug!(
"instruction {} ({}) indicates argument {} may be a boolean",
state.last_instruction.instruction,
OpCodeInfo::from(state.last_instruction.opcode).name(),
opcode_name(state.last_instruction.opcode),
arg_index
);

Expand Down
27 changes: 7 additions & 20 deletions crates/decompile/src/utils/heuristics/modifiers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,42 +9,29 @@ use tracing::debug;

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

use lazy_static::lazy_static;

lazy_static! {
/// A list of opcodes that are considered non-pure (state accessing)
pub static ref NON_PURE_OPCODES: Vec<u8> = vec![
0x31, 0x32, 0x33, 0x3a, 0x3b, 0x3c, 0x40, 0x41, 0x42,
0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x54, 0x55, 0xf0,
0xf1, 0xf2, 0xf4, 0xf5, 0xfa, 0xff
];
/// A list of opcodes that are considered non-view (state modifying)
pub static ref NON_VIEW_OPCODES: Vec<u8> = vec![
0x55, 0xf0, 0xf1, 0xf2, 0xf4, 0xf5, 0xfa, 0xff
];
}

pub fn modifier_heuristic(
function: &mut AnalyzedFunction,
state: &State,
_: &mut AnalyzerState,
) -> Result<(), Error> {
let opcode_name = OpCodeInfo::from(state.last_instruction.opcode).name();
let opcode_info = OpCodeInfo::from(state.last_instruction.opcode);

// if any instruction is non-pure, the function is non-pure
if function.pure && NON_PURE_OPCODES.contains(&state.last_instruction.opcode) {
if function.pure && !opcode_info.is_pure() {
debug!(
"instruction {} ({}) indicates a non-pure function",
state.last_instruction.instruction, opcode_name
state.last_instruction.instruction,
opcode_info.name()
);
function.pure = false;
}

// if any instruction is non-view, the function is non-view
if function.view && NON_VIEW_OPCODES.contains(&state.last_instruction.opcode) {
if function.view && !opcode_info.is_view() {
debug!(
"instruction {} ({}) indicates a non-view function",
state.last_instruction.instruction, opcode_name
state.last_instruction.instruction,
opcode_info.name()
);
function.view = false;
}
Expand Down
4 changes: 2 additions & 2 deletions crates/decompile/src/utils/heuristics/solidity.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use alloy::primitives::U256;
use alloy_dyn_abi::{DynSolType, DynSolValue};
use heimdall_common::utils::strings::encode_hex_reduced;
use heimdall_vm::core::{opcodes::OpCodeInfo, vm::State};
use heimdall_vm::core::{opcodes::opcode_name, vm::State};

use crate::{
core::analyze::AnalyzerState,
Expand Down Expand Up @@ -188,7 +188,7 @@ pub fn solidity_heuristic(
function.logic.push(format!(
"(bool success, bytes memory ret0) = address({}).{}{}(abi.encode({}));",
address,
OpCodeInfo::from(instruction.opcode).name().to_lowercase(),
opcode_name(instruction.opcode).to_lowercase(),
modifier,
calldata
.iter()
Expand Down
6 changes: 3 additions & 3 deletions crates/decompile/src/utils/heuristics/yul.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use heimdall_common::utils::strings::encode_hex_reduced;
use heimdall_vm::core::{opcodes::OpCodeInfo, vm::State};
use heimdall_vm::core::{opcodes::opcode_name, vm::State};

use crate::{
core::analyze::AnalyzerState,
Expand All @@ -24,7 +24,7 @@ pub fn yul_heuristic(
function.memory.insert(key, StorageFrame { operation });
function.logic.push(format!(
"{}({}, {})",
OpCodeInfo::from(instruction.opcode).name().to_lowercase(),
opcode_name(instruction.opcode).to_lowercase(),
encode_hex_reduced(key),
instruction.input_operations[1].yulify()
));
Expand Down Expand Up @@ -80,7 +80,7 @@ pub fn yul_heuristic(
0xff | 0xA0 | 0xA1 | 0xA2 | 0xA3 | 0xA4 => {
function.logic.push(format!(
"{}({})",
OpCodeInfo::from(instruction.opcode).name().to_lowercase(),
opcode_name(instruction.opcode).to_lowercase(),
instruction
.input_operations
.iter()
Expand Down
4 changes: 2 additions & 2 deletions crates/disassemble/src/core/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::time::Instant;
use crate::{error::Error, interfaces::DisassemblerArgs};
use eyre::eyre;
use heimdall_common::utils::strings::encode_hex;
use heimdall_vm::core::opcodes::OpCodeInfo;
use heimdall_vm::core::opcodes::opcode_name;
use tracing::{debug, info};

pub async fn disassemble(args: DisassemblerArgs) -> Result<String, Error> {
Expand Down Expand Up @@ -45,7 +45,7 @@ pub async fn disassemble(args: DisassemblerArgs) -> Result<String, Error> {
} else {
format!("{:06x}", program_counter)
},
OpCodeInfo::from(opcode).name(),
opcode_name(opcode),
pushed_bytes
)
.as_str(),
Expand Down
6 changes: 3 additions & 3 deletions crates/vm/benches/bench_ten_thousand_hashes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ use heimdall_common::utils::strings::decode_hex;
use heimdall_vm::core::vm::VM;
use tokio::runtime::Runtime;

fn test_fib(c: &mut Criterion) {
fn test_ten_thousand_hashes(c: &mut Criterion) {
let mut group = c.benchmark_group("heimdall_vm");

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

criterion_group!(benches, test_fib);
criterion_group!(benches, test_ten_thousand_hashes);
criterion_main!(benches);
19 changes: 17 additions & 2 deletions crates/vm/src/core/opcodes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ impl OpCodeInfo {
impl From<u8> for OpCodeInfo {
#[inline]
fn from(opcode: u8) -> Self {
OPCODE_INFO_JUMPTABLE[opcode as usize].unwrap_or(OpCodeInfo {
OPCODE_INFO_TABLE[opcode as usize].unwrap_or(OpCodeInfo {
name: "unknown",
inputs: 0,
outputs: 0,
Expand Down Expand Up @@ -269,7 +269,7 @@ macro_rules! opcodes {
)*

/// Maps each opcode to its info.
pub const OPCODE_INFO_JUMPTABLE: [Option<OpCodeInfo>; 256] = {
pub const OPCODE_INFO_TABLE: [Option<OpCodeInfo>; 256] = {
let mut map = [None; 256];
let mut prev: u8 = 0;
$(
Expand All @@ -287,9 +287,24 @@ macro_rules! opcodes {
let _ = prev;
map
};

/// Maps each opcode to its name. (So we dont need to load [`OpCodeInfo`] to get the name)
pub const OPCODE_NAME_TABLE: [&'static str; 256] = {
let mut map = ["unknown"; 256];
$(
map[$val] = stringify!($name);
)*
map
};
}
}

/// Get the name of an opcode.
#[inline]
pub fn opcode_name(opcode: u8) -> &'static str {
OPCODE_NAME_TABLE[opcode as usize]
}

opcodes! {
0x00 => STOP => terminating;

Expand Down
4 changes: 2 additions & 2 deletions crates/vm/src/core/opcodes/wrapped.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use alloy::primitives::U256;

use crate::core::opcodes::OpCodeInfo;
use crate::core::opcodes::opcode_name;

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