Home | History | Annotate | Line # | Download | only in rt
minfo.d revision 1.1
      1 /**
      2  * Written in the D programming language.
      3  * Module initialization routines.
      4  *
      5  * Copyright: Copyright Digital Mars 2000 - 2013.
      6  * License: Distributed under the
      7  *      $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0).
      8  *    (See accompanying file LICENSE)
      9  * Authors:   Walter Bright, Sean Kelly
     10  * Source: $(DRUNTIMESRC src/rt/_minfo.d)
     11  */
     12 
     13 module rt.minfo;
     14 
     15 import core.stdc.stdlib;  // alloca
     16 import core.stdc.string;  // memcpy
     17 import rt.sections;
     18 
     19 enum
     20 {
     21     MIctorstart  = 0x1,   // we've started constructing it
     22     MIctordone   = 0x2,   // finished construction
     23     MIstandalone = 0x4,   // module ctor does not depend on other module
     24                         // ctors being done first
     25     MItlsctor    = 8,
     26     MItlsdtor    = 0x10,
     27     MIctor       = 0x20,
     28     MIdtor       = 0x40,
     29     MIxgetMembers = 0x80,
     30     MIictor      = 0x100,
     31     MIunitTest   = 0x200,
     32     MIimportedModules = 0x400,
     33     MIlocalClasses = 0x800,
     34     MIname       = 0x1000,
     35 }
     36 
     37 /*****
     38  * A ModuleGroup is an unordered collection of modules.
     39  * There is exactly one for:
     40  *  1. all statically linked in D modules, either directely or as shared libraries
     41  *  2. each call to rt_loadLibrary()
     42  */
     43 
     44 struct ModuleGroup
     45 {
     46     this(immutable(ModuleInfo*)[] modules) nothrow @nogc
     47     {
     48         _modules = modules;
     49     }
     50 
     51     @property immutable(ModuleInfo*)[] modules() const nothrow @nogc
     52     {
     53         return _modules;
     54     }
     55 
     56     // this function initializes the bookeeping necessary to create the
     57     // cycle path, and then creates it. It is a precondition that src and
     58     // target modules are involved in a cycle.
     59     //
     60     // The return value is malloc'd using C, so it must be freed after use.
     61     private size_t[] genCyclePath(size_t srcidx, size_t targetidx, int[][] edges)
     62     {
     63         import core.bitop : bt, btc, bts;
     64 
     65         // set up all the arrays.
     66         size_t[] cyclePath = (cast(size_t*)malloc(size_t.sizeof * _modules.length * 2))[0 .. _modules.length * 2];
     67         size_t totalMods;
     68         int[] distance = (cast(int*)malloc(int.sizeof * _modules.length))[0 .. _modules.length];
     69         scope(exit)
     70             .free(distance.ptr);
     71 
     72         // determine the shortest path between two modules. Uses dijkstra
     73         // without a priority queue. (we can be a bit slow here, in order to
     74         // get a better printout).
     75         void shortest(size_t start, size_t target)
     76         {
     77             // initial setup
     78             distance[] = int.max;
     79             int curdist = 0;
     80             distance[start] = 0;
     81             while (true)
     82             {
     83                 bool done = true;
     84                 foreach (i, x; distance)
     85                 {
     86                     if (x == curdist)
     87                     {
     88                         if (i == target)
     89                         {
     90                             done = true;
     91                             break;
     92                         }
     93                         foreach (n; edges[i])
     94                         {
     95                             if (distance[n] == int.max)
     96                             {
     97                                 distance[n] = curdist + 1;
     98                                 done = false;
     99                             }
    100                         }
    101                     }
    102                 }
    103                 if (done)
    104                     break;
    105                 ++curdist;
    106             }
    107             // it should be impossible to not get to target, this is just a
    108             // sanity check. Not an assert, because druntime is compiled in
    109             // release mode.
    110             if (distance[target] != curdist)
    111             {
    112                 throw new Error("internal error printing module cycle");
    113             }
    114 
    115             // determine the path. This is tricky, because we have to
    116             // follow the edges in reverse to get back to the original. We
    117             // don't have a reverse mapping, so it takes a bit of looping.
    118             totalMods += curdist;
    119             auto subpath = cyclePath[totalMods - curdist .. totalMods];
    120             while (true)
    121             {
    122                 --curdist;
    123                 subpath[curdist] = target;
    124                 if (curdist == 0)
    125                     break;
    126             distloop:
    127                 // search for next (previous) module in cycle.
    128                 foreach (int m, d; distance)
    129                 {
    130                     if (d == curdist)
    131                     {
    132                         // determine if m can reach target
    133                         foreach (e; edges[m])
    134                         {
    135                             if (e == target)
    136                             {
    137                                 // recurse
    138                                 target = m;
    139                                 break distloop;
    140                             }
    141                         }
    142                     }
    143                 }
    144             }
    145         }
    146 
    147         // first get to the target
    148         shortest(srcidx, targetidx);
    149         // now get back.
    150         shortest(targetidx, srcidx);
    151 
    152         return cyclePath[0 .. totalMods];
    153     }
    154 
    155     /******************************
    156      * Allocate and fill in _ctors[] and _tlsctors[].
    157      * Modules are inserted into the arrays in the order in which the constructors
    158      * need to be run.
    159      *
    160      * Params:
    161      *  cycleHandling - string indicating option for cycle handling
    162      * Throws:
    163      *  Exception if it fails.
    164      */
    165     void sortCtors(string cycleHandling)
    166     {
    167         import core.bitop : bts, btr, bt, BitRange;
    168         import rt.util.container.hashtab;
    169 
    170         enum OnCycle
    171         {
    172             deprecate,
    173             abort,
    174             print,
    175             ignore
    176         }
    177 
    178         auto onCycle = OnCycle.abort;
    179 
    180         switch (cycleHandling) with(OnCycle)
    181         {
    182         case "deprecate":
    183             onCycle = deprecate;
    184             break;
    185         case "abort":
    186             onCycle = abort;
    187             break;
    188         case "print":
    189             onCycle = print;
    190             break;
    191         case "ignore":
    192             onCycle = ignore;
    193             break;
    194         case "":
    195             // no option passed
    196             break;
    197         default:
    198             // invalid cycle handling option.
    199             throw new Error("DRT invalid cycle handling option: " ~ cycleHandling);
    200         }
    201 
    202         debug (printModuleDependencies)
    203         {
    204             import core.stdc.stdio : printf;
    205 
    206             foreach (_m; _modules)
    207             {
    208                 printf("%s%s%s:", _m.name.ptr, (_m.flags & MIstandalone)
    209                         ? "+".ptr : "".ptr, (_m.flags & (MIctor | MIdtor)) ? "*".ptr : "".ptr);
    210                 foreach (_i; _m.importedModules)
    211                     printf(" %s", _i.name.ptr);
    212                 printf("\n");
    213             }
    214         }
    215 
    216         immutable uint len = cast(uint) _modules.length;
    217         if (!len)
    218             return; // nothing to do.
    219 
    220         // allocate some stack arrays that will be used throughout the process.
    221         immutable nwords = (len + 8 * size_t.sizeof - 1) / (8 * size_t.sizeof);
    222         immutable flagbytes = nwords * size_t.sizeof;
    223         auto ctorstart = cast(size_t*) malloc(flagbytes); // ctor/dtor seen
    224         auto ctordone = cast(size_t*) malloc(flagbytes); // ctor/dtor processed
    225         auto relevant = cast(size_t*) malloc(flagbytes); // has ctors/dtors
    226         scope (exit)
    227         {
    228             .free(ctorstart);
    229             .free(ctordone);
    230             .free(relevant);
    231         }
    232 
    233         void clearFlags(size_t* flags)
    234         {
    235             memset(flags, 0, flagbytes);
    236         }
    237 
    238 
    239         // build the edges between each module. We may need this for printing,
    240         // and also allows avoiding keeping a hash around for module lookups.
    241         int[][] edges = (cast(int[]*)malloc((int[]).sizeof * _modules.length))[0 .. _modules.length];
    242         {
    243             HashTab!(immutable(ModuleInfo)*, int) modIndexes;
    244             foreach (i, m; _modules)
    245                 modIndexes[m] = cast(int) i;
    246 
    247             auto reachable = cast(size_t*) malloc(flagbytes);
    248             scope(exit)
    249                 .free(reachable);
    250 
    251             foreach (i, m; _modules)
    252             {
    253                 // use bit array to prevent duplicates
    254                 // https://issues.dlang.org/show_bug.cgi?id=16208
    255                 clearFlags(reachable);
    256                 // preallocate enough space to store all the indexes
    257                 int *edge = cast(int*)malloc(int.sizeof * _modules.length);
    258                 size_t nEdges = 0;
    259                 foreach (imp; m.importedModules)
    260                 {
    261                     if (imp is m) // self-import
    262                         continue;
    263                     if (auto impidx = imp in modIndexes)
    264                     {
    265                         if (!bts(reachable, *impidx))
    266                             edge[nEdges++] = *impidx;
    267                     }
    268                 }
    269                 // trim space to what is needed.
    270                 edges[i] = (cast(int*)realloc(edge, int.sizeof * nEdges))[0 .. nEdges];
    271             }
    272         }
    273 
    274         // free all the edges after we are done
    275         scope(exit)
    276         {
    277             foreach (e; edges)
    278                 if (e.ptr)
    279                     .free(e.ptr);
    280             .free(edges.ptr);
    281         }
    282 
    283         void buildCycleMessage(size_t sourceIdx, size_t cycleIdx, scope void delegate(string) sink)
    284         {
    285             version (Windows)
    286                 enum EOL = "\r\n";
    287             else
    288                 enum EOL = "\n";
    289 
    290             sink("Cyclic dependency between module ");
    291             sink(_modules[sourceIdx].name);
    292             sink(" and ");
    293             sink(_modules[cycleIdx].name);
    294             sink(EOL);
    295             auto cyclePath = genCyclePath(sourceIdx, cycleIdx, edges);
    296             scope(exit) .free(cyclePath.ptr);
    297 
    298             sink(_modules[sourceIdx].name);
    299             sink("* ->" ~ EOL);
    300             foreach (x; cyclePath[0 .. $ - 1])
    301             {
    302                 sink(_modules[x].name);
    303                 sink(bt(relevant, x) ? "* ->" ~ EOL : " ->" ~ EOL);
    304             }
    305             sink(_modules[sourceIdx].name);
    306             sink("*" ~ EOL);
    307         }
    308 
    309         // find all the non-trivial dependencies (that is, dependencies that have a
    310         // ctor or dtor) of a given module.  Doing this, we can 'skip over' the
    311         // trivial modules to get at the non-trivial ones.
    312         //
    313         // If a cycle is detected, returns the index of the module that completes the cycle.
    314         // Returns: true for success, false for a deprecated cycle error
    315         bool findDeps(size_t idx, size_t* reachable)
    316         {
    317             static struct stackFrame
    318             {
    319                 size_t curMod;
    320                 size_t curDep;
    321             }
    322 
    323             // initialize "stack"
    324             auto stack = cast(stackFrame*) malloc(stackFrame.sizeof * len);
    325             scope (exit)
    326                 .free(stack);
    327             auto stacktop = stack + len;
    328             auto sp = stack;
    329             sp.curMod = cast(int) idx;
    330             sp.curDep = 0;
    331 
    332             // initialize reachable by flagging source module
    333             clearFlags(reachable);
    334             bts(reachable, idx);
    335 
    336             for (;;)
    337             {
    338                 auto m = _modules[sp.curMod];
    339                 if (sp.curDep >= edges[sp.curMod].length)
    340                 {
    341                     // return
    342                     if (sp == stack) // finished the algorithm
    343                         break;
    344                     --sp;
    345                 }
    346                 else
    347                 {
    348                     auto midx = edges[sp.curMod][sp.curDep];
    349                     if (!bts(reachable, midx))
    350                     {
    351                         if (bt(relevant, midx))
    352                         {
    353                             // need to process this node, don't recurse.
    354                             if (bt(ctorstart, midx))
    355                             {
    356                                 // was already started, this is a cycle.
    357                                 final switch (onCycle) with(OnCycle)
    358                                 {
    359                                 case deprecate:
    360                                     // check with old algorithm
    361                                     if (sortCtorsOld(edges))
    362                                     {
    363                                         // unwind to print deprecation message.
    364                                         return false;   // deprecated cycle error
    365                                     }
    366                                     goto case abort; // fall through
    367                                 case abort:
    368 
    369                                     string errmsg = "";
    370                                     buildCycleMessage(idx, midx, (string x) {errmsg ~= x;});
    371                                     throw new Error(errmsg, __FILE__, __LINE__);
    372                                 case ignore:
    373                                     break;
    374                                 case print:
    375                                     // print the message
    376                                     buildCycleMessage(idx, midx, (string x) {
    377                                                       import core.stdc.stdio : fprintf, stderr;
    378                                                       fprintf(stderr, "%.*s", cast(int) x.length, x.ptr);
    379                                                       });
    380                                     // continue on as if this is correct.
    381                                     break;
    382                                 }
    383                             }
    384                         }
    385                         else if (!bt(ctordone, midx))
    386                         {
    387                             // non-relevant, and hasn't been exhaustively processed, recurse.
    388                             if (++sp >= stacktop)
    389                             {
    390                                 // stack overflow, this shouldn't happen.
    391                                 import core.internal.abort : abort;
    392 
    393                                 abort("stack overflow on dependency search");
    394                             }
    395                             sp.curMod = midx;
    396                             sp.curDep = 0;
    397                             continue;
    398                         }
    399                     }
    400                 }
    401 
    402                 // next dependency
    403                 ++sp.curDep;
    404             }
    405             return true; // success
    406         }
    407 
    408         // The list of constructors that will be returned by the sorting.
    409         immutable(ModuleInfo)** ctors;
    410         // current element being inserted into ctors list.
    411         size_t ctoridx = 0;
    412 
    413         // This function will determine the order of construction/destruction and
    414         // check for cycles. If a cycle is found, the cycle path is transformed
    415         // into a string and thrown as an error.
    416         //
    417         // Each call into this function is given a module that has static
    418         // ctor/dtors that must be dealt with. It recurses only when it finds
    419         // dependencies that also have static ctor/dtors.
    420         // Returns: true for success, false for a deprecated cycle error
    421         bool processMod(size_t curidx)
    422         {
    423             immutable ModuleInfo* current = _modules[curidx];
    424 
    425             // First, determine what modules are reachable.
    426             auto reachable = cast(size_t*) malloc(flagbytes);
    427             scope (exit)
    428                 .free(reachable);
    429             if (!findDeps(curidx, reachable))
    430                 return false;   // deprecated cycle error
    431 
    432             // process the dependencies. First, we process all relevant ones
    433             bts(ctorstart, curidx);
    434             auto brange = BitRange(reachable, len);
    435             foreach (i; brange)
    436             {
    437                 // note, don't check for cycles here, because the config could have been set to ignore cycles.
    438                 // however, don't recurse if there is one, so still check for started ctor.
    439                 if (i != curidx && bt(relevant, i) && !bt(ctordone, i) && !bt(ctorstart, i))
    440                 {
    441                     if (!processMod(i))
    442                         return false; // deprecated cycle error
    443                 }
    444             }
    445 
    446             // now mark this node, and all nodes reachable from this module as done.
    447             bts(ctordone, curidx);
    448             btr(ctorstart, curidx);
    449             foreach (i; brange)
    450             {
    451                 // Since relevant dependencies are already marked as done
    452                 // from recursion above (or are going to be handled up the call
    453                 // stack), no reason to check for relevance, that is a wasted
    454                 // op.
    455                 bts(ctordone, i);
    456             }
    457 
    458             // add this module to the construction order list
    459             ctors[ctoridx++] = current;
    460             return true;
    461         }
    462 
    463         // returns `false` if deprecated cycle error otherwise set `result`.
    464         bool doSort(size_t relevantFlags, ref immutable(ModuleInfo)*[] result)
    465         {
    466             clearFlags(relevant);
    467             clearFlags(ctorstart);
    468             clearFlags(ctordone);
    469 
    470             // pre-allocate enough space to hold all modules.
    471             ctors = (cast(immutable(ModuleInfo)**).malloc(len * (void*).sizeof));
    472             ctoridx = 0;
    473             foreach (int idx, m; _modules)
    474             {
    475                 if (m.flags & relevantFlags)
    476                 {
    477                     if (m.flags & MIstandalone)
    478                     {
    479                         // can run at any time. Just run it first.
    480                         ctors[ctoridx++] = m;
    481                     }
    482                     else
    483                     {
    484                         bts(relevant, idx);
    485                     }
    486                 }
    487             }
    488 
    489             // now run the algorithm in the relevant ones
    490             foreach (idx; BitRange(relevant, len))
    491             {
    492                 if (!bt(ctordone, idx))
    493                 {
    494                     if (!processMod(idx))
    495                         return false;
    496                 }
    497             }
    498 
    499             if (ctoridx == 0)
    500             {
    501                 // no ctors in the list.
    502                 .free(ctors);
    503             }
    504             else
    505             {
    506                 ctors = cast(immutable(ModuleInfo)**).realloc(ctors, ctoridx * (void*).sizeof);
    507                 if (ctors is null)
    508                     assert(0);
    509                 result = ctors[0 .. ctoridx];
    510             }
    511             return true;
    512         }
    513 
    514         // finally, do the sorting for both shared and tls ctors. If either returns false,
    515         // print the deprecation warning.
    516         if (!doSort(MIctor | MIdtor, _ctors) ||
    517             !doSort(MItlsctor | MItlsdtor, _tlsctors))
    518         {
    519             // print a warning
    520             import core.stdc.stdio : fprintf, stderr;
    521             fprintf(stderr, "Deprecation 16211 warning:\n"
    522                 ~ "A cycle has been detected in your program that was undetected prior to DMD\n"
    523                 ~ "2.072. This program will continue, but will not operate when using DMD 2.074\n"
    524                 ~ "to compile. Use runtime option --DRT-oncycle=print to see the cycle details.\n");
    525 
    526         }
    527     }
    528 
    529     /// ditto
    530     void sortCtors()
    531     {
    532         import rt.config : rt_configOption;
    533         sortCtors(rt_configOption("oncycle"));
    534     }
    535 
    536     /******************************
    537      * This is the old ctor sorting algorithm that does not find all cycles.
    538      *
    539      * It is here to allow the deprecated behavior from the original algorithm
    540      * until people have fixed their code.
    541      *
    542      * If no cycles are found, the _ctors and _tlsctors are replaced with the
    543      * ones generated by this algorithm to preserve the old incorrect ordering
    544      * behavior.
    545      *
    546      * Params:
    547      *   edges - The module edges as found in the `importedModules` member of
    548      *          each ModuleInfo. Generated in sortCtors.
    549      * Returns:
    550      *   true if no cycle is found, false if one was.
    551      */
    552     bool sortCtorsOld(int[][] edges)
    553     {
    554         immutable len = edges.length;
    555         assert(len == _modules.length);
    556 
    557         static struct StackRec
    558         {
    559             @property int mod()
    560             {
    561                 return _mods[_idx];
    562             }
    563 
    564             int[] _mods;
    565             size_t         _idx;
    566         }
    567 
    568         auto stack = (cast(StackRec*).calloc(len, StackRec.sizeof))[0 .. len];
    569         // TODO: reuse GCBits by moving it to rt.util.container or core.internal
    570         immutable nwords = (len + 8 * size_t.sizeof - 1) / (8 * size_t.sizeof);
    571         auto ctorstart = cast(size_t*).malloc(nwords * size_t.sizeof);
    572         auto ctordone = cast(size_t*).malloc(nwords * size_t.sizeof);
    573         int[] initialEdges = (cast(int *)malloc(int.sizeof * len))[0 .. len];
    574         if (!stack.ptr || ctorstart is null || ctordone is null || !initialEdges.ptr)
    575             assert(0);
    576         scope (exit)
    577         {
    578             .free(stack.ptr);
    579             .free(ctorstart);
    580             .free(ctordone);
    581             .free(initialEdges.ptr);
    582         }
    583 
    584         // initialize the initial edges
    585         foreach (int i, ref v; initialEdges)
    586             v = i;
    587 
    588         bool sort(ref immutable(ModuleInfo)*[] ctors, uint mask)
    589         {
    590             import core.bitop;
    591 
    592             ctors = (cast(immutable(ModuleInfo)**).malloc(len * size_t.sizeof))[0 .. len];
    593             if (!ctors.ptr)
    594                 assert(0);
    595 
    596             // clean flags
    597             memset(ctorstart, 0, nwords * size_t.sizeof);
    598             memset(ctordone, 0, nwords * size_t.sizeof);
    599             size_t stackidx = 0;
    600             size_t cidx;
    601 
    602             int[] mods = initialEdges;
    603 
    604             size_t idx;
    605             while (true)
    606             {
    607                 while (idx < mods.length)
    608                 {
    609                     auto m = mods[idx];
    610 
    611                     if (bt(ctordone, m))
    612                     {
    613                         // this module has already been processed, skip
    614                         ++idx;
    615                         continue;
    616                     }
    617                     else if (bt(ctorstart, m))
    618                     {
    619                         /* Trace back to the begin of the cycle.
    620                          */
    621                         bool ctorInCycle;
    622                         size_t start = stackidx;
    623                         while (start--)
    624                         {
    625                             auto sm = stack[start].mod;
    626                             if (sm == m)
    627                                 break;
    628                             assert(sm >= 0);
    629                             if (bt(ctorstart, sm))
    630                                 ctorInCycle = true;
    631                         }
    632                         assert(stack[start].mod == m);
    633                         if (ctorInCycle)
    634                         {
    635                             return false;
    636                         }
    637                         else
    638                         {
    639                             /* This is also a cycle, but the import chain does not constrain
    640                              * the order of initialization, either because the imported
    641                              * modules have no ctors or the ctors are standalone.
    642                              */
    643                             ++idx;
    644                         }
    645                     }
    646                     else
    647                     {
    648                         auto curmod = _modules[m];
    649                         if (curmod.flags & mask)
    650                         {
    651                             if (curmod.flags & MIstandalone || !edges[m].length)
    652                             {   // trivial ctor => sort in
    653                                 ctors[cidx++] = curmod;
    654                                 bts(ctordone, m);
    655                             }
    656                             else
    657                             {   // non-trivial ctor => defer
    658                                 bts(ctorstart, m);
    659                             }
    660                         }
    661                         else    // no ctor => mark as visited
    662                         {
    663                             bts(ctordone, m);
    664                         }
    665 
    666                         if (edges[m].length)
    667                         {
    668                             /* Internal runtime error, recursion exceeds number of modules.
    669                              */
    670                             (stackidx < len) || assert(0);
    671 
    672                             // recurse
    673                             stack[stackidx++] = StackRec(mods, idx);
    674                             idx  = 0;
    675                             mods = edges[m];
    676                         }
    677                     }
    678                 }
    679 
    680                 if (stackidx)
    681                 {   // pop old value from stack
    682                     --stackidx;
    683                     mods    = stack[stackidx]._mods;
    684                     idx     = stack[stackidx]._idx;
    685                     auto m  = mods[idx++];
    686                     if (bt(ctorstart, m) && !bts(ctordone, m))
    687                         ctors[cidx++] = _modules[m];
    688                 }
    689                 else // done
    690                     break;
    691             }
    692             // store final number and shrink array
    693             ctors = (cast(immutable(ModuleInfo)**).realloc(ctors.ptr, cidx * size_t.sizeof))[0 .. cidx];
    694             return true;
    695         }
    696 
    697         /* Do two passes: ctor/dtor, tlsctor/tlsdtor
    698          */
    699         immutable(ModuleInfo)*[] _ctors2;
    700         immutable(ModuleInfo)*[] _tlsctors2;
    701         auto result = sort(_ctors2, MIctor | MIdtor) && sort(_tlsctors2, MItlsctor | MItlsdtor);
    702         if (result) // no cycle
    703         {
    704             // fall back to original ordering as part of the deprecation.
    705             if (_ctors.ptr)
    706                 .free(_ctors.ptr);
    707             _ctors = _ctors2;
    708             if (_tlsctors.ptr)
    709                 .free(_tlsctors.ptr);
    710             _tlsctors = _tlsctors2;
    711         }
    712         else
    713         {
    714             // free any allocated memory that will be forgotten
    715             if (_ctors2.ptr)
    716                 .free(_ctors2.ptr);
    717             if (_tlsctors2.ptr)
    718                 .free(_tlsctors2.ptr);
    719         }
    720         return result;
    721     }
    722 
    723     void runCtors()
    724     {
    725         // run independent ctors
    726         runModuleFuncs!(m => m.ictor)(_modules);
    727         // sorted module ctors
    728         runModuleFuncs!(m => m.ctor)(_ctors);
    729     }
    730 
    731     void runTlsCtors()
    732     {
    733         runModuleFuncs!(m => m.tlsctor)(_tlsctors);
    734     }
    735 
    736     void runTlsDtors()
    737     {
    738         runModuleFuncsRev!(m => m.tlsdtor)(_tlsctors);
    739     }
    740 
    741     void runDtors()
    742     {
    743         runModuleFuncsRev!(m => m.dtor)(_ctors);
    744     }
    745 
    746     void free()
    747     {
    748         if (_ctors.ptr)
    749             .free(_ctors.ptr);
    750         _ctors = null;
    751         if (_tlsctors.ptr)
    752             .free(_tlsctors.ptr);
    753         _tlsctors = null;
    754         // _modules = null; // let the owner free it
    755     }
    756 
    757 private:
    758     immutable(ModuleInfo*)[]  _modules;
    759     immutable(ModuleInfo)*[]    _ctors;
    760     immutable(ModuleInfo)*[] _tlsctors;
    761 }
    762 
    763 
    764 /********************************************
    765  * Iterate over all module infos.
    766  */
    767 
    768 int moduleinfos_apply(scope int delegate(immutable(ModuleInfo*)) dg)
    769 {
    770     foreach (ref sg; SectionGroup)
    771     {
    772         foreach (m; sg.modules)
    773         {
    774             // TODO: Should null ModuleInfo be allowed?
    775             if (m !is null)
    776             {
    777                 if (auto res = dg(m))
    778                     return res;
    779             }
    780         }
    781     }
    782     return 0;
    783 }
    784 
    785 /********************************************
    786  * Module constructor and destructor routines.
    787  */
    788 
    789 extern (C)
    790 {
    791 void rt_moduleCtor()
    792 {
    793     foreach (ref sg; SectionGroup)
    794     {
    795         sg.moduleGroup.sortCtors();
    796         sg.moduleGroup.runCtors();
    797     }
    798 }
    799 
    800 void rt_moduleTlsCtor()
    801 {
    802     foreach (ref sg; SectionGroup)
    803     {
    804         sg.moduleGroup.runTlsCtors();
    805     }
    806 }
    807 
    808 void rt_moduleTlsDtor()
    809 {
    810     foreach_reverse (ref sg; SectionGroup)
    811     {
    812         sg.moduleGroup.runTlsDtors();
    813     }
    814 }
    815 
    816 void rt_moduleDtor()
    817 {
    818     foreach_reverse (ref sg; SectionGroup)
    819     {
    820         sg.moduleGroup.runDtors();
    821         sg.moduleGroup.free();
    822     }
    823 }
    824 
    825 version (Win32)
    826 {
    827     // Alternate names for backwards compatibility with older DLL code
    828     void _moduleCtor()
    829     {
    830         rt_moduleCtor();
    831     }
    832 
    833     void _moduleDtor()
    834     {
    835         rt_moduleDtor();
    836     }
    837 
    838     void _moduleTlsCtor()
    839     {
    840         rt_moduleTlsCtor();
    841     }
    842 
    843     void _moduleTlsDtor()
    844     {
    845         rt_moduleTlsDtor();
    846     }
    847 }
    848 }
    849 
    850 /********************************************
    851  */
    852 
    853 void runModuleFuncs(alias getfp)(const(immutable(ModuleInfo)*)[] modules)
    854 {
    855     foreach (m; modules)
    856     {
    857         if (auto fp = getfp(m))
    858             (*fp)();
    859     }
    860 }
    861 
    862 void runModuleFuncsRev(alias getfp)(const(immutable(ModuleInfo)*)[] modules)
    863 {
    864     foreach_reverse (m; modules)
    865     {
    866         if (auto fp = getfp(m))
    867             (*fp)();
    868     }
    869 }
    870 
    871 unittest
    872 {
    873     static void assertThrown(T : Throwable, E)(lazy E expr, string msg)
    874     {
    875         try
    876             expr;
    877         catch (T)
    878             return;
    879         assert(0, msg);
    880     }
    881 
    882     static void stub()
    883     {
    884     }
    885 
    886     static struct UTModuleInfo
    887     {
    888         this(uint flags)
    889         {
    890             mi._flags = flags;
    891         }
    892 
    893         void setImports(immutable(ModuleInfo)*[] imports...)
    894         {
    895             import core.bitop;
    896             assert(flags & MIimportedModules);
    897 
    898             immutable nfuncs = popcnt(flags & (MItlsctor|MItlsdtor|MIctor|MIdtor|MIictor));
    899             immutable size = nfuncs * (void function()).sizeof +
    900                 size_t.sizeof + imports.length * (ModuleInfo*).sizeof;
    901             assert(size <= pad.sizeof);
    902 
    903             pad[nfuncs] = imports.length;
    904             .memcpy(&pad[nfuncs+1], imports.ptr, imports.length * imports[0].sizeof);
    905         }
    906 
    907         immutable ModuleInfo mi;
    908         size_t[8] pad;
    909         alias mi this;
    910     }
    911 
    912     static UTModuleInfo mockMI(uint flags)
    913     {
    914         auto mi = UTModuleInfo(flags | MIimportedModules);
    915         auto p = cast(void function()*)&mi.pad;
    916         if (flags & MItlsctor) *p++ = &stub;
    917         if (flags & MItlsdtor) *p++ = &stub;
    918         if (flags & MIctor) *p++ = &stub;
    919         if (flags & MIdtor) *p++ = &stub;
    920         if (flags & MIictor) *p++ = &stub;
    921         *cast(size_t*)p++ = 0; // number of imported modules
    922         assert(cast(void*)p <= &mi + 1);
    923         return mi;
    924     }
    925 
    926     static void checkExp2(string testname, bool shouldThrow, string oncycle,
    927         immutable(ModuleInfo*)[] modules,
    928         immutable(ModuleInfo*)[] dtors=null,
    929         immutable(ModuleInfo*)[] tlsdtors=null)
    930     {
    931         auto mgroup = ModuleGroup(modules);
    932         mgroup.sortCtors(oncycle);
    933 
    934         // if we are expecting sort to throw, don't throw because of unexpected
    935         // success!
    936         if (!shouldThrow)
    937         {
    938             foreach (m; mgroup._modules)
    939                 assert(!(m.flags & (MIctorstart | MIctordone)), testname);
    940             assert(mgroup._ctors    == dtors, testname);
    941             assert(mgroup._tlsctors == tlsdtors, testname);
    942         }
    943     }
    944 
    945     static void checkExp(string testname, bool shouldThrow,
    946         immutable(ModuleInfo*)[] modules,
    947         immutable(ModuleInfo*)[] dtors=null,
    948         immutable(ModuleInfo*)[] tlsdtors=null)
    949     {
    950         checkExp2(testname, shouldThrow, "abort", modules, dtors, tlsdtors);
    951     }
    952 
    953 
    954     {
    955         auto m0 = mockMI(0);
    956         auto m1 = mockMI(0);
    957         auto m2 = mockMI(0);
    958         checkExp("no ctors", false, [&m0.mi, &m1.mi, &m2.mi]);
    959     }
    960 
    961     {
    962         auto m0 = mockMI(MIictor);
    963         auto m1 = mockMI(0);
    964         auto m2 = mockMI(MIictor);
    965         auto mgroup = ModuleGroup([&m0.mi, &m1.mi, &m2.mi]);
    966         checkExp("independent ctors", false, [&m0.mi, &m1.mi, &m2.mi]);
    967     }
    968 
    969     {
    970         auto m0 = mockMI(MIstandalone | MIctor);
    971         auto m1 = mockMI(0);
    972         auto m2 = mockMI(0);
    973         auto mgroup = ModuleGroup([&m0.mi, &m1.mi, &m2.mi]);
    974         checkExp("standalone ctor", false, [&m0.mi, &m1.mi, &m2.mi], [&m0.mi]);
    975     }
    976 
    977     {
    978         auto m0 = mockMI(MIstandalone | MIctor);
    979         auto m1 = mockMI(MIstandalone | MIctor);
    980         auto m2 = mockMI(0);
    981         m1.setImports(&m0.mi);
    982         checkExp("imported standalone => no dependency", false,
    983                  [&m0.mi, &m1.mi, &m2.mi], [&m0.mi, &m1.mi]);
    984     }
    985 
    986     {
    987         auto m0 = mockMI(MIstandalone | MIctor);
    988         auto m1 = mockMI(MIstandalone | MIctor);
    989         auto m2 = mockMI(0);
    990         m0.setImports(&m1.mi);
    991         checkExp("imported standalone => no dependency (2)", false,
    992                 [&m0.mi, &m1.mi, &m2.mi], [&m0.mi, &m1.mi]);
    993     }
    994 
    995     {
    996         auto m0 = mockMI(MIstandalone | MIctor);
    997         auto m1 = mockMI(MIstandalone | MIctor);
    998         auto m2 = mockMI(0);
    999         m0.setImports(&m1.mi);
   1000         m1.setImports(&m0.mi);
   1001         checkExp("standalone may have cycle", false,
   1002                 [&m0.mi, &m1.mi, &m2.mi], [&m0.mi, &m1.mi]);
   1003     }
   1004 
   1005     {
   1006         auto m0 = mockMI(MIctor);
   1007         auto m1 = mockMI(MIctor);
   1008         auto m2 = mockMI(0);
   1009         m1.setImports(&m0.mi);
   1010         checkExp("imported ctor => ordered ctors", false,
   1011                 [&m0.mi, &m1.mi, &m2.mi], [&m0.mi, &m1.mi], []);
   1012     }
   1013 
   1014     {
   1015         auto m0 = mockMI(MIctor);
   1016         auto m1 = mockMI(MIctor);
   1017         auto m2 = mockMI(0);
   1018         m0.setImports(&m1.mi);
   1019         checkExp("imported ctor => ordered ctors (2)", false,
   1020                 [&m0.mi, &m1.mi, &m2.mi], [&m1.mi, &m0.mi], []);
   1021     }
   1022 
   1023     {
   1024         auto m0 = mockMI(MIctor);
   1025         auto m1 = mockMI(MIctor);
   1026         auto m2 = mockMI(0);
   1027         m0.setImports(&m1.mi);
   1028         m1.setImports(&m0.mi);
   1029         assertThrown!Throwable(checkExp("", true, [&m0.mi, &m1.mi, &m2.mi]),
   1030                 "detects ctors cycles");
   1031         assertThrown!Throwable(checkExp2("", true, "deprecate",
   1032                                         [&m0.mi, &m1.mi, &m2.mi]),
   1033                 "detects ctors cycles (dep)");
   1034     }
   1035 
   1036     {
   1037         auto m0 = mockMI(MIctor);
   1038         auto m1 = mockMI(MIctor);
   1039         auto m2 = mockMI(0);
   1040         m0.setImports(&m2.mi);
   1041         m1.setImports(&m2.mi);
   1042         m2.setImports(&m0.mi, &m1.mi);
   1043         assertThrown!Throwable(checkExp("", true, [&m0.mi, &m1.mi, &m2.mi]),
   1044                 "detects cycle with repeats");
   1045     }
   1046 
   1047     {
   1048         auto m0 = mockMI(MIctor);
   1049         auto m1 = mockMI(MIctor);
   1050         auto m2 = mockMI(MItlsctor);
   1051         m0.setImports(&m1.mi, &m2.mi);
   1052         checkExp("imported ctor/tlsctor => ordered ctors/tlsctors", false,
   1053                 [&m0.mi, &m1.mi, &m2.mi], [&m1.mi, &m0.mi], [&m2.mi]);
   1054     }
   1055 
   1056     {
   1057         auto m0 = mockMI(MIctor | MItlsctor);
   1058         auto m1 = mockMI(MIctor);
   1059         auto m2 = mockMI(MItlsctor);
   1060         m0.setImports(&m1.mi, &m2.mi);
   1061         checkExp("imported ctor/tlsctor => ordered ctors/tlsctors (2)", false,
   1062                 [&m0.mi, &m1.mi, &m2.mi], [&m1.mi, &m0.mi], [&m2.mi, &m0.mi]);
   1063     }
   1064 
   1065     {
   1066         auto m0 = mockMI(MIctor);
   1067         auto m1 = mockMI(MIctor);
   1068         auto m2 = mockMI(MItlsctor);
   1069         m0.setImports(&m1.mi, &m2.mi);
   1070         m2.setImports(&m0.mi);
   1071         checkExp("no cycle between ctors/tlsctors", false,
   1072                 [&m0.mi, &m1.mi, &m2.mi], [&m1.mi, &m0.mi], [&m2.mi]);
   1073     }
   1074 
   1075     {
   1076         auto m0 = mockMI(MItlsctor);
   1077         auto m1 = mockMI(MIctor);
   1078         auto m2 = mockMI(MItlsctor);
   1079         m0.setImports(&m2.mi);
   1080         m2.setImports(&m0.mi);
   1081         assertThrown!Throwable(checkExp("", true, [&m0.mi, &m1.mi, &m2.mi]),
   1082                 "detects tlsctors cycle");
   1083         assertThrown!Throwable(checkExp2("", true, "deprecate",
   1084                                          [&m0.mi, &m1.mi, &m2.mi]),
   1085                 "detects tlsctors cycle (dep)");
   1086     }
   1087 
   1088     {
   1089         auto m0 = mockMI(MItlsctor);
   1090         auto m1 = mockMI(MIctor);
   1091         auto m2 = mockMI(MItlsctor);
   1092         m0.setImports(&m1.mi);
   1093         m1.setImports(&m0.mi, &m2.mi);
   1094         m2.setImports(&m1.mi);
   1095         assertThrown!Throwable(checkExp("", true, [&m0.mi, &m1.mi, &m2.mi]),
   1096                 "detects tlsctors cycle with repeats");
   1097     }
   1098 
   1099     {
   1100         auto m0 = mockMI(MIctor);
   1101         auto m1 = mockMI(MIstandalone | MIctor);
   1102         auto m2 = mockMI(MIstandalone | MIctor);
   1103         m0.setImports(&m1.mi);
   1104         m1.setImports(&m2.mi);
   1105         m2.setImports(&m0.mi);
   1106         // NOTE: this is implementation dependent, sorted order shouldn't be tested.
   1107         checkExp("closed ctors cycle", false, [&m0.mi, &m1.mi, &m2.mi],
   1108                 [&m1.mi, &m2.mi, &m0.mi]);
   1109         //checkExp("closed ctors cycle", false, [&m0.mi, &m1.mi, &m2.mi], [&m0.mi, &m1.mi, &m2.mi]);
   1110     }
   1111 }
   1112 
   1113 version (CRuntime_Microsoft)
   1114 {
   1115     // Dummy so Win32 code can still call it
   1116     extern(C) void _minit() { }
   1117 }
   1118