@@ -107,7 +107,6 @@ struct ModuleGroup
107107 auto ctorstart = cast (size_t * )alloca(flagbytes);// ctor/dtor seen
108108 auto ctordone = cast (size_t * )alloca(flagbytes);// ctor/dtor processed
109109 auto relevant = cast (size_t * )alloca(flagbytes);// has ctors/dtors
110- auto reachable = cast (size_t * )alloca(flagbytes);// used for reachability check
111110
112111 void clearFlags (size_t * flags)
113112 {
@@ -231,9 +230,10 @@ distloop:
231230 // set up all the arrays. Use the GC, we are going to exit anyway.
232231 distance.length = len;
233232 edges.length = len;
233+ auto reachable = (new size_t [](nwords)).ptr;
234234 foreach (i, m; _modules)
235235 {
236- // use reachable, because an import can appear more than once.
236+ // use bit array to prevent duplicates
237237 // https://issues.dlang.org/show_bug.cgi?id=16208
238238 clearFlags(reachable);
239239 foreach (e; m.importedModules)
@@ -256,7 +256,9 @@ distloop:
256256 // find all the non-trivial dependencies (that is, dependencies that have a
257257 // ctor or dtor) of a given module. Doing this, we can 'skip over' the
258258 // trivial modules to get at the non-trivial ones.
259- size_t _findDependencies (int idx)
259+ //
260+ // If a cycle is detected, returns the index of the module that completes the cycle.
261+ int findDeps (int idx, size_t * reachable)
260262 {
261263 static struct stackFrame
262264 {
@@ -270,7 +272,10 @@ distloop:
270272 auto sp = stack;
271273 sp.curMod = idx;
272274 sp.curDep = 0 ;
273- size_t result = 0 ;
275+
276+ // initialize reachable by flagging source module
277+ clearFlags(reachable);
278+ bts(reachable, idx);
274279
275280 for (;;)
276281 {
@@ -282,40 +287,44 @@ distloop:
282287 // finished the algorithm
283288 break ;
284289 -- sp;
285- ++ sp.curDep;
286- continue ;
287290 }
288- auto midx = findModule(m.importedModules[sp.curDep]);
289- // if midx is -1, then this isn't part of this DSO.
290- if (midx != - 1 && ! bts(reachable, midx))
291+ else
291292 {
292- if (bt(relevant, midx))
293+ auto midx = findModule(m.importedModules[sp.curDep]);
294+ // if midx is -1, then this isn't part of this DSO.
295+ if (midx != - 1 && ! bts(reachable, midx))
293296 {
294- // non-trivial, stop here
295- result += 1 ;
296- }
297- else if (! bt(ctordone , midx))
298- {
299- // non-relevant, and hasn't been exhaustively processed, recurse .
300- if ( ! bt(ctorstart, midx))
301- ++ result;
302- // recurse
303- if (++ sp >= stacktop )
297+ if (bt(relevant, midx))
298+ {
299+ // need to process this node, don't recurse.
300+ if (bt(ctorstart , midx))
301+ {
302+ // was already started, this is a cycle .
303+ return midx;
304+ }
305+ }
306+ else if (! bt(ctordone, midx) )
304307 {
305- // stack overflow, this shouldn't happen.
306- import core.internal.abort : abort;
307- abort(" stack overflow on dependency search" );
308+ // non-relevant, and hasn't been exhaustively processed, recurse.
309+ if (++ sp >= stacktop)
310+ {
311+ // stack overflow, this shouldn't happen.
312+ import core.internal.abort : abort;
313+ abort(" stack overflow on dependency search" );
314+ }
315+ sp.curMod = midx;
316+ sp.curDep = 0 ;
317+ continue ;
308318 }
309- sp.curMod = midx;
310- sp.curDep = 0 ;
311- continue ;
312319 }
313320 }
314321
315322 // next dependency
316323 ++ sp.curDep;
317324 }
318- return result;
325+
326+ // no cycles seen
327+ return - 1 ;
319328 }
320329
321330 // The list of constructors that will be returned by the sorting.
@@ -331,82 +340,61 @@ distloop:
331340 // Each call into this function is given a module that has static
332341 // ctor/dtors that must be dealt with. It recurses only when it finds
333342 // dependencies that also have static ctor/dtors.
334- void _checkModCtors2 (int curidx)
343+ void processMod (int curidx)
335344 {
336345 assert (curidx != - 1 );
337346 immutable ModuleInfo * current = _modules[curidx];
338347
339- // First, determine what non-trivial elements are reachable.
340- clearFlags(reachable);
341- bts(reachable, curidx);
342- auto nmodules = _findDependencies(curidx);
343-
344- // allocate the dependencies on the stack, because reachable will
345- // be reused as we recurse.
346- auto p = cast (int * )alloca(nmodules * int .sizeof);
347- auto dependencies = p[0 .. nmodules];
348- uint depidx = 0 ;
349- // fill in the dependencies
350- foreach (int i; 0 .. len)
348+ // First, determine what modules are reachable.
349+ auto reachable = cast (size_t * )alloca(flagbytes);
350+ auto cycleIdx = findDeps(curidx, reachable);
351+ if (cycleIdx != - 1 )
351352 {
352- if (i != curidx && bt(reachable, i))
353+ auto cycleMod = _modules[cycleIdx];
354+ // found a cycle
355+ println(" Cyclic dependency between module " , cycleMod.name, " and " , current.name);
356+ genPath(cycleIdx, curidx);
357+
358+ foreach (midx; cyclePath[0 .. $- 1 ])
353359 {
354- if (bt(relevant, i))
355- {
356- if (bt(ctorstart, i))
357- {
358- // found a cycle
359- println(" Cyclic dependency between module " , _modules[i].name, " and " , current.name);
360- genPath(i, curidx);
361-
362- foreach (midx; cyclePath[0 .. $- 1 ])
363- {
364- println(_modules[midx].name, bt (relevant, midx) ? " * ->" : " ->" );
365- }
366- println(_modules[i].name, " *" );
367- throw new Error(errmsg);
368- }
369- dependencies[depidx++ ] = i;
370- }
371- else if (! bts(ctorstart, i))
372- {
373- // this is a non-relevant module, but it has never been
374- // imported by any other relevant module in our search.
375- // Once we have processed the current relevant module,
376- // we can mark this non-relevant module as done, so it's
377- // not ever looked at again.
378- dependencies[depidx++ ] = i;
379- }
360+ println(_modules[midx].name, bt (relevant, midx) ? " * ->" : " ->" );
380361 }
362+ println(cycleMod.name, " *" );
363+ throw new Error(errmsg);
381364 }
382- assert (depidx == nmodules);
383365
384- // process all the dependencies
366+ // process the dependencies. First, we process all relevant ones
385367 bts(ctorstart, curidx);
386- foreach (m; dependencies )
368+ foreach (int i; 0 .. len )
387369 {
388- if (bt(relevant, m) && ! bt(ctordone, m))
389- _checkModCtors2(m);
370+ if (i != curidx && bt(reachable, i) &&
371+ bt(relevant, i) && ! bt(ctordone, i))
372+ {
373+ assert (! bt(ctorstart, i)); // sanity check, this should have been flagged a cycle earlier
374+ processMod(i);
375+ }
390376 }
377+
378+ // now mark this node, and all nodes reachable from this module as done.
391379 bts(ctordone, curidx);
392380 btr(ctorstart, curidx);
393-
394- // mark all non-relevant dependencies as done
395- foreach (m; dependencies)
381+ foreach (int i; 0 .. len)
396382 {
397- if (! bt(relevant, m ))
383+ if (bt(reachable, i ))
398384 {
399- bts(ctordone, m);
400- // no need to clear ctorstart, as we don't care about
401- // irrelevant modules for detecting cycles.
385+ // Since relevant dependencies are already marked as done
386+ // from recursion above, no reason to check for relevance,
387+ // that is a wasted op.
388+ bts(ctordone, i);
402389 }
403390 }
391+
404392 // add this module to the construction order list
405393 ctors[ctoridx++ ] = current;
406394 }
407395
408396 immutable (ModuleInfo )* []
409- _checkModCtors3 (int function (immutable ModuleInfo * ) getf)
397+ doSort (int function (immutable ModuleInfo * ) getf)
410398 {
411399 clearFlags(relevant);
412400 clearFlags(ctorstart);
@@ -434,22 +422,22 @@ distloop:
434422 }
435423 }
436424
437- // now run the search in the relevant ones
425+ // now run the algorithm in the relevant ones
438426 foreach (int idx, m; _modules)
439427 {
440428 if (bt(relevant, idx))
441429 {
442430 if (! bt(ctordone, idx))
443- _checkModCtors2 (idx);
431+ processMod (idx);
444432 }
445433 }
446434
447435 return ctors[0 .. ctoridx];
448436 }
449437
450438 // finally, do the sorting for both shared and tls ctors.
451- _ctors = _checkModCtors3 ((immutable ModuleInfo * m) => (m.flags & MIstandalone) | ((m.dtor || m.ctor)? MIctor : 0 ));
452- _tlsctors = _checkModCtors3 ((immutable ModuleInfo * m) => (m.flags & MIstandalone) | ((m.tlsdtor || m.tlsctor)? MIctor : 0 ));
439+ _ctors = doSort ((immutable ModuleInfo * m) => (m.flags & MIstandalone) | ((m.dtor || m.ctor)? MIctor : 0 ));
440+ _tlsctors = doSort ((immutable ModuleInfo * m) => (m.flags & MIstandalone) | ((m.tlsdtor || m.tlsctor)? MIctor : 0 ));
453441 }
454442
455443 void runCtors ()
0 commit comments