@@ -106,11 +106,11 @@ static bool TopoSort(DumpableObject **objs,
106
106
static void addHeapElement (int val ,int * heap ,int heapLength );
107
107
static int removeHeapElement (int * heap ,int heapLength );
108
108
static void findDependencyLoops (DumpableObject * * objs ,int nObjs ,int totObjs );
109
- static bool findLoop (DumpableObject * obj ,
109
+ static int findLoop (DumpableObject * obj ,
110
110
DumpId startPoint ,
111
+ bool * processed ,
111
112
DumpableObject * * workspace ,
112
- int depth ,
113
- int * newDepth );
113
+ int depth );
114
114
static void repairDependencyLoop (DumpableObject * * loop ,
115
115
int nLoop );
116
116
static void describeDumpableObject (DumpableObject * obj ,
@@ -500,58 +500,52 @@ static void
500
500
findDependencyLoops (DumpableObject * * objs ,int nObjs ,int totObjs )
501
501
{
502
502
/*
503
- * We use a workspace array, the initial part of which stores objects
504
- * already processed, and the rest of which is used as temporary space to
505
- * try to build a loop in.This is convenient because we do not care
506
- * about loops involving already-processed objects (see notes above); we
507
- * can easily reject such loops in findLoop() because of this
508
- * representation.After we identify and process a loop, we can add it to
509
- * the initial part of the workspace just by moving the boundary pointer.
510
- *
511
- * When we determine that an object is not part of any interesting loop,
512
- * we also add it to the initial part of the workspace. This is not
513
- * necessary for correctness, but saves later invocations of findLoop()
514
- * from uselessly chasing references to such an object.
515
- *
516
- * We make the workspace large enough to hold all objects in the original
517
- * universe. This is probably overkill, but it's provably enough space...
503
+ * We use two data structures here. One is a bool array processed[],
504
+ * which is indexed by dump ID and marks the objects already processed
505
+ * during this invocation of findDependencyLoops(). The other is a
506
+ * workspace[] array of DumpableObject pointers, in which we try to build
507
+ * lists of objects constituting loops. We make workspace[] large enough
508
+ * to hold all the objects, which is huge overkill in most cases but could
509
+ * theoretically be necessary if there is a single dependency chain
510
+ * linking all the objects.
518
511
*/
512
+ bool * processed ;
519
513
DumpableObject * * workspace ;
520
- int initiallen ;
521
514
bool fixedloop ;
522
515
int i ;
523
516
517
+ processed = (bool * )calloc (getMaxDumpId ()+ 1 ,sizeof (bool ));
524
518
workspace = (DumpableObject * * )malloc (totObjs * sizeof (DumpableObject * ));
525
- if (workspace == NULL )
519
+ if (processed == NULL || workspace == NULL )
526
520
exit_horribly (NULL ,modulename ,"out of memory\n" );
527
- initiallen = 0 ;
528
521
fixedloop = false;
529
522
530
523
for (i = 0 ;i < nObjs ;i ++ )
531
524
{
532
525
DumpableObject * obj = objs [i ];
533
- int newlen ;
526
+ int looplen ;
527
+ int j ;
534
528
535
- workspace [ initiallen ] = NULL ; /* see test below */
529
+ looplen = findLoop ( obj , obj -> dumpId , processed , workspace , 0 );
536
530
537
- if (findLoop ( obj , obj -> dumpId , workspace , initiallen , & newlen ) )
531
+ if (looplen > 0 )
538
532
{
539
- /* Found a loop of length newlen - initiallen */
540
- repairDependencyLoop (& workspace [initiallen ],newlen - initiallen );
541
- /* Add loop members to workspace */
542
- initiallen = newlen ;
533
+ /* Found a loop, repair it */
534
+ repairDependencyLoop (workspace ,looplen );
543
535
fixedloop = true;
536
+ /* Mark loop members as processed */
537
+ for (j = 0 ;j < looplen ;j ++ )
538
+ processed [workspace [j ]-> dumpId ]= true;
544
539
}
545
540
else
546
541
{
547
542
/*
548
- *Didn't find a loop, but add this object to workspace anyway,
549
- *unless it's already present. We piggyback on the test that
550
- * findLoop()already did: it won't have tentatively added obj to
551
- *workspace if it's already present .
543
+ *There's no loop starting at this object, but mark it processed
544
+ *anyway. This is not necessary for correctness, but saves later
545
+ *invocations of findLoop()from uselessly chasing references to
546
+ *such an object .
552
547
*/
553
- if (workspace [initiallen ]== obj )
554
- initiallen ++ ;
548
+ processed [obj -> dumpId ]= true;
555
549
}
556
550
}
557
551
@@ -560,45 +554,51 @@ findDependencyLoops(DumpableObject **objs, int nObjs, int totObjs)
560
554
exit_horribly (NULL ,modulename ,"could not identify dependency loop\n" );
561
555
562
556
free (workspace );
557
+ free (processed );
563
558
}
564
559
565
560
/*
566
561
* Recursively search for a circular dependency loop that doesn't include
567
- * anyexisting workspace members .
562
+ * anyalready-processed objects .
568
563
*
569
564
*obj: object we are examining now
570
565
*startPoint: dumpId of starting object for the hoped-for circular loop
571
- *workspace[]: work array for previously processed and current objects
566
+ *processed[]: flag array marking already-processed objects
567
+ *workspace[]: work array in which we are building list of loop members
572
568
*depth: number of valid entries in workspace[] at call
573
- *newDepth: if successful, set to new number of workspace[] entries
574
569
*
575
- * On success,*newDepth isset and workspace[]entries depth..*newDepth-1
576
- *are filled with pointers to the members of the loop.
570
+ * On success,the length of the loop isreturned, and workspace[]is filled
571
+ * with pointers to the members of the loop. On failure, we return 0 .
577
572
*
578
573
* Note: it is possible that the given starting object is a member of more
579
574
* than one cycle; if so, we will find an arbitrary one of the cycles.
580
575
*/
581
- static bool
576
+ static int
582
577
findLoop (DumpableObject * obj ,
583
578
DumpId startPoint ,
579
+ bool * processed ,
584
580
DumpableObject * * workspace ,
585
- int depth ,
586
- int * newDepth )
581
+ int depth )
587
582
{
588
583
int i ;
589
584
590
585
/*
591
- * Reject if obj is already present in workspace. This test serves three
592
- * purposes: it prevents us from finding loops that overlap
593
- * previously-processed loops, it prevents us from going into infinite
594
- * recursion if we are given a startPoint object that links to a cycle
595
- * it's not a member of, and it guarantees that we can't overflow the
596
- * allocated size of workspace[].
586
+ * Reject if obj is already processed. This test prevents us from finding
587
+ * loops that overlap previously-processed loops.
588
+ */
589
+ if (processed [obj -> dumpId ])
590
+ return 0 ;
591
+
592
+ /*
593
+ * Reject if obj is already present in workspace. This test prevents us
594
+ * from going into infinite recursion if we are given a startPoint object
595
+ * that links to a cycle it's not a member of, and it guarantees that we
596
+ * can't overflow the allocated size of workspace[].
597
597
*/
598
598
for (i = 0 ;i < depth ;i ++ )
599
599
{
600
600
if (workspace [i ]== obj )
601
- return false ;
601
+ return 0 ;
602
602
}
603
603
604
604
/*
@@ -612,10 +612,7 @@ findLoop(DumpableObject *obj,
612
612
for (i = 0 ;i < obj -> nDeps ;i ++ )
613
613
{
614
614
if (obj -> dependencies [i ]== startPoint )
615
- {
616
- * newDepth = depth ;
617
- return true;
618
- }
615
+ return depth ;
619
616
}
620
617
621
618
/*
@@ -624,18 +621,20 @@ findLoop(DumpableObject *obj,
624
621
for (i = 0 ;i < obj -> nDeps ;i ++ )
625
622
{
626
623
DumpableObject * nextobj = findObjectByDumpId (obj -> dependencies [i ]);
624
+ int newDepth ;
627
625
628
626
if (!nextobj )
629
627
continue ;/* ignore dependencies on undumped objects */
630
- if (findLoop (nextobj ,
631
- startPoint ,
632
- workspace ,
633
- depth ,
634
- newDepth ))
635
- return true;
628
+ newDepth = findLoop (nextobj ,
629
+ startPoint ,
630
+ processed ,
631
+ workspace ,
632
+ depth );
633
+ if (newDepth > 0 )
634
+ return newDepth ;
636
635
}
637
636
638
- return false ;
637
+ return 0 ;
639
638
}
640
639
641
640
/*