Skip to content

Commit d6080c8

Browse files
authored
feat: Refactor analysis traits to reduce copies (#146)
* Initial too-complicated refactor * small clippy fixes * streamlined * reorg checkpoint * More refactoring
1 parent 8045f32 commit d6080c8

File tree

27 files changed

+522
-321
lines changed

27 files changed

+522
-321
lines changed

jingle/examples/location.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
use jingle::analysis::Analysis;
44
use jingle::analysis::cpa::RunnableConfigurableProgramAnalysis;
5-
use jingle::analysis::cpa::reducer::CfgReducer;
5+
use jingle::analysis::cpa::residue::CFG;
66
use jingle::analysis::cpa::residue::Residue;
77
use jingle::analysis::cpa::state::LocationState;
88
use jingle::analysis::location::{BasicLocationAnalysis, CallBehavior};

jingle/examples/stack_offset.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22

33
use jingle::analysis::Analysis;
44
use jingle::analysis::cpa::lattice::pcode::PcodeAddressLattice;
5-
use jingle::analysis::cpa::reducer::CfgReducer;
5+
use jingle::analysis::cpa::residue::CFG;
66
use jingle::analysis::cpa::residue::Residue;
77
use jingle::analysis::cpa::state::LocationState;
88
use jingle::analysis::cpa::{FinalReducer, RunnableConfigurableProgramAnalysis};
99
use jingle::analysis::location::{BasicLocationAnalysis, CallBehavior};
1010
use jingle::analysis::pcode_store::PcodeStore;
11+
use jingle::analysis::pcode_store::{self, PcodeOpRef};
1112
use jingle::analysis::valuation::{
1213
MergeBehavior, SimpleValuation, SimpleValuationAnalysis, SimpleValuationState,
1314
};
@@ -58,9 +59,8 @@ fn main() {
5859
let valuation_analysis =
5960
SimpleValuationAnalysis::new(loaded.arch_info().clone(), MergeBehavior::Or);
6061

61-
// The tuple implements Analysis via the compound machinery; wrap it with the CfgReducer
62-
let mut compound_with_cfg =
63-
(location_analysis, valuation_analysis).with_residue(CfgReducer::new());
62+
// The tuple implements Analysis via the compound machinery; wrap it with the CfgReducer (factory)
63+
let mut compound_with_cfg = (location_analysis, valuation_analysis).with_residue(CFG);
6464

6565
tracing::info!("Starting analysis run at address 0x{:x}", FUNC_NESTED);
6666

@@ -133,7 +133,7 @@ fn main() {
133133

134134
let op_str = cfg
135135
.get_op_at(node)
136-
.map(|o: &jingle_sleigh::PcodeOperation| format!("{}", o))
136+
.map(|o: &PcodeOpRef<'_>| format!("{}", o.as_ref()))
137137
.unwrap_or_else(|| "no-op".to_string());
138138

139139
println!(" {} -> {}: {}", origin_str, succ_str, op_str);

jingle/examples/stack_offset_smt.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22

33
use jingle::analysis::Analysis;
44
use jingle::analysis::cpa::lattice::pcode::PcodeAddressLattice;
5-
use jingle::analysis::cpa::reducer::CfgReducer;
5+
use jingle::analysis::cpa::residue::CFG;
66
use jingle::analysis::cpa::residue::Residue;
77
use jingle::analysis::cpa::state::LocationState;
88
use jingle::analysis::cpa::{FinalReducer, RunnableConfigurableProgramAnalysis};
99
use jingle::analysis::location::{BasicLocationAnalysis, CallBehavior};
1010
use jingle::analysis::pcode_store::PcodeStore;
11+
use jingle::analysis::pcode_store::{self, PcodeOpRef};
1112
use jingle::analysis::valuation::{MergeBehavior, SmtVal, SmtValuationAnalysis, SmtValuationState};
1213
use jingle::display::JingleDisplayable;
1314
use jingle::modeling::machine::cpu::concrete::ConcretePcodeAddress;
@@ -57,8 +58,7 @@ fn main() {
5758
SmtValuationAnalysis::new(loaded.arch_info().clone(), MergeBehavior::Or);
5859

5960
// The tuple implements Analysis via the compound machinery; wrap it with the CfgReducer
60-
let mut compound_with_cfg =
61-
(location_analysis, valuation_analysis).with_residue(CfgReducer::new());
61+
let mut compound_with_cfg = (location_analysis, valuation_analysis).with_residue(CFG);
6262

6363
tracing::info!("Starting analysis run at address 0x{:x}", FUNC_NESTED);
6464

@@ -131,7 +131,7 @@ fn main() {
131131

132132
let op_str = cfg
133133
.get_op_at(node)
134-
.map(|o: &jingle_sleigh::PcodeOperation| format!("{}", o))
134+
.map(|o: &PcodeOpRef<'_>| format!("{}", o.as_ref()))
135135
.unwrap_or_else(|| "no-op".to_string());
136136

137137
println!(" {} -> {}: {}", origin_str, succ_str, op_str);

jingle/examples/unwind.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#![allow(unused)]
22

33
use jingle::analysis::cpa::RunnableConfigurableProgramAnalysis;
4-
use jingle::analysis::cpa::reducer::CfgReducer;
4+
use jingle::analysis::cpa::residue::CFG;
55
use jingle::analysis::cpa::residue::Residue;
66
use jingle::analysis::cpa::state::LocationState;
77
use jingle::analysis::location::{CallBehavior, UnwindingAnalysis};
@@ -46,8 +46,8 @@ fn main() {
4646
UnwindingAnalysis::new(2),
4747
);
4848

49-
// Wrap with CfgReducer
50-
let mut analysis_with_cfg = location_analysis.with_residue(CfgReducer::new());
49+
// Wrap with CfgReducer (pass the factory ZST)
50+
let mut analysis_with_cfg = location_analysis.with_residue(CFG);
5151

5252
// Run the unwinding analysis
5353
let cfg = analysis_with_cfg.run(&loaded, ConcretePcodeAddress::from(FUNC_NESTED));

jingle/src/analysis/cfg/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ impl LowerHex for EmptyEdge {
2929
}
3030

3131
#[derive(Debug)]
32-
pub struct PcodeCfg<N: CfgState = ConcretePcodeAddress, D = PcodeOperation> {
32+
pub struct PcodeCfg<N, D> {
3333
pub(crate) graph: StableDiGraph<N, EmptyEdge>,
3434
// Key pcode ops by concrete p-code address so lookups by address are efficient.
3535
// For CFG states `N` that can produce a `ConcretePcodeAddress` via `location()`,

jingle/src/analysis/cfg/model.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::JingleError;
22
// use crate::analysis::compound::CompoundState;
33
use crate::analysis::cpa::lattice::flat::FlatLattice;
4+
use crate::analysis::pcode_store::PcodeOpRef;
45
use crate::modeling::machine::MachineState;
56
use crate::modeling::machine::cpu::concrete::ConcretePcodeAddress;
67
use jingle_sleigh::{PcodeOperation, SleighArchInfo};
@@ -110,6 +111,12 @@ impl<N: CfgStateModel> ModelTransition<N> for PcodeOperation {
110111
}
111112
}
112113

114+
impl<'a, N: CfgStateModel> ModelTransition<N> for PcodeOpRef<'a> {
115+
fn transition(&self, init: &N) -> Result<N, JingleError> {
116+
init.apply(self)
117+
}
118+
}
119+
113120
impl<N: CfgStateModel, T: ModelTransition<N>> ModelTransition<N> for Vec<T> {
114121
fn transition(&self, init: &N) -> Result<N, JingleError> {
115122
let mut state = init.clone();

jingle/src/analysis/compound/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ where
2020
{
2121
type State = CompoundState2<A::State, B::State>;
2222

23-
type Reducer = CompoundReducer2<A, B>;
23+
type Reducer<'op> = CompoundReducer2<'op, A, B>;
2424
}
2525

2626
impl<A: ConfigurableProgramAnalysis, B: ConfigurableProgramAnalysis, T> IntoState<(A, B)> for T
@@ -52,7 +52,7 @@ where
5252
type State = CompoundState3<A::State, B::State, C::State>;
5353

5454
// 3-ary reducer
55-
type Reducer = CompoundReducer3<A, B, C>;
55+
type Reducer<'op> = CompoundReducer3<'op, A, B, C>;
5656
}
5757

5858
impl<
@@ -96,7 +96,7 @@ where
9696
type State = CompoundState4<A::State, B::State, C::State, D::State>;
9797

9898
// 4-ary reducer
99-
type Reducer = CompoundReducer4<A, B, C, D>;
99+
type Reducer<'op> = CompoundReducer4<'op, A, B, C, D>;
100100
}
101101

102102
impl<

jingle/src/analysis/compound/reducer.rs

Lines changed: 58 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,23 @@ use crate::analysis::{
44
};
55

66
/// Generic 2-ary compound reducer (keeps the old name for backward compatibility).
7-
pub struct CompoundReducer<A: ConfigurableProgramAnalysis, B: ConfigurableProgramAnalysis> {
8-
a: A::Reducer,
9-
b: B::Reducer,
7+
pub struct CompoundReducer<'op, A: ConfigurableProgramAnalysis, B: ConfigurableProgramAnalysis> {
8+
a: A::Reducer<'op>,
9+
b: B::Reducer<'op>,
1010
}
1111

12-
impl<A: ConfigurableProgramAnalysis, B: ConfigurableProgramAnalysis>
13-
Residue<CompoundState2<A::State, B::State>> for CompoundReducer<A, B>
12+
impl<'op, A: ConfigurableProgramAnalysis, B: ConfigurableProgramAnalysis>
13+
Residue<'op, CompoundState2<A::State, B::State>> for CompoundReducer<'op, A, B>
1414
{
1515
type Output = (
16-
<A::Reducer as Residue<A::State>>::Output,
17-
<B::Reducer as Residue<B::State>>::Output,
16+
<A::Reducer<'op> as Residue<'op, A::State>>::Output,
17+
<B::Reducer<'op> as Residue<'op, B::State>>::Output,
1818
);
1919

2020
fn new() -> Self {
2121
Self {
22-
a: A::Reducer::new(),
23-
b: B::Reducer::new(),
22+
a: <A::Reducer<'op> as Residue<'op, A::State>>::new(),
23+
b: <B::Reducer<'op> as Residue<'op, B::State>>::new(),
2424
}
2525
}
2626

@@ -34,7 +34,7 @@ impl<A: ConfigurableProgramAnalysis, B: ConfigurableProgramAnalysis>
3434
curr_state: &CompoundState2<A::State, B::State>,
3535
dest_state: &CompoundState2<A::State, B::State>,
3636
merged_state: &CompoundState2<A::State, B::State>,
37-
op: &Option<crate::analysis::pcode_store::PcodeOpRef<'_>>,
37+
op: &Option<crate::analysis::pcode_store::PcodeOpRef<'op>>,
3838
) {
3939
self.a
4040
.merged_state(&curr_state.s1, &dest_state.s1, &merged_state.s1, op);
@@ -46,31 +46,31 @@ impl<A: ConfigurableProgramAnalysis, B: ConfigurableProgramAnalysis>
4646
&mut self,
4747
state: &CompoundState2<A::State, B::State>,
4848
dest_state: &CompoundState2<A::State, B::State>,
49-
op: &Option<crate::analysis::pcode_store::PcodeOpRef<'_>>,
49+
op: &Option<crate::analysis::pcode_store::PcodeOpRef<'op>>,
5050
) {
5151
self.a.new_state(&state.s1, &dest_state.s1, op);
5252
self.b.new_state(&state.s2, &dest_state.s2, op);
5353
}
5454
}
5555

5656
/// Explicitly named 2-ary reducer.
57-
pub struct CompoundReducer2<A: ConfigurableProgramAnalysis, B: ConfigurableProgramAnalysis> {
58-
a: A::Reducer,
59-
b: B::Reducer,
57+
pub struct CompoundReducer2<'op, A: ConfigurableProgramAnalysis, B: ConfigurableProgramAnalysis> {
58+
a: A::Reducer<'op>,
59+
b: B::Reducer<'op>,
6060
}
6161

62-
impl<A: ConfigurableProgramAnalysis, B: ConfigurableProgramAnalysis>
63-
Residue<CompoundState2<A::State, B::State>> for CompoundReducer2<A, B>
62+
impl<'op, A: ConfigurableProgramAnalysis, B: ConfigurableProgramAnalysis>
63+
Residue<'op, CompoundState2<A::State, B::State>> for CompoundReducer2<'op, A, B>
6464
{
6565
type Output = (
66-
<A::Reducer as Residue<A::State>>::Output,
67-
<B::Reducer as Residue<B::State>>::Output,
66+
<A::Reducer<'op> as Residue<'op, A::State>>::Output,
67+
<B::Reducer<'op> as Residue<'op, B::State>>::Output,
6868
);
6969

7070
fn new() -> Self {
7171
Self {
72-
a: A::Reducer::new(),
73-
b: B::Reducer::new(),
72+
a: <A::Reducer<'op> as Residue<'op, A::State>>::new(),
73+
b: <B::Reducer<'op> as Residue<'op, B::State>>::new(),
7474
}
7575
}
7676

@@ -84,7 +84,7 @@ impl<A: ConfigurableProgramAnalysis, B: ConfigurableProgramAnalysis>
8484
curr_state: &CompoundState2<A::State, B::State>,
8585
dest_state: &CompoundState2<A::State, B::State>,
8686
merged_state: &CompoundState2<A::State, B::State>,
87-
op: &Option<crate::analysis::pcode_store::PcodeOpRef<'_>>,
87+
op: &Option<crate::analysis::pcode_store::PcodeOpRef<'op>>,
8888
) {
8989
self.a
9090
.merged_state(&curr_state.s1, &dest_state.s1, &merged_state.s1, op);
@@ -96,7 +96,7 @@ impl<A: ConfigurableProgramAnalysis, B: ConfigurableProgramAnalysis>
9696
&mut self,
9797
state: &CompoundState2<A::State, B::State>,
9898
dest_state: &CompoundState2<A::State, B::State>,
99-
op: &Option<crate::analysis::pcode_store::PcodeOpRef<'_>>,
99+
op: &Option<crate::analysis::pcode_store::PcodeOpRef<'op>>,
100100
) {
101101
self.a.new_state(&state.s1, &dest_state.s1, op);
102102
self.b.new_state(&state.s2, &dest_state.s2, op);
@@ -105,29 +105,34 @@ impl<A: ConfigurableProgramAnalysis, B: ConfigurableProgramAnalysis>
105105

106106
/// 3-ary compound reducer.
107107
pub struct CompoundReducer3<
108+
'op,
108109
A: ConfigurableProgramAnalysis,
109110
B: ConfigurableProgramAnalysis,
110111
C: ConfigurableProgramAnalysis,
111112
> {
112-
a: A::Reducer,
113-
b: B::Reducer,
114-
c: C::Reducer,
113+
a: A::Reducer<'op>,
114+
b: B::Reducer<'op>,
115+
c: C::Reducer<'op>,
115116
}
116117

117-
impl<A: ConfigurableProgramAnalysis, B: ConfigurableProgramAnalysis, C: ConfigurableProgramAnalysis>
118-
Residue<CompoundState3<A::State, B::State, C::State>> for CompoundReducer3<A, B, C>
118+
impl<
119+
'op,
120+
A: ConfigurableProgramAnalysis,
121+
B: ConfigurableProgramAnalysis,
122+
C: ConfigurableProgramAnalysis,
123+
> Residue<'op, CompoundState3<A::State, B::State, C::State>> for CompoundReducer3<'op, A, B, C>
119124
{
120125
type Output = (
121-
<A::Reducer as Residue<A::State>>::Output,
122-
<B::Reducer as Residue<B::State>>::Output,
123-
<C::Reducer as Residue<C::State>>::Output,
126+
<A::Reducer<'op> as Residue<'op, A::State>>::Output,
127+
<B::Reducer<'op> as Residue<'op, B::State>>::Output,
128+
<C::Reducer<'op> as Residue<'op, C::State>>::Output,
124129
);
125130

126131
fn new() -> Self {
127132
Self {
128-
a: A::Reducer::new(),
129-
b: B::Reducer::new(),
130-
c: C::Reducer::new(),
133+
a: <A::Reducer<'op> as Residue<'op, A::State>>::new(),
134+
b: <B::Reducer<'op> as Residue<'op, B::State>>::new(),
135+
c: <C::Reducer<'op> as Residue<'op, C::State>>::new(),
131136
}
132137
}
133138

@@ -141,7 +146,7 @@ impl<A: ConfigurableProgramAnalysis, B: ConfigurableProgramAnalysis, C: Configur
141146
curr_state: &CompoundState3<A::State, B::State, C::State>,
142147
dest_state: &CompoundState3<A::State, B::State, C::State>,
143148
merged_state: &CompoundState3<A::State, B::State, C::State>,
144-
op: &Option<crate::analysis::pcode_store::PcodeOpRef<'_>>,
149+
op: &Option<crate::analysis::pcode_store::PcodeOpRef<'op>>,
145150
) {
146151
self.a
147152
.merged_state(&curr_state.s1, &dest_state.s1, &merged_state.s1, op);
@@ -155,7 +160,7 @@ impl<A: ConfigurableProgramAnalysis, B: ConfigurableProgramAnalysis, C: Configur
155160
&mut self,
156161
state: &CompoundState3<A::State, B::State, C::State>,
157162
dest_state: &CompoundState3<A::State, B::State, C::State>,
158-
op: &Option<crate::analysis::pcode_store::PcodeOpRef<'_>>,
163+
op: &Option<crate::analysis::pcode_store::PcodeOpRef<'op>>,
159164
) {
160165
self.a.new_state(&state.s1, &dest_state.s1, op);
161166
self.b.new_state(&state.s2, &dest_state.s2, op);
@@ -165,37 +170,40 @@ impl<A: ConfigurableProgramAnalysis, B: ConfigurableProgramAnalysis, C: Configur
165170

166171
/// 4-ary compound reducer.
167172
pub struct CompoundReducer4<
173+
'op,
168174
A: ConfigurableProgramAnalysis,
169175
B: ConfigurableProgramAnalysis,
170176
C: ConfigurableProgramAnalysis,
171177
D: ConfigurableProgramAnalysis,
172178
> {
173-
a: A::Reducer,
174-
b: B::Reducer,
175-
c: C::Reducer,
176-
d: D::Reducer,
179+
a: A::Reducer<'op>,
180+
b: B::Reducer<'op>,
181+
c: C::Reducer<'op>,
182+
d: D::Reducer<'op>,
177183
}
178184

179185
impl<
186+
'op,
180187
A: ConfigurableProgramAnalysis,
181188
B: ConfigurableProgramAnalysis,
182189
C: ConfigurableProgramAnalysis,
183190
D: ConfigurableProgramAnalysis,
184-
> Residue<CompoundState4<A::State, B::State, C::State, D::State>> for CompoundReducer4<A, B, C, D>
191+
> Residue<'op, CompoundState4<A::State, B::State, C::State, D::State>>
192+
for CompoundReducer4<'op, A, B, C, D>
185193
{
186194
type Output = (
187-
<A::Reducer as Residue<A::State>>::Output,
188-
<B::Reducer as Residue<B::State>>::Output,
189-
<C::Reducer as Residue<C::State>>::Output,
190-
<D::Reducer as Residue<D::State>>::Output,
195+
<A::Reducer<'op> as Residue<'op, A::State>>::Output,
196+
<B::Reducer<'op> as Residue<'op, B::State>>::Output,
197+
<C::Reducer<'op> as Residue<'op, C::State>>::Output,
198+
<D::Reducer<'op> as Residue<'op, D::State>>::Output,
191199
);
192200

193201
fn new() -> Self {
194202
Self {
195-
a: A::Reducer::new(),
196-
b: B::Reducer::new(),
197-
c: C::Reducer::new(),
198-
d: D::Reducer::new(),
203+
a: <A::Reducer<'op> as Residue<'op, A::State>>::new(),
204+
b: <B::Reducer<'op> as Residue<'op, B::State>>::new(),
205+
c: <C::Reducer<'op> as Residue<'op, C::State>>::new(),
206+
d: <D::Reducer<'op> as Residue<'op, D::State>>::new(),
199207
}
200208
}
201209

@@ -209,7 +217,7 @@ impl<
209217
curr_state: &CompoundState4<A::State, B::State, C::State, D::State>,
210218
dest_state: &CompoundState4<A::State, B::State, C::State, D::State>,
211219
merged_state: &CompoundState4<A::State, B::State, C::State, D::State>,
212-
op: &Option<crate::analysis::pcode_store::PcodeOpRef<'_>>,
220+
op: &Option<crate::analysis::pcode_store::PcodeOpRef<'op>>,
213221
) {
214222
self.a
215223
.merged_state(&curr_state.s1, &dest_state.s1, &merged_state.s1, op);
@@ -225,7 +233,7 @@ impl<
225233
&mut self,
226234
state: &CompoundState4<A::State, B::State, C::State, D::State>,
227235
dest_state: &CompoundState4<A::State, B::State, C::State, D::State>,
228-
op: &Option<crate::analysis::pcode_store::PcodeOpRef<'_>>,
236+
op: &Option<crate::analysis::pcode_store::PcodeOpRef<'op>>,
229237
) {
230238
self.a.new_state(&state.s1, &dest_state.s1, op);
231239
self.b.new_state(&state.s2, &dest_state.s2, op);

0 commit comments

Comments
 (0)