Skip to content

Commit 4d1f72b

Browse files
authored
perf(coverage): use u32 for IDs, improve analysis (#9763)
* refactor(debugger): renames, less clones * perf(coverage): use u32 for IDs, improve analysis * perf: don't keep source maps around, shrink_to_fit * chore: clippy * fmt
1 parent 58166ca commit 4d1f72b

File tree

18 files changed

+469
-448
lines changed

18 files changed

+469
-448
lines changed

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ alloy-json-abi = "0.8.18"
212212
alloy-primitives = { version = "0.8.18", features = [
213213
"getrandom",
214214
"rand",
215+
"map-fxhash",
215216
"map-foldhash",
216217
] }
217218
alloy-sol-macro-expander = "0.8.18"

crates/common/src/fs.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
//! Contains various `std::fs` wrapper functions that also contain the target path in their errors
1+
//! Contains various `std::fs` wrapper functions that also contain the target path in their errors.
2+
23
use crate::errors::FsPathError;
34
use serde::{de::DeserializeOwned, Serialize};
45
use std::{
@@ -7,7 +8,8 @@ use std::{
78
path::{Component, Path, PathBuf},
89
};
910

10-
type Result<T> = std::result::Result<T, FsPathError>;
11+
/// The [`fs`](self) result type.
12+
pub type Result<T> = std::result::Result<T, FsPathError>;
1113

1214
/// Wrapper for [`File::create`].
1315
pub fn create_file(path: impl AsRef<Path>) -> Result<fs::File> {

crates/debugger/src/debugger.rs

+4-6
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
//! Debugger implementation.
22
3-
use crate::{tui::TUI, DebugNode, DebuggerBuilder, ExitReason, FileDumper};
3+
use crate::{tui::TUI, DebugNode, DebuggerBuilder, ExitReason};
44
use alloy_primitives::map::AddressHashMap;
55
use eyre::Result;
66
use foundry_common::evm::Breakpoints;
77
use foundry_evm_traces::debug::ContractSources;
8-
use std::path::PathBuf;
8+
use std::path::Path;
99

1010
pub struct DebuggerContext {
1111
pub debug_arena: Vec<DebugNode>,
@@ -64,10 +64,8 @@ impl Debugger {
6464
}
6565

6666
/// Dumps debugger data to file.
67-
pub fn dump_to_file(&mut self, path: &PathBuf) -> Result<()> {
67+
pub fn dump_to_file(&mut self, path: &Path) -> Result<()> {
6868
eyre::ensure!(!self.context.debug_arena.is_empty(), "debug arena is empty");
69-
70-
let mut file_dumper = FileDumper::new(path, &mut self.context);
71-
file_dumper.run()
69+
crate::dump::dump(path, &self.context)
7270
}
7371
}

crates/debugger/src/dump.rs

+148
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
use crate::{debugger::DebuggerContext, DebugNode};
2+
use alloy_primitives::map::AddressMap;
3+
use foundry_common::fs::write_json_file;
4+
use foundry_compilers::{
5+
artifacts::sourcemap::{Jump, SourceElement},
6+
multi::MultiCompilerLanguage,
7+
};
8+
use foundry_evm_core::utils::PcIcMap;
9+
use foundry_evm_traces::debug::{ArtifactData, ContractSources, SourceData};
10+
use serde::Serialize;
11+
use std::{collections::HashMap, path::Path};
12+
13+
/// Dumps debugger data to a JSON file.
14+
pub(crate) fn dump(path: &Path, context: &DebuggerContext) -> eyre::Result<()> {
15+
write_json_file(path, &DebuggerDump::new(context))?;
16+
Ok(())
17+
}
18+
19+
/// Holds info of debugger dump.
20+
#[derive(Serialize)]
21+
struct DebuggerDump<'a> {
22+
contracts: ContractsDump<'a>,
23+
debug_arena: &'a [DebugNode],
24+
}
25+
26+
impl<'a> DebuggerDump<'a> {
27+
fn new(debugger_context: &'a DebuggerContext) -> Self {
28+
Self {
29+
contracts: ContractsDump::new(debugger_context),
30+
debug_arena: &debugger_context.debug_arena,
31+
}
32+
}
33+
}
34+
35+
#[derive(Serialize)]
36+
struct SourceElementDump {
37+
offset: u32,
38+
length: u32,
39+
index: i32,
40+
jump: u32,
41+
modifier_depth: u32,
42+
}
43+
44+
impl SourceElementDump {
45+
fn new(v: &SourceElement) -> Self {
46+
Self {
47+
offset: v.offset(),
48+
length: v.length(),
49+
index: v.index_i32(),
50+
jump: match v.jump() {
51+
Jump::In => 0,
52+
Jump::Out => 1,
53+
Jump::Regular => 2,
54+
},
55+
modifier_depth: v.modifier_depth(),
56+
}
57+
}
58+
}
59+
60+
#[derive(Serialize)]
61+
struct ContractsDump<'a> {
62+
identified_contracts: &'a AddressMap<String>,
63+
sources: ContractsSourcesDump<'a>,
64+
}
65+
66+
impl<'a> ContractsDump<'a> {
67+
fn new(debugger_context: &'a DebuggerContext) -> Self {
68+
Self {
69+
identified_contracts: &debugger_context.identified_contracts,
70+
sources: ContractsSourcesDump::new(&debugger_context.contracts_sources),
71+
}
72+
}
73+
}
74+
75+
#[derive(Serialize)]
76+
struct ContractsSourcesDump<'a> {
77+
sources_by_id: HashMap<&'a str, HashMap<u32, SourceDataDump<'a>>>,
78+
artifacts_by_name: HashMap<&'a str, Vec<ArtifactDataDump<'a>>>,
79+
}
80+
81+
impl<'a> ContractsSourcesDump<'a> {
82+
fn new(contracts_sources: &'a ContractSources) -> Self {
83+
Self {
84+
sources_by_id: contracts_sources
85+
.sources_by_id
86+
.iter()
87+
.map(|(name, inner_map)| {
88+
(
89+
name.as_str(),
90+
inner_map
91+
.iter()
92+
.map(|(id, source_data)| (*id, SourceDataDump::new(source_data)))
93+
.collect(),
94+
)
95+
})
96+
.collect(),
97+
artifacts_by_name: contracts_sources
98+
.artifacts_by_name
99+
.iter()
100+
.map(|(name, data)| {
101+
(name.as_str(), data.iter().map(ArtifactDataDump::new).collect())
102+
})
103+
.collect(),
104+
}
105+
}
106+
}
107+
108+
#[derive(Serialize)]
109+
struct SourceDataDump<'a> {
110+
source: &'a str,
111+
language: MultiCompilerLanguage,
112+
path: &'a Path,
113+
}
114+
115+
impl<'a> SourceDataDump<'a> {
116+
fn new(v: &'a SourceData) -> Self {
117+
Self { source: &v.source, language: v.language, path: &v.path }
118+
}
119+
}
120+
121+
#[derive(Serialize)]
122+
struct ArtifactDataDump<'a> {
123+
source_map: Option<Vec<SourceElementDump>>,
124+
source_map_runtime: Option<Vec<SourceElementDump>>,
125+
pc_ic_map: Option<&'a PcIcMap>,
126+
pc_ic_map_runtime: Option<&'a PcIcMap>,
127+
build_id: &'a str,
128+
file_id: u32,
129+
}
130+
131+
impl<'a> ArtifactDataDump<'a> {
132+
fn new(v: &'a ArtifactData) -> Self {
133+
Self {
134+
source_map: v
135+
.source_map
136+
.as_ref()
137+
.map(|source_map| source_map.iter().map(SourceElementDump::new).collect()),
138+
source_map_runtime: v
139+
.source_map_runtime
140+
.as_ref()
141+
.map(|source_map| source_map.iter().map(SourceElementDump::new).collect()),
142+
pc_ic_map: v.pc_ic_map.as_ref(),
143+
pc_ic_map_runtime: v.pc_ic_map_runtime.as_ref(),
144+
build_id: &v.build_id,
145+
file_id: v.file_id,
146+
}
147+
}
148+
}

crates/debugger/src/file_dumper.rs

-172
This file was deleted.

crates/debugger/src/lib.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ mod op;
1515

1616
mod builder;
1717
mod debugger;
18-
mod file_dumper;
18+
mod dump;
1919
mod tui;
2020

2121
mod node;
@@ -24,5 +24,4 @@ pub use node::DebugNode;
2424

2525
pub use builder::DebuggerBuilder;
2626
pub use debugger::Debugger;
27-
pub use file_dumper::FileDumper;
2827
pub use tui::{ExitReason, TUI};

crates/debugger/src/tui/draw.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ impl TUIContext<'_> {
351351
.contracts_sources
352352
.find_source_mapping(
353353
contract_name,
354-
self.current_step().pc,
354+
self.current_step().pc as u32,
355355
self.debug_call().kind.is_any_create(),
356356
)
357357
.ok_or_else(|| format!("No source map for contract {contract_name}"))

0 commit comments

Comments
 (0)