5
5
#![ cfg_attr( not( test) , warn( unused_crate_dependencies) ) ]
6
6
#![ cfg_attr( docsrs, feature( doc_cfg, doc_auto_cfg) ) ]
7
7
8
- #[ macro_use]
9
- extern crate foundry_common;
10
-
11
8
#[ macro_use]
12
9
extern crate tracing;
13
10
14
- use alloy_primitives:: { map:: HashMap , Bytes , B256 } ;
15
- use eyre:: { Context , Result } ;
11
+ use alloy_primitives:: {
12
+ map:: { B256HashMap , HashMap } ,
13
+ Bytes ,
14
+ } ;
15
+ use eyre:: Result ;
16
16
use foundry_compilers:: artifacts:: sourcemap:: SourceMap ;
17
17
use semver:: Version ;
18
18
use std:: {
19
19
collections:: BTreeMap ,
20
20
fmt:: Display ,
21
+ num:: NonZeroU32 ,
21
22
ops:: { Deref , DerefMut , Range } ,
22
23
path:: { Path , PathBuf } ,
23
24
sync:: Arc ,
@@ -119,22 +120,21 @@ impl CoverageReport {
119
120
is_deployed_code : bool ,
120
121
) -> Result < ( ) > {
121
122
// Add bytecode level hits
122
- let e = self
123
- . bytecode_hits
123
+ self . bytecode_hits
124
124
. entry ( contract_id. clone ( ) )
125
- . or_insert_with ( || HitMap :: new ( hit_map . bytecode . clone ( ) ) ) ;
126
- e . merge ( hit_map ) . wrap_err_with ( || format ! ( "{contract_id:?}" ) ) ? ;
125
+ . and_modify ( |m| m . merge ( hit_map ) )
126
+ . or_insert_with ( || hit_map . clone ( ) ) ;
127
127
128
128
// Add source level hits
129
129
if let Some ( anchors) = self . anchors . get ( contract_id) {
130
130
let anchors = if is_deployed_code { & anchors. 1 } else { & anchors. 0 } ;
131
131
for anchor in anchors {
132
- if let Some ( & hits) = hit_map. hits . get ( & anchor. instruction ) {
132
+ if let Some ( hits) = hit_map. get ( anchor. instruction ) {
133
133
self . items
134
134
. get_mut ( & contract_id. version )
135
135
. and_then ( |items| items. get_mut ( anchor. item_id ) )
136
136
. expect ( "Anchor refers to non-existent coverage item" )
137
- . hits += hits;
137
+ . hits += hits. get ( ) ;
138
138
}
139
139
}
140
140
}
@@ -160,9 +160,10 @@ impl CoverageReport {
160
160
161
161
/// A collection of [`HitMap`]s.
162
162
#[ derive( Clone , Debug , Default ) ]
163
- pub struct HitMaps ( pub HashMap < B256 , HitMap > ) ;
163
+ pub struct HitMaps ( pub B256HashMap < HitMap > ) ;
164
164
165
165
impl HitMaps {
166
+ /// Merges two `Option<HitMaps>`.
166
167
pub fn merge_opt ( a : & mut Option < Self > , b : Option < Self > ) {
167
168
match ( a, b) {
168
169
( _, None ) => { }
@@ -171,25 +172,22 @@ impl HitMaps {
171
172
}
172
173
}
173
174
175
+ /// Merges two `HitMaps`.
174
176
pub fn merge ( & mut self , other : Self ) {
175
- for ( code_hash, hit_map) in other. 0 {
176
- if let Some ( HitMap { hits : extra_hits, .. } ) = self . insert ( code_hash, hit_map) {
177
- for ( pc, hits) in extra_hits {
178
- self . entry ( code_hash)
179
- . and_modify ( |map| * map. hits . entry ( pc) . or_default ( ) += hits) ;
180
- }
181
- }
177
+ for ( code_hash, other) in other. 0 {
178
+ self . entry ( code_hash) . and_modify ( |e| e. merge ( & other) ) . or_insert ( other) ;
182
179
}
183
180
}
184
181
182
+ /// Merges two `HitMaps`.
185
183
pub fn merged ( mut self , other : Self ) -> Self {
186
184
self . merge ( other) ;
187
185
self
188
186
}
189
187
}
190
188
191
189
impl Deref for HitMaps {
192
- type Target = HashMap < B256 , HitMap > ;
190
+ type Target = B256HashMap < HitMap > ;
193
191
194
192
fn deref ( & self ) -> & Self :: Target {
195
193
& self . 0
@@ -207,40 +205,46 @@ impl DerefMut for HitMaps {
207
205
/// Contains low-level data about hit counters for the instructions in the bytecode of a contract.
208
206
#[ derive( Clone , Debug ) ]
209
207
pub struct HitMap {
210
- pub bytecode : Bytes ,
211
- pub hits : BTreeMap < usize , u64 > ,
208
+ bytecode : Bytes ,
209
+ hits : HashMap < u32 , u32 > ,
212
210
}
213
211
214
212
impl HitMap {
213
+ /// Create a new hitmap with the given bytecode.
215
214
pub fn new ( bytecode : Bytes ) -> Self {
216
- Self { bytecode, hits : BTreeMap :: new ( ) }
215
+ Self { bytecode, hits : Default :: default ( ) }
216
+ }
217
+
218
+ /// Returns the bytecode.
219
+ pub fn bytecode ( & self ) -> & Bytes {
220
+ & self . bytecode
217
221
}
218
222
219
- /// Increase the hit counter for the given program counter.
223
+ /// Returns the number of hits for the given program counter.
224
+ pub fn get ( & self , pc : usize ) -> Option < NonZeroU32 > {
225
+ NonZeroU32 :: new ( self . hits . get ( & Self :: cvt_pc ( pc) ) . copied ( ) . unwrap_or ( 0 ) )
226
+ }
227
+
228
+ /// Increase the hit counter by 1 for the given program counter.
220
229
pub fn hit ( & mut self , pc : usize ) {
221
- * self . hits . entry ( pc) . or_default ( ) += 1 ;
230
+ self . hits ( pc, 1 )
231
+ }
232
+
233
+ /// Increase the hit counter by `hits` for the given program counter.
234
+ pub fn hits ( & mut self , pc : usize , hits : u32 ) {
235
+ * self . hits . entry ( Self :: cvt_pc ( pc) ) . or_default ( ) += hits;
222
236
}
223
237
224
238
/// Merge another hitmap into this, assuming the bytecode is consistent
225
- pub fn merge ( & mut self , other : & Self ) -> Result < ( ) , eyre :: Report > {
226
- for ( pc, hits) in & other. hits {
227
- * self . hits . entry ( * pc ) . or_default ( ) += hits;
239
+ pub fn merge ( & mut self , other : & Self ) {
240
+ for ( & pc, & hits) in & other. hits {
241
+ self . hits ( pc as usize , hits) ;
228
242
}
229
- Ok ( ( ) )
230
243
}
231
244
232
- pub fn consistent_bytecode ( & self , hm1 : & Self , hm2 : & Self ) -> bool {
233
- // Consider the bytecodes consistent if they are the same out as far as the
234
- // recorded hits
235
- let len1 = hm1. hits . last_key_value ( ) ;
236
- let len2 = hm2. hits . last_key_value ( ) ;
237
- if let ( Some ( len1) , Some ( len2) ) = ( len1, len2) {
238
- let len = std:: cmp:: max ( len1. 0 , len2. 0 ) ;
239
- let ok = hm1. bytecode . 0 [ ..* len] == hm2. bytecode . 0 [ ..* len] ;
240
- let _ = sh_println ! ( "consistent_bytecode: {}, {}, {}, {}" , ok, len1. 0 , len2. 0 , len) ;
241
- return ok;
242
- }
243
- true
245
+ #[ inline]
246
+ fn cvt_pc ( pc : usize ) -> u32 {
247
+ pc. try_into ( ) . expect ( "4GiB bytecode" )
244
248
}
245
249
}
246
250
@@ -311,7 +315,7 @@ pub struct CoverageItem {
311
315
/// The location of the item in the source code.
312
316
pub loc : SourceLocation ,
313
317
/// The number of times this item was hit.
314
- pub hits : u64 ,
318
+ pub hits : u32 ,
315
319
}
316
320
317
321
impl Display for CoverageItem {
0 commit comments