@@ -286,12 +286,95 @@ impl Memory {
286286 }
287287 Ok ( addr. into ( ) )
288288 }
289+ #[ cfg( not( feature = "extensive_hints" ) ) ]
290+ fn flatten_relocation_rules ( & mut self ) -> Result < ( ) , MemoryError > {
291+ let keys: Vec < usize > = self . relocation_rules . keys ( ) . copied ( ) . collect ( ) ;
292+ let max_hops = self . relocation_rules . len ( ) . saturating_add ( 1 ) ;
293+ for key in keys {
294+ let mut dst = * self
295+ . relocation_rules
296+ . get ( & key)
297+ . expect ( "key taken from keys vec must exist" ) ;
298+
299+ let mut hops = 0usize ;
300+ while dst. segment_index < 0 {
301+ let next_key = ( -( dst. segment_index + 1 ) ) as usize ;
302+ let next = * self . relocation_rules . get ( & next_key) . ok_or_else ( || {
303+ MemoryError :: UnallocatedSegment ( Box :: new ( ( next_key, self . temp_data . len ( ) ) ) )
304+ } ) ?;
305+ dst = ( next + dst. offset ) . map_err ( MemoryError :: Math ) ?;
306+ hops += 1 ;
307+ if hops > max_hops {
308+ return Err ( MemoryError :: Relocation ) ; // cycle guard
309+ }
310+ }
311+ self . relocation_rules . insert ( key, dst) ;
312+ }
313+ Ok ( ( ) )
314+ }
315+
316+ #[ cfg( feature = "extensive_hints" ) ]
317+ fn flatten_relocation_rules ( & mut self ) -> Result < ( ) , MemoryError > {
318+ let keys: Vec < usize > = self . relocation_rules . keys ( ) . copied ( ) . collect ( ) ;
319+ let max_hops = self . relocation_rules . len ( ) . saturating_add ( 1 ) ;
320+ for key in keys {
321+ let mut dst = self
322+ . relocation_rules
323+ . get ( & key)
324+ . expect ( "key taken from keys vec must exist" )
325+ . clone ( ) ;
326+
327+ let mut hops = 0usize ;
328+ loop {
329+ match dst {
330+ MaybeRelocatable :: RelocatableValue ( r) if r. segment_index < 0 => {
331+ let next_key = ( -( r. segment_index + 1 ) ) as usize ;
332+ let next = self
333+ . relocation_rules
334+ . get ( & next_key)
335+ . ok_or_else ( || {
336+ MemoryError :: UnallocatedSegment ( Box :: new ( (
337+ next_key,
338+ self . temp_data . len ( ) ,
339+ ) ) )
340+ } ) ?
341+ . clone ( ) ;
342+
343+ match next {
344+ MaybeRelocatable :: RelocatableValue ( nr) => {
345+ dst = MaybeRelocatable :: RelocatableValue (
346+ ( nr + r. offset ) . map_err ( MemoryError :: Math ) ?,
347+ ) ;
348+ }
349+ MaybeRelocatable :: Int ( i) => {
350+ if r. offset != 0 {
351+ return Err ( MemoryError :: NonZeroOffset ( r. offset ) ) ;
352+ }
353+ dst = MaybeRelocatable :: Int ( i) ;
354+ }
355+ }
356+ }
357+ _ => break ,
358+ }
359+ hops += 1 ;
360+ if hops > max_hops {
361+ return Err ( MemoryError :: Relocation ) ;
362+ }
363+ }
364+ self . relocation_rules . insert ( key, dst) ;
365+ }
366+ Ok ( ( ) )
367+ }
289368
290369 /// Relocates the memory according to the relocation rules and clears `self.relocaction_rules`.
291370 pub fn relocate_memory ( & mut self ) -> Result < ( ) , MemoryError > {
292371 if self . relocation_rules . is_empty ( ) || self . temp_data . is_empty ( ) {
293372 return Ok ( ( ) ) ;
294373 }
374+
375+ // flatten chains (temp->temp->...->real).
376+ self . flatten_relocation_rules ( ) ?;
377+
295378 // Relocate temporary addresses in memory
296379 for segment in self . data . iter_mut ( ) . chain ( self . temp_data . iter_mut ( ) ) {
297380 for cell in segment. iter_mut ( ) {
@@ -345,6 +428,7 @@ impl Memory {
345428 self . relocation_rules . clear ( ) ;
346429 Ok ( ( ) )
347430 }
431+
348432 /// Add a new relocation rule.
349433 ///
350434 /// When using feature "extensive_hints" the destination is allowed to be an Integer (via
0 commit comments