Skip to content
This repository was archived by the owner on Oct 12, 2022. It is now read-only.
/ druntime Public archive
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 33 additions & 22 deletions src/rt/minfo.d
Original file line number Diff line number Diff line change
Expand Up @@ -167,13 +167,6 @@ struct ModuleGroup
import core.bitop : bts, btr, bt, BitRange;
import rt.util.container.hashtab;

// used to unwind stack for printing deprecation message.
static class DeprecatedCycleException : Exception
{
this() { super(""); }
}
scope deprecation = new DeprecatedCycleException();

enum OnCycle
{
deprecate,
Expand Down Expand Up @@ -318,7 +311,8 @@ struct ModuleGroup
// trivial modules to get at the non-trivial ones.
//
// If a cycle is detected, returns the index of the module that completes the cycle.
void findDeps(size_t idx, size_t* reachable)
// Returns: true for success, false for a deprecated cycle error
bool findDeps(size_t idx, size_t* reachable)
{
static struct stackFrame
{
Expand Down Expand Up @@ -367,7 +361,7 @@ struct ModuleGroup
if(sortCtorsOld(edges))
{
// unwind to print deprecation message.
throw deprecation;
return false; // deprecated cycle error
}
goto case abort; // fall through
case abort:
Expand Down Expand Up @@ -408,6 +402,7 @@ struct ModuleGroup
// next dependency
++sp.curDep;
}
return true; // success
}

// The list of constructors that will be returned by the sorting.
Expand All @@ -422,15 +417,17 @@ struct ModuleGroup
// Each call into this function is given a module that has static
// ctor/dtors that must be dealt with. It recurses only when it finds
// dependencies that also have static ctor/dtors.
void processMod(size_t curidx)
// Returns: true for success, false for a deprecated cycle error
bool processMod(size_t curidx)
{
immutable ModuleInfo* current = _modules[curidx];

// First, determine what modules are reachable.
auto reachable = cast(size_t*) malloc(flagbytes);
scope (exit)
.free(reachable);
findDeps(curidx, reachable);
if (!findDeps(curidx, reachable))
return false; // deprecated cycle error

// process the dependencies. First, we process all relevant ones
bts(ctorstart, curidx);
Expand All @@ -440,7 +437,10 @@ struct ModuleGroup
// note, don't check for cycles here, because the config could have been set to ignore cycles.
// however, don't recurse if there is one, so still check for started ctor.
if (i != curidx && bt(relevant, i) && !bt(ctordone, i) && !bt(ctorstart, i))
processMod(i);
{
if (!processMod(i))
return false; // deprecated cycle error
}
}

// now mark this node, and all nodes reachable from this module as done.
Expand All @@ -457,10 +457,15 @@ struct ModuleGroup

// add this module to the construction order list
ctors[ctoridx++] = current;
return true;
}

immutable(ModuleInfo)*[] doSort(size_t relevantFlags)
// `cycle` is set to `true` if deprecated cycle error otherwise set `result`.
void doSort(size_t relevantFlags, ref bool cycle, ref immutable(ModuleInfo)*[] result)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm... what about returning bool, and then if statement below reads:

if (doSort(...) || doSort(...))

In any case, the new code is correct at least.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Returning both a bool and a ref with the same value strikes me as odd and a bit eyebrow raising. I'd need a better reason to use it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's just get this merged and move on.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what you mean, you just would return a bool. But not important right now.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, the ref parameter is no longer required if doSort just returns a bool.

{
if (cycle)
return;

clearFlags(relevant);
clearFlags(ctorstart);
clearFlags(ctordone);
Expand Down Expand Up @@ -488,29 +493,35 @@ struct ModuleGroup
foreach (idx; BitRange(relevant, len))
{
if (!bt(ctordone, idx))
processMod(idx);
{
if (!processMod(idx))
{
cycle = true;
return;
}
}
}

if (ctoridx == 0)
{
// no ctors in the list.
.free(ctors);
return null;
result = null;
return;
}

ctors = cast(immutable(ModuleInfo)**).realloc(ctors, ctoridx * (void*).sizeof);
if (ctors is null)
assert(0);
return ctors[0 .. ctoridx];
result = ctors[0 .. ctoridx];
return;
}

// finally, do the sorting for both shared and tls ctors.
try
{
_ctors = doSort(MIctor | MIdtor);
_tlsctors = doSort(MItlsctor | MItlsdtor);
}
catch(DeprecatedCycleException)
bool cycle = false;
doSort(MIctor | MIdtor, cycle, _ctors);
doSort(MItlsctor | MItlsdtor, cycle, _tlsctors);
if (cycle)
{
// print a warning
import core.stdc.stdio : fprintf, stderr;
Expand Down