minfo.d revision 1.1 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 mrg * Source: $(DRUNTIMESRC src/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 mrg foreach (int 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 mrg import rt.util.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 mrg sink("Cyclic dependency between module ");
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 mrg foreach (int 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 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 mrg // TODO: reuse GCBits by moving it to rt.util.container or core.internal
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 mrg foreach (int i, ref v; initialEdges)
586 1.1 mrg v = 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