@@ -20,16 +20,15 @@ impl MarkMap {
2020 . iter ( )
2121 . enumerate ( )
2222 . fold ( 0 , |offset, ( index, chunk) | match chunk {
23- Asm :: Ref ( _) => offset + chunk. size ( ) + ref_extra_bytes as usize ,
23+ Asm :: Ref ( _) => offset + chunk. base_size ( ) + ref_extra_bytes as usize ,
2424 Asm :: Mark ( id) => {
25- #[ cfg( feature = "sanity-checks" ) ]
2625 if inner_mark_map[ * id] . is_some ( ) {
2726 panic ! ( "Mark with duplicate id {} at index {}" , id, index) ;
2827 }
2928 inner_mark_map[ * id] = Some ( offset) ;
3029 offset
3130 }
32- _ => offset + chunk. size ( ) ,
31+ _ => offset + chunk. base_size ( ) ,
3332 } ) ;
3433
3534 ( Self ( inner_mark_map) , total_size)
@@ -43,13 +42,7 @@ impl MarkMap {
4342
4443 fn get_offset ( & self , index : usize , id : usize ) -> usize {
4544 self . 0 . get ( id) . and_then ( |value| * value) . unwrap_or_else ( || {
46- #[ cfg( feature = "sanity-checks" ) ]
47- {
48- panic ! ( "Reference to nonexistent mark {} at index {}" , id, index)
49- } ;
50-
51- #[ cfg( not( feature = "sanity-checks" ) ) ]
52- Default :: default ( )
45+ panic ! ( "Reference to nonexistent mark {} at index {}" , id, index) ;
5346 } )
5447 }
5548
@@ -58,14 +51,7 @@ impl MarkMap {
5851 RefType :: Delta ( start_id, end_id) => {
5952 let start_offset = self . get_offset ( index, * start_id) ;
6053 let end_offset = self . get_offset ( index, * end_id) ;
61- #[ cfg( feature = "sanity-checks" ) ]
62- if end_offset < start_offset {
63- panic ! (
64- "Delta reference at {} has end offset {} (id: {}) before start {} (id: {})" ,
65- index, end_offset, end_id, start_offset, start_id
66- ) ;
67- }
68- end_offset. wrapping_sub ( start_offset)
54+ end_offset - start_offset
6955 }
7056 RefType :: Direct ( id) => self . get_offset ( index, * id) ,
7157 }
@@ -85,6 +71,7 @@ pub enum AssembleError {
8571 InvalidSetSize { chunk_index : usize } ,
8672}
8773
74+ /// Assemble using the worst case size push opcodes for references.
8875pub fn assemble_maximized (
8976 asm : & [ Asm ] ,
9077 allow_push0 : bool ,
@@ -93,7 +80,7 @@ pub fn assemble_maximized(
9380 . iter ( )
9481 . filter ( |chunk| matches ! ( chunk, Asm :: Ref ( _) ) )
9582 . count ( ) ;
96- let known_size: usize = asm. iter ( ) . map ( |chunk| chunk. size ( ) ) . sum ( ) ;
83+ let known_size: usize = asm. iter ( ) . map ( |chunk| chunk. base_size ( ) ) . sum ( ) ;
9784 let max_ref_extra_bytes: u8 = max_ref_extra_bytes ( known_size, total_refs) ;
9885
9986 let ( mark_map, total_size) = MarkMap :: build ( asm, max_ref_extra_bytes) ;
@@ -111,7 +98,7 @@ pub fn assemble_maximized(
11198 } ) => {
11299 let value = mark_map. lookup_rt ( i, ref_type) ;
113100 let ref_extra_bytes = set_size. unwrap_or ( max_ref_extra_bytes) ;
114- let min_extra_bytes = value_to_ref_extra_bytes ( value, allow_push0) ;
101+ let min_extra_bytes = value_push_size ( value, allow_push0) ;
115102 if ref_extra_bytes < min_extra_bytes {
116103 return Err ( AssembleError :: InvalidSetSize { chunk_index : i } ) ;
117104 }
@@ -130,59 +117,54 @@ pub fn assemble_maximized(
130117
131118const MAX_CHANGES : usize = 10_000 ;
132119
120+ /// Assemble minimizing the push opcodes used for references.
133121pub fn assemble_minimized (
134122 asm : & [ Asm ] ,
135123 allow_push0 : bool ,
136124) -> Result < ( MarkMap , Vec < u8 > ) , AssembleError > {
137- let ( mark_map, total_size) =
138- {
139- let total_refs = asm
125+ let ( mark_map, total_size) = {
126+ let total_refs = asm
127+ . iter ( )
128+ . filter ( |chunk| matches ! ( chunk, Asm :: Ref ( _) ) )
129+ . count ( ) ;
130+ let known_size: usize = asm. iter ( ) . map ( |chunk| chunk. base_size ( ) ) . sum ( ) ;
131+ let ref_extra_bytes: u8 = max_ref_extra_bytes ( known_size, total_refs) ;
132+ let ( mut mark_map, mut total_size) = MarkMap :: build ( asm, ref_extra_bytes) ;
133+
134+ let mut made_a_change = true ;
135+ let mut change_count = 1 ;
136+
137+ while made_a_change {
138+ made_a_change = false ;
139+ total_size = asm
140140 . iter ( )
141- . filter ( |chunk| matches ! ( chunk, Asm :: Ref ( _) ) )
142- . count ( ) ;
143- let known_size: usize = asm. iter ( ) . map ( |chunk| chunk. size ( ) ) . sum ( ) ;
144- let ref_extra_bytes: u8 = max_ref_extra_bytes ( known_size, total_refs) ;
145- let ( mut mark_map, mut total_size) = MarkMap :: build ( asm, ref_extra_bytes) ;
146-
147- let mut made_a_change = true ;
148- let mut change_count = 1 ;
149-
150- while made_a_change {
151- ( total_size, made_a_change) = asm. iter ( ) . enumerate ( ) . fold (
152- ( 0 , false ) ,
153- |( offset, made_a_change) , ( i, chunk) | match chunk {
154- Asm :: Ref ( MarkRef {
155- ref_type, set_size, ..
156- } ) => {
157- let extra_size = set_size. map_or_else (
158- || {
159- value_to_ref_extra_bytes (
160- mark_map. lookup_rt ( i, ref_type) ,
161- allow_push0,
162- ) as usize
163- } ,
164- |_| 0 ,
165- ) ;
166-
167- ( offset + chunk. size ( ) + extra_size, made_a_change)
141+ . enumerate ( )
142+ . fold ( 0 , |offset, ( i, chunk) | match chunk {
143+ Asm :: Ref ( MarkRef {
144+ ref_type, set_size, ..
145+ } ) => {
146+ let ref_size = set_size. unwrap_or_else ( || {
147+ value_push_size ( mark_map. lookup_rt ( i, ref_type) , allow_push0)
148+ } ) as usize ;
149+ offset + chunk. base_size ( ) + ref_size
150+ }
151+ Asm :: Mark ( id) => {
152+ if mark_map. set_mark_offset ( * id, offset) {
153+ made_a_change = true ;
168154 }
169- #[ allow( clippy:: identity_op) ]
170- Asm :: Mark ( id) => (
171- offset + 0 ,
172- made_a_change || mark_map. set_mark_offset ( * id, offset) ,
173- ) ,
174- _ => ( offset + chunk. size ( ) , made_a_change) ,
175- } ,
176- ) ;
177- change_count += 1 ;
178- assert ! (
179- change_count <= MAX_CHANGES ,
180- "Max changes exceeded, likely infinite loop, report bug"
181- ) ;
182- }
155+ offset
156+ }
157+ _ => offset + chunk. base_size ( ) ,
158+ } ) ;
159+ change_count += 1 ;
160+ assert ! (
161+ change_count <= MAX_CHANGES ,
162+ "Max changes exceeded, likely infinite loop, report bug"
163+ ) ;
164+ }
183165
184- ( mark_map, total_size)
185- } ;
166+ ( mark_map, total_size)
167+ } ;
186168
187169 let mut final_code = Vec :: with_capacity ( total_size) ;
188170
@@ -197,7 +179,7 @@ pub fn assemble_minimized(
197179 set_size,
198180 } ) => {
199181 let value = mark_map. lookup_rt ( i, ref_type) ;
200- let min_extra_bytes = value_to_ref_extra_bytes ( value, allow_push0) ;
182+ let min_extra_bytes = value_push_size ( value, allow_push0) ;
201183 let ref_extra_bytes = set_size. unwrap_or_else ( || min_extra_bytes) ;
202184 if ref_extra_bytes < min_extra_bytes {
203185 return Err ( AssembleError :: InvalidSetSize { chunk_index : i } ) ;
@@ -215,7 +197,7 @@ pub fn assemble_minimized(
215197 Ok ( ( mark_map, final_code) )
216198}
217199
218- fn value_to_ref_extra_bytes ( value : usize , allow_push0 : bool ) -> u8 {
200+ fn value_push_size ( value : usize , allow_push0 : bool ) -> u8 {
219201 match ( value, allow_push0) {
220202 ( 0 , true ) => 0 ,
221203 ( 0 , false ) => 1 ,
@@ -288,30 +270,30 @@ mod tests {
288270
289271 #[ test]
290272 fn test_value_to_ref_extra_bytes ( ) {
291- assert_eq ! ( value_to_ref_extra_bytes ( 0 , true ) , 0 ) ;
292- assert_eq ! ( value_to_ref_extra_bytes ( 0 , false ) , 1 ) ;
293-
294- assert_eq ! ( value_to_ref_extra_bytes ( 1 , false ) , 1 ) ;
295- assert_eq ! ( value_to_ref_extra_bytes ( 2 , false ) , 1 ) ;
296- assert_eq ! ( value_to_ref_extra_bytes ( 3 , false ) , 1 ) ;
297- assert_eq ! ( value_to_ref_extra_bytes ( 4 , false ) , 1 ) ;
298- assert_eq ! ( value_to_ref_extra_bytes ( 5 , false ) , 1 ) ;
299- assert_eq ! ( value_to_ref_extra_bytes ( 6 , false ) , 1 ) ;
300- assert_eq ! ( value_to_ref_extra_bytes ( 7 , false ) , 1 ) ;
301- assert_eq ! ( value_to_ref_extra_bytes ( 8 , false ) , 1 ) ;
302- assert_eq ! ( value_to_ref_extra_bytes ( 256 , false ) , 2 ) ;
303- assert_eq ! ( value_to_ref_extra_bytes ( 65535 , false ) , 2 ) ;
304- assert_eq ! ( value_to_ref_extra_bytes ( 65536 , false ) , 3 ) ;
305-
306- assert_eq ! ( value_to_ref_extra_bytes ( 1 , true ) , 1 ) ;
307- assert_eq ! ( value_to_ref_extra_bytes ( 2 , true ) , 1 ) ;
308- assert_eq ! ( value_to_ref_extra_bytes ( 3 , true ) , 1 ) ;
309- assert_eq ! ( value_to_ref_extra_bytes ( 4 , true ) , 1 ) ;
310- assert_eq ! ( value_to_ref_extra_bytes ( 5 , true ) , 1 ) ;
311- assert_eq ! ( value_to_ref_extra_bytes ( 6 , true ) , 1 ) ;
312- assert_eq ! ( value_to_ref_extra_bytes ( 7 , true ) , 1 ) ;
313- assert_eq ! ( value_to_ref_extra_bytes ( 8 , true ) , 1 ) ;
314- assert_eq ! ( value_to_ref_extra_bytes ( 256 , true ) , 2 ) ;
315- assert_eq ! ( value_to_ref_extra_bytes ( 65536 , true ) , 3 ) ;
273+ assert_eq ! ( value_push_size ( 0 , true ) , 0 ) ;
274+ assert_eq ! ( value_push_size ( 0 , false ) , 1 ) ;
275+
276+ assert_eq ! ( value_push_size ( 1 , false ) , 1 ) ;
277+ assert_eq ! ( value_push_size ( 2 , false ) , 1 ) ;
278+ assert_eq ! ( value_push_size ( 3 , false ) , 1 ) ;
279+ assert_eq ! ( value_push_size ( 4 , false ) , 1 ) ;
280+ assert_eq ! ( value_push_size ( 5 , false ) , 1 ) ;
281+ assert_eq ! ( value_push_size ( 6 , false ) , 1 ) ;
282+ assert_eq ! ( value_push_size ( 7 , false ) , 1 ) ;
283+ assert_eq ! ( value_push_size ( 8 , false ) , 1 ) ;
284+ assert_eq ! ( value_push_size ( 256 , false ) , 2 ) ;
285+ assert_eq ! ( value_push_size ( 65535 , false ) , 2 ) ;
286+ assert_eq ! ( value_push_size ( 65536 , false ) , 3 ) ;
287+
288+ assert_eq ! ( value_push_size ( 1 , true ) , 1 ) ;
289+ assert_eq ! ( value_push_size ( 2 , true ) , 1 ) ;
290+ assert_eq ! ( value_push_size ( 3 , true ) , 1 ) ;
291+ assert_eq ! ( value_push_size ( 4 , true ) , 1 ) ;
292+ assert_eq ! ( value_push_size ( 5 , true ) , 1 ) ;
293+ assert_eq ! ( value_push_size ( 6 , true ) , 1 ) ;
294+ assert_eq ! ( value_push_size ( 7 , true ) , 1 ) ;
295+ assert_eq ! ( value_push_size ( 8 , true ) , 1 ) ;
296+ assert_eq ! ( value_push_size ( 256 , true ) , 2 ) ;
297+ assert_eq ! ( value_push_size ( 65536 , true ) , 3 ) ;
316298 }
317299}
0 commit comments