Skip to content
This repository was archived by the owner on Oct 12, 2022. It is now read-only.

Commit 3de899d

Browse files
committed
Change pruning of non-relevant nodes to be at deepest level, actually
simplifies a lot. Instead of reusing reachable and allocating deps, just allocate new reachable array at each recursion.
1 parent 8752d18 commit 3de899d

File tree

1 file changed

+72
-84
lines changed

1 file changed

+72
-84
lines changed

src/rt/minfo.d

Lines changed: 72 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)