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

Commit

Permalink
Merge pull request #3841 from dkorpel/remove-old-mctor-cycle
Browse files Browse the repository at this point in the history
Remove `--DRT-oncycle=deprecate` option
  • Loading branch information
dkorpel authored Jun 20, 2022
2 parents 8f12ffe + 1bf4c7c commit 20ee98a
Show file tree
Hide file tree
Showing 3 changed files with 10 additions and 199 deletions.
5 changes: 5 additions & 0 deletions changelog/drt-oncycle-deprecate.dd
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
`--DRT-oncycle=deprecate` is removed

The option was [introduced in 2.072.2](https://dlang.org/changelog/2.072.2.html#drt-cycle-deprecated) to help transition code that relied on the old faulty cycle checker for module constructors.
It now prints a warning and does the same as the default, `--DRT-oncycle=abort`.
See also: $(DDSUBLINK spec/module, order_of_static_ctor, Order of Static Construction) in the specification.
200 changes: 3 additions & 197 deletions src/rt/minfo.d
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,6 @@ struct ModuleGroup

enum OnCycle
{
deprecate,
abort,
print,
ignore
Expand All @@ -180,7 +179,9 @@ struct ModuleGroup
switch (cycleHandling) with(OnCycle)
{
case "deprecate":
onCycle = deprecate;
import core.stdc.stdio : fprintf, stderr;
// Option deprecated in 2.101, remove in 2.111
fprintf(stderr, "`--DRT-oncycle=deprecate` is no longer supported, using `abort` instead\n");
break;
case "abort":
onCycle = abort;
Expand Down Expand Up @@ -356,14 +357,6 @@ struct ModuleGroup
// was already started, this is a cycle.
final switch (onCycle) with(OnCycle)
{
case deprecate:
// check with old algorithm
if (sortCtorsOld(edges))
{
// unwind to print deprecation message.
return false; // deprecated cycle error
}
goto case abort; // fall through
case abort:

string errmsg = "";
Expand Down Expand Up @@ -533,193 +526,6 @@ struct ModuleGroup
sortCtors(rt_configOption("oncycle"));
}

/******************************
* This is the old ctor sorting algorithm that does not find all cycles.
*
* It is here to allow the deprecated behavior from the original algorithm
* until people have fixed their code.
*
* If no cycles are found, the _ctors and _tlsctors are replaced with the
* ones generated by this algorithm to preserve the old incorrect ordering
* behavior.
*
* Params:
* edges = The module edges as found in the `importedModules` member of
* each ModuleInfo. Generated in sortCtors.
* Returns:
* true if no cycle is found, false if one was.
*/
bool sortCtorsOld(int[][] edges)
{
immutable len = edges.length;
assert(len == _modules.length);

static struct StackRec
{
@property int mod()
{
return _mods[_idx];
}

int[] _mods;
size_t _idx;
}

auto stack = (cast(StackRec*).calloc(len, StackRec.sizeof))[0 .. len];
// TODO: reuse GCBits by moving it to core.internal.container
immutable nwords = (len + 8 * size_t.sizeof - 1) / (8 * size_t.sizeof);
auto ctorstart = cast(size_t*).malloc(nwords * size_t.sizeof);
auto ctordone = cast(size_t*).malloc(nwords * size_t.sizeof);
int[] initialEdges = (cast(int *)malloc(int.sizeof * len))[0 .. len];
if (!stack.ptr || ctorstart is null || ctordone is null || !initialEdges.ptr)
assert(0);
scope (exit)
{
.free(stack.ptr);
.free(ctorstart);
.free(ctordone);
.free(initialEdges.ptr);
}

// initialize the initial edges
foreach (i, ref v; initialEdges)
v = cast(int)i;

bool sort(ref immutable(ModuleInfo)*[] ctors, uint mask)
{
import core.bitop;

ctors = (cast(immutable(ModuleInfo)**).malloc(len * size_t.sizeof))[0 .. len];
if (!ctors.ptr)
assert(0);

// clean flags
memset(ctorstart, 0, nwords * size_t.sizeof);
memset(ctordone, 0, nwords * size_t.sizeof);
size_t stackidx = 0;
size_t cidx;

int[] mods = initialEdges;

size_t idx;
while (true)
{
while (idx < mods.length)
{
auto m = mods[idx];

if (bt(ctordone, m))
{
// this module has already been processed, skip
++idx;
continue;
}
else if (bt(ctorstart, m))
{
/* Trace back to the begin of the cycle.
*/
bool ctorInCycle;
size_t start = stackidx;
while (start--)
{
auto sm = stack[start].mod;
if (sm == m)
break;
assert(sm >= 0);
if (bt(ctorstart, sm))
ctorInCycle = true;
}
assert(stack[start].mod == m);
if (ctorInCycle)
{
return false;
}
else
{
/* This is also a cycle, but the import chain does not constrain
* the order of initialization, either because the imported
* modules have no ctors or the ctors are standalone.
*/
++idx;
}
}
else
{
auto curmod = _modules[m];
if (curmod.flags & mask)
{
if (curmod.flags & MIstandalone || !edges[m].length)
{ // trivial ctor => sort in
ctors[cidx++] = curmod;
bts(ctordone, m);
}
else
{ // non-trivial ctor => defer
bts(ctorstart, m);
}
}
else // no ctor => mark as visited
{
bts(ctordone, m);
}

if (edges[m].length)
{
/* Internal runtime error, recursion exceeds number of modules.
*/
(stackidx < len) || assert(0);

// recurse
stack[stackidx++] = StackRec(mods, idx);
idx = 0;
mods = edges[m];
}
}
}

if (stackidx)
{ // pop old value from stack
--stackidx;
mods = stack[stackidx]._mods;
idx = stack[stackidx]._idx;
auto m = mods[idx++];
if (bt(ctorstart, m) && !bts(ctordone, m))
ctors[cidx++] = _modules[m];
}
else // done
break;
}
// store final number and shrink array
ctors = (cast(immutable(ModuleInfo)**).realloc(ctors.ptr, cidx * size_t.sizeof))[0 .. cidx];
return true;
}

/* Do two passes: ctor/dtor, tlsctor/tlsdtor
*/
immutable(ModuleInfo)*[] _ctors2;
immutable(ModuleInfo)*[] _tlsctors2;
auto result = sort(_ctors2, MIctor | MIdtor) && sort(_tlsctors2, MItlsctor | MItlsdtor);
if (result) // no cycle
{
// fall back to original ordering as part of the deprecation.
if (_ctors.ptr)
.free(_ctors.ptr);
_ctors = _ctors2;
if (_tlsctors.ptr)
.free(_tlsctors.ptr);
_tlsctors = _tlsctors2;
}
else
{
// free any allocated memory that will be forgotten
if (_ctors2.ptr)
.free(_ctors2.ptr);
if (_tlsctors2.ptr)
.free(_tlsctors2.ptr);
}
return result;
}

void runCtors()
{
// run independent ctors
Expand Down
4 changes: 2 additions & 2 deletions test/cycles/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ $(ROOT)/cycle_abort.done: RETCODE=1
$(ROOT)/cycle_abort.done: LINES=7
$(ROOT)/cycle_print.done: RETCODE=0
$(ROOT)/cycle_print.done: LINES=6
$(ROOT)/cycle_deprecate.done: RETCODE=0
$(ROOT)/cycle_deprecate.done: LINES=4
$(ROOT)/cycle_deprecate.done: RETCODE=1
$(ROOT)/cycle_deprecate.done: LINES=8
$(ROOT)/%.done: $(ROOT)/test_cycles
@echo Testing $*
$(QUIET)$(TIMELIMIT)$(ROOT)/test_cycles --DRT-oncycle=$(patsubst cycle_%.done,%, $(notdir $@)) > $@ 2>&1; test $$? -eq $(RETCODE)
Expand Down

0 comments on commit 20ee98a

Please sign in to comment.