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