1 /**
2  * Part of the D programming language runtime library.
3  * Forms the symbols available to all D programs. Includes
4  * Object, which is the root of the class object hierarchy.
5  *
6  * This module is implicitly imported.
7  * Macros:
8  *      WIKI = Object
9  */
10 
11 /*
12  *  Copyright (C) 2004-2007 by Digital Mars, www.digitalmars.com
13  *  Written by Walter Bright
14  *
15  *  This software is provided 'as-is', without any express or implied
16  *  warranty. In no event will the authors be held liable for any damages
17  *  arising from the use of this software.
18  *
19  *  Permission is granted to anyone to use this software for any purpose,
20  *  including commercial applications, and to alter it and redistribute it
21  *  freely, in both source and binary form, subject to the following
22  *  restrictions:
23  *
24  *  o  The origin of this software must not be misrepresented; you must not
25  *     claim that you wrote the original software. If you use this software
26  *     in a product, an acknowledgment in the product documentation would be
27  *     appreciated but is not required.
28  *  o  Altered source versions must be plainly marked as such, and must not
29  *     be misrepresented as being the original software.
30  *  o  This notice may not be removed or altered from any source
31  *     distribution.
32  */
33 
34 /*
35  *  Modified by Sean Kelly <sean@f4.ca> for use with Tango.
36  */
37 
38 module object;
39 
40 private
41 {
42     import tango.stdc.string : memcmp, memcpy, memmove;
43     import tango.stdc.stdlib : calloc, realloc, free;
44     import tango.stdc.stdio : snprintf;
45     import tango.core.Exception : onOutOfMemoryError;
46     import rt.compiler.util.string;
47     import rt.compiler.util.hash;
48     import rt.compiler.dmd.rt.aaA;
49     debug(PRINTF) import tango.stdc.stdio: printf;
50     extern (C) Object _d_newclass(ClassInfo ci);
51 
52     version (darwin)
53         import rt.compiler.dmd.darwin.Image;
54 }
55 
56 // NOTE: For some reason, this declaration method doesn't work
57 //       in this particular file (and this file only).  It must
58 //       be a DMD thing.
59 //alias typeof(int.sizeof)                    size_t;
60 //alias typeof(cast(void*)0 - cast(void*)0)   ptrdiff_t;
61 
62 version( X86_64 )
63 {
64     alias ulong size_t;
65     alias long  ptrdiff_t;
66 }
67 else
68 {
69     alias uint  size_t;
70     alias int   ptrdiff_t;
71 }
72 
73 alias size_t hash_t;
74 alias int equals_t;
75 
76 version (PhobosCompatibility)
77 {
78         alias char[]  string;
79         alias wchar[] wstring;
80         alias dchar[] dstring;
81 }
82 
83 /**
84  * All D class objects inherit from Object.
85  */
86 class Object
87 {
88     /**
89      * Override this to capture an explicit delete or an implicit
90      * delete via a scoped-instance. Unlike a dtor(), GC references
91      * are still intact when this method is invoked
92      */
93     void dispose()
94     {
95     }
96 
97     /**
98      * Convert Object to a human readable string.
99      */
100     char[] toString()
101     {
102         return this.classinfo.name;
103     }
104 
105     /**
106      * Compute hash function for Object.
107      */
108     hash_t toHash()
109     {
110         // BUG: this prevents a compacting GC from working, needs to be fixed
111         return cast(hash_t)cast(void*)this;
112     }
113 
114     /**
115      * Compare with another Object obj.
116      * Returns:
117      *  $(TABLE
118      *  $(TR $(TD this &lt; obj) $(TD &lt; 0))
119      *  $(TR $(TD this == obj) $(TD 0))
120      *  $(TR $(TD this &gt; obj) $(TD &gt; 0))
121      *  )
122      */
123     int opCmp(Object o)
124     {
125         // BUG: this prevents a compacting GC from working, needs to be fixed
126         //return cast(int)cast(void*)this - cast(int)cast(void*)o;
127 
128         throw new Exception("need opCmp for class " ~ this.classinfo.name);
129         //return ((cast(void*)this<cast(void*)o)?-1:((cast(void*)this==cast(void*)o)?0:1));
130     }
131 
132     /**
133      * Returns !=0 if this object does have the same contents as obj.
134      */
135     equals_t opEquals(Object o)
136     {
137         return cast(equals_t)(this is o);
138     }
139 
140     interface Monitor
141     {
142         void lock();
143         void unlock();
144     }
145 }
146 
147 /**
148  * Information about an interface.
149  * When an object is accessed via an interface, an Interface* appears as the
150  * first entry in its vtbl.
151  */
152 struct Interface
153 {
154     ClassInfo   classinfo;  /// .classinfo for this interface (not for containing class)
155     void*[]     vtbl;
156     ptrdiff_t   offset;     /// offset to Interface 'this' from Object 'this'
157 }
158 
159 /**
160  * Pointer map for precise heap scanning.
161  * Format:
162  *  PointerMap pm = typeid(T).pointermap;
163  *  pm.bits = [header] ~ scan_bits ~ pointer_bits
164  *  size_t header is the number of pointer sized units in T (T.sizeof/size_t.sizeof)
165  *  size_t[] scan_bits is the bitmap; each bit covers size_t bytes of T, meaning:
166  *      0: guaranteed not to be a pointer, don't scan
167  *      1: possibly a pointer, must scan
168  *  size_t[] pointer_bits is a second bitmap similar to scan_bits. If the
169  *  corrsponding bit in scan_bits is 0, the bit is 0; otherwise its meaning is:
170  *      0: pointer can not be moved, because it's possibly an integer
171  *      1: pointer can be moved, the corresponding word is always a pointer
172  *  Note that not the bit-arrays are concatenated, but the size_t arrays.
173  * This implies all GC-aware pointers must be aligned on size_t boundaries.
174  * The compiler won't set any bits for unaligned pointer fields.
175  * The least significant bit of a size_t item is considered the first bit.
176  * PointerMap.init is a conservative scanning mask equivelant to void*[]
177  */
178 struct PointerMap
179 {
180     size_t[] bits = [1, 1, 0];
181 
182     private const size_t BITS = size_t.sizeof * 8;
183 
184     /// return size in bytes (aligned)
185     size_t size()
186     {
187         return bits[0] * size_t.sizeof;
188     }
189 
190     private bool getbit(size_t offset, bool pointer_bit)
191     {
192         assert(offset < size);
193 
194         if ((offset & (size_t.sizeof - 1)) != 0)
195             return false;
196 
197         size_t elem = offset / size_t.sizeof;
198         size_t start = 1; //scan_bits offset
199         if (pointer_bit)
200             start += (bits[0] + BITS - 1) / BITS; //pointer_bits offset
201         return !!(bits[start + elem / BITS] & (1 << (elem % BITS)));
202     }
203 
204     /// return if the (aligned) field starting at byte offset is a pointer
205     /// Warning: the GC may access the internal data structure directly instead
206     /// of using this method to make scanning faster
207     bool mustScanWordAt(size_t offset)
208     {
209         return getbit(offset, false);
210     }
211 
212     /// return if the (aligned) field starting at byte offset is a moveable pointer
213     /// "moveable pointer" means that the memory block referenced by the pointer can
214     /// be moved by the GC (the pointer field will be updated with the new address)
215     bool isPointerAt(size_t offset)
216     {
217         return getbit(offset, true);
218     }
219 
220     /// return true if and only if there are integer fields overlapping with pointer
221     /// fields in this type
222     bool canUpdatePointers()
223     {
224         auto len = (bits.length - 1) / 2;
225         return bits[1 .. 1 + len] == bits[1 + len .. $];
226     }
227 
228 }
229 
230 /// code for manually building PointerMaps
231 /// separate struct from PointerMap because for some representations, it may be
232 /// hard to handle arbitrary pointerAt() calls to update the internal data structure
233 /// (think of pointer maps encoded as lists of runs etc.)
234 /// xxx untested
235 struct PointerMapBuilder
236 {
237     private size_t[] m_bits = null;
238     private size_t m_size = 0;
239 
240     private const size_t BITS = size_t.sizeof * 8;
241 
242     /// set the underlying type's size in bytes
243     void size(size_t bytes)
244     {
245         size_t nelem = bytes / size_t.sizeof;
246         m_bits.length = 1 + ((nelem + BITS - 1) / BITS) * 2;
247         m_bits[] = 0;
248         m_bits[0] = nelem;
249         m_size = bytes;
250     }
251 
252     /// mark the pointer sized field at byte offset as pointer
253     /// if the offset is unaligned, it does nothing
254     void mustScanWordAt(size_t offset)
255     {
256         assert(offset < m_size);
257 
258         if ((offset & (size_t.sizeof - 1)) != 0)
259             return;
260 
261         size_t elem = offset / size_t.sizeof;
262         m_bits[1 + elem / BITS] |= 1 << (elem % BITS);
263     }
264 
265     /// starting at the given byte offset, call pointerAt() for each pointer in pm
266     void inlineAt(size_t offset, PointerMap pm)
267     {
268         assert(offset + pm.size <= m_size);
269 
270         for (size_t n = 0; n < pm.size; n += size_t.sizeof)
271         {
272             if (pm.mustScanWordAt(n))
273                 mustScanWordAt(offset + n);
274         }
275     }
276 
277     /// create a PointerMap instance
278     /// accessing this PointerMapBuilder after calling this method is not allowed
279     PointerMap convertToPointerMap() {
280         //no un-moveable pointer stuff supported => imply all pointers are moveable
281         size_t len = (m_bits[0] + BITS - 1) / BITS;
282         assert(len == (m_bits.length - 1) / 2);
283         m_bits[1 + len .. $] = m_bits[1 .. 1 + len];
284 
285         auto res = PointerMap(m_bits);
286         *this = PointerMapBuilder.init; //invalidate this instance
287         return res;
288     }
289 }
290 
291 //static const PointerMap cPointerMapNoScan = PointerMap([1, 0, 0]);
292 
293 /**
294  * Runtime type information about a class. Can be retrieved for any class type
295  * or instance by using the .classinfo property.
296  * A pointer to this appears as the first entry in the class's vtbl[].
297  */
298 class ClassInfo : Object
299 {
300     byte[]      init;           /** class static initializer
301                                  * (init.length gives size in bytes of class)
302                                  */
303     char[]      name;           /// class name
304     void*[]     vtbl;           /// virtual function pointer table
305     Interface[] interfaces;     /// interfaces this class implements
306     ClassInfo   base;           /// base class
307     void*       destructor;     // Only use as delegate.funcptr!
308     void*       classInvariant; // Only use as delegate.funcptr!
309     uint        flags;
310     //  1:                      // is IUnknown or is derived from IUnknown
311     //  2:                      // has no possible pointers into GC memory
312     //  4:                      // has offTi[] member
313     //  8:                      // has constructors
314     //  32:         // has typeinfo
315     void*       deallocator;
316     OffsetTypeInfo[] offTi;
317     Object function() defaultConstructor;   // default Constructor. Only use as delegate.funcptr!
318     static if (__VERSION__ >= 1045) {
319         TypeInfo typeinfo;
320     }
321 
322     version (D_HavePointerMap) {
323         PointerMap pointermap;
324     }
325 
326     /**
327      * Search all modules for ClassInfo corresponding to classname.
328      * Returns: null if not found
329      */
330     static ClassInfo find(char[] classname)
331     {
332         foreach (m; ModuleInfo)
333         {
334             if (!m)
335                 continue;
336 
337             //writefln("module %s, %d", m.name, m.localClasses.length);
338             foreach (c; m.localClasses)
339             {
340                 //writefln("\tclass %s", c.name);
341                 if (c.name == classname)
342                     return c;
343             }
344         }
345         return null;
346     }
347 
348     /**
349      * Create instance of Object represented by 'this'.
350      */
351     Object create()
352     {
353         if (flags & 8 && defaultConstructor is null)
354             return null;
355         Object o = _d_newclass(this);
356         if (flags & 8 && defaultConstructor !is null)
357         {
358             Object delegate() ctor;
359             ctor.ptr = cast(void*)o;
360             ctor.funcptr = cast(Object function())defaultConstructor;
361             return ctor();
362         }
363         return o;
364     }
365 }
366 
367 /**
368  * Array of pairs giving the offset and type information for each
369  * member in an aggregate.
370  */
371 struct OffsetTypeInfo
372 {
373     size_t   offset;    /// Offset of member from start of object
374     TypeInfo ti;        /// TypeInfo for this member
375 }
376 
377 /**
378  * Runtime type information about a type.
379  * Can be retrieved for any type using a
380  * <a href="../expression.html#typeidexpression">TypeidExpression</a>.
381  */
382 class TypeInfo
383 {
384     hash_t toHash()
385     {   hash_t hash;
386 
387         foreach (char c; this.toString())
388             hash = hash * 9 + c;
389         return hash;
390     }
391 
392     int opCmp(Object o)
393     {
394         if (this is o)
395             return 0;
396         TypeInfo ti = cast(TypeInfo)o;
397         if (ti is null)
398             return 1;
399         return stringCompare(this.toString(), ti.toString());
400     }
401 
402     override equals_t opEquals(Object o)
403     {
404         /* TypeInfo instances are singletons, but duplicates can exist
405          * across DLL's. Therefore, comparing for a name match is
406          * sufficient.
407          */
408         if (this is o)
409             return 1;
410         TypeInfo ti = cast(TypeInfo)o;
411         return cast(equals_t)(ti && this.toString() == ti.toString());
412     }
413 
414     /// Returns a hash of the instance of a type.
415     hash_t getHash(in void* p) { return cast(hash_t)p; }
416 
417     /// Compares two instances for equality.
418     equals_t equals(in void* p1, in void* p2) { return p1 == p2; }
419 
420     /// Compares two instances for &lt;, ==, or &gt;.
421     int compare(in void* p1, in void* p2) { return 0; } // throw new Exception("non comparable",__FILE__,__LINE__);
422     /// Return alignment of type
423     size_t talign() { return tsize(); }
424     /// Returns size of the type.
425     size_t tsize() { return 0; }
426 
427     /// Swaps two instances of the type.
428     void swap(void* p1, void* p2)
429     {
430         size_t n = tsize();
431         for (size_t i = 0; i < n; i++)
432         {
433             byte t = (cast(byte *)p1)[i];
434             (cast(byte*)p1)[i] = (cast(byte*)p2)[i];
435             (cast(byte*)p2)[i] = t;
436         }
437     }
438 
439     /// Get TypeInfo for 'next' type, as defined by what kind of type this is,
440     /// null if none.
441     TypeInfo next() { return null; }
442 
443     /// Return default initializer, null if default initialize to 0
444     void[] init() { return null; }
445 
446     /// Get flags for type: 1 means GC should scan for pointers
447     uint flags() { return 0; }
448 
449     /// Get a pointer to PointerMap; used for GC scanning
450     PointerMap pointermap() {
451         if (flags() & 1) {
452             return PointerMap.init;
453         } else {
454             //return cPointerMapNoScan;
455             //work around for dmd bug #4397 (triggers infinite recursion)
456             static size_t[3] g_arr;
457             static PointerMap pm;
458             pm.bits = g_arr;
459             pm.bits[0] = 1;
460             pm.bits[1] = 0;
461             pm.bits[2] = 0;
462             return pm;
463         }
464     }
465 
466     //return PointerMap for a single, moveable pointer
467     //also just a workaround for dmd bug #4397; should be a const variable
468     private PointerMap exactpointer() {
469         static size_t[3] g_arr;
470         static PointerMap pm;
471         pm.bits = g_arr;
472         pm.bits[0] = 1;
473         pm.bits[1] = 1;
474         pm.bits[2] = 1;
475         return pm;
476     }
477 
478     /// Get type information on the contents of the type; null if not available
479     OffsetTypeInfo[] offTi() { return null; }
480 
481 
482      /** Return internal info on arguments fitting into 8byte.
483        * See X86-64 ABI 3.2.3
484      */
485     version (X86_64) int argTypes(out TypeInfo arg1, out TypeInfo arg2)
486     {
487         arg1 = this;
488         return 0;
489     }
490 }
491 
492 class TypeInfo_Typedef : TypeInfo
493 {
494     override char[] toString() { return name; }
495 
496     override equals_t opEquals(Object o)
497     {
498         TypeInfo_Typedef c;
499         return this is o ||
500                ((c = cast(TypeInfo_Typedef)o) !is null &&
501                 this.name == c.name &&
502                 this.base == c.base);
503     }
504 
505     override hash_t getHash(in void* p) { return base.getHash(p); }
506     override equals_t equals(in void* p1, in void* p2) { return base.equals(p1, p2); }
507     override int compare(in void* p1, in void* p2) { return base.compare(p1, p2); }
508     override size_t tsize() { return base.tsize(); }
509     override void swap(void* p1, void* p2) { return base.swap(p1, p2); }
510 
511     override TypeInfo next() { return base; }
512     override uint flags() { return base.flags(); }
513     override PointerMap pointermap() { return base.pointermap(); }
514     override void[] init() { return m_init.length ? m_init : base.init(); }
515 
516     size_t talign() { return base.talign(); }
517 
518     version (X86_64) int argTypes(out TypeInfo arg1, out TypeInfo arg2)
519     {   
520         return base.argTypes(arg1, arg2);
521     }
522 
523     TypeInfo base;
524     char[] name;
525     void[] m_init;
526 }
527 
528 class TypeInfo_Enum : TypeInfo_Typedef
529 {
530 
531 }
532 
533 class TypeInfo_Pointer : TypeInfo
534 {
535     override char[] toString() { return m_next.toString() ~ "*"; }
536 
537     override equals_t opEquals(Object o)
538     {
539         TypeInfo_Pointer c;
540         return this is o ||
541                 ((c = cast(TypeInfo_Pointer)o) !is null &&
542                  this.m_next == c.m_next);
543     }
544 
545     override hash_t getHash(in void* p)
546     {
547         return cast(hash_t)*cast(void**)p;
548     }
549 
550     override equals_t equals(in void* p1, in void* p2)
551     {
552         return cast(equals_t)(*cast(void**)p1 == *cast(void**)p2);
553     }
554 
555     override int compare(in void* p1, in void* p2)
556     {
557         if (*cast(void**)p1 < *cast(void**)p2)
558             return -1;
559         else if (*cast(void**)p1 > *cast(void**)p2)
560             return 1;
561         else
562             return 0;
563     }
564 
565     override size_t tsize()
566     {
567         return (void*).sizeof;
568     }
569 
570     override void swap(void* p1, void* p2)
571     {
572         void* tmp = *cast(void**)p1;
573         *cast(void**)p1 = *cast(void**)p2;
574         *cast(void**)p2 = tmp;
575     }
576 
577     override TypeInfo next() { return m_next; }
578     override uint flags() { return 1; }
579     override PointerMap pointermap() { return exactpointer(); }
580 
581     TypeInfo m_next;
582 }
583 
584 class TypeInfo_Array : TypeInfo
585 {
586     override char[] toString() { return value.toString() ~ "[]"; }
587 
588     override equals_t opEquals(Object o)
589     {
590         TypeInfo_Array c;
591         return this is o ||
592                ((c = cast(TypeInfo_Array)o) !is null &&
593                 this.value == c.value);
594     }
595 
596     override hash_t getHash(in void* p)
597     {
598         size_t sz = value.tsize();
599         void[] a = *cast(void[]*)p;
600         hash_t hash = a.length;
601         for (size_t i = 0; i < a.length; i++)
602             hash = rt_hash_combine(value.getHash(a.ptr + i * sz),hash);
603         return hash;
604     }
605 
606     override equals_t equals(in void* p1, in void* p2)
607     {
608         void[] a1 = *cast(void[]*)p1;
609         void[] a2 = *cast(void[]*)p2;
610         if (a1.length != a2.length)
611             return false;
612         size_t sz = value.tsize();
613         for (size_t i = 0; i < a1.length; i++)
614         {
615             if (!value.equals(a1.ptr + i * sz, a2.ptr + i * sz))
616                 return false;
617         }
618         return true;
619     }
620 
621     override int compare(in void* p1, in void* p2)
622     {
623         void[] a1 = *cast(void[]*)p1;
624         void[] a2 = *cast(void[]*)p2;
625         size_t sz = value.tsize();
626         size_t len = a1.length;
627 
628         if (a2.length < len)
629             len = a2.length;
630         for (size_t u = 0; u < len; u++)
631         {
632             int result = value.compare(a1.ptr + u * sz, a2.ptr + u * sz);
633             if (result)
634                 return result;
635         }
636         return cast(int)a1.length - cast(int)a2.length;
637     }
638 
639     override size_t tsize()
640     {
641         return (void[]).sizeof;
642     }
643 
644     override void swap(void* p1, void* p2)
645     {
646         void[] tmp = *cast(void[]*)p1;
647         *cast(void[]*)p1 = *cast(void[]*)p2;
648         *cast(void[]*)p2 = tmp;
649     }
650 
651     TypeInfo value;
652 
653     override TypeInfo next()
654     {
655         return value;
656     }
657 
658     override uint flags() { return 1; }
659 
660     size_t talign()
661     {
662         return (void[]).alignof;
663     }
664 
665     version (X86_64) override int argTypes(out TypeInfo arg1, out TypeInfo arg2)
666     {   //arg1 = typeid(size_t);
667         //arg2 = typeid(void*);
668         return 0;
669     }
670 
671     override PointerMap pointermap()
672     {
673         //return static mask for arrays
674         //  word 0: length
675         //  word 1: pointer
676         //work around for dmd bug #4397 (triggers infinite recursion)
677         static size_t[3] g_arr;
678         static PointerMap pm;
679         pm.bits = g_arr;
680         pm.bits[0] = 2;
681         pm.bits[1] = 0b10;
682         pm.bits[2] = 0b10; //moveable
683         return pm;
684     }
685 }
686 
687 class TypeInfo_StaticArray : TypeInfo
688 {
689     override char[] toString()
690     {
691         char [10] tmp = void;
692         return value.toString() ~ "[" ~ intToUtf8(tmp, len) ~ "]";
693     }
694 
695     override equals_t opEquals(Object o)
696     {
697         TypeInfo_StaticArray c;
698         return this is o ||
699                ((c = cast(TypeInfo_StaticArray)o) !is null &&
700                 this.len == c.len &&
701                 this.value == c.value);
702     }
703 
704     override hash_t getHash(in void* p)
705     {
706         size_t sz = value.tsize();
707         hash_t hash = len;
708         for (size_t i = 0; i < len; i++)
709             hash = rt_hash_combine(value.getHash(p + i * sz),hash);
710         return hash;
711     }
712 
713     override equals_t equals(in void* p1, in void* p2)
714     {
715         size_t sz = value.tsize();
716 
717         for (size_t u = 0; u < len; u++)
718         {
719             if (!value.equals(p1 + u * sz, p2 + u * sz))
720                 return false;
721         }
722         return true;
723     }
724 
725     override int compare(in void* p1, in void* p2)
726     {
727         size_t sz = value.tsize();
728 
729         for (size_t u = 0; u < len; u++)
730         {
731             int result = value.compare(p1 + u * sz, p2 + u * sz);
732             if (result)
733                 return result;
734         }
735         return 0;
736     }
737 
738     override size_t tsize()
739     {
740         return len * value.tsize();
741     }
742 
743     override void swap(void* p1, void* p2)
744     {
745         void* tmp;
746         size_t sz = value.tsize();
747         ubyte[16] buffer;
748         void* pbuffer;
749 
750         if (sz < buffer.sizeof)
751             tmp = buffer.ptr;
752         else
753             tmp = pbuffer = (new void[sz]).ptr;
754 
755         for (size_t u = 0; u < len; u += sz)
756         {   size_t o = u * sz;
757             memcpy(tmp, p1 + o, sz);
758             memcpy(p1 + o, p2 + o, sz);
759             memcpy(p2 + o, tmp, sz);
760         }
761         if (pbuffer)
762             delete pbuffer;
763     }
764 
765     override void[] init() { return value.init(); }
766     override TypeInfo next() { return value; }
767     override uint flags() { return value.flags(); }
768 
769     override PointerMap pointermap()
770     {
771         //assert(0);
772         //this is kind of a hack to make arrays of static arrays work
773         //e.g. T[2][] (typeid(T[2]) would be this instance)
774         //because the GC repeats GC bitmasks shorter than the allocation size,
775         //  this should work well
776         //it's a hack because pointermap() is supposed to return a map that
777         //  covers the whole type (i.e. doesn't rely on repeat)
778         //this also might prevent subtle bugs, when a static array is resized
779         //  as dynamic array, and the bitmask is reused (can that happen at all?)
780         return value.pointermap();
781     }
782 
783     TypeInfo value;
784     size_t   len;
785 
786     size_t talign()
787     {
788         return value.talign();
789     }
790 
791     version (X86_64) override int argTypes(out TypeInfo arg1, out TypeInfo arg2)
792     {
793         arg1 = typeid(void*);
794         return 0;
795     }
796 
797 }
798 
799 class TypeInfo_AssociativeArray : TypeInfo
800 {
801     override char[] toString()
802     {
803         return next.toString() ~ "[" ~ key.toString() ~ "]";
804     }
805 
806     override equals_t opEquals(Object o)
807     {
808         TypeInfo_AssociativeArray c;
809         return this is o ||
810                 ((c = cast(TypeInfo_AssociativeArray)o) !is null &&
811                  this.key == c.key &&
812                  this.next == c.next);
813     }
814 
815     override hash_t getHash(in void* p)
816     {
817         size_t sz = value.tsize();
818         hash_t hash = sz;
819         AA aa=*cast(AA*)p;
820         size_t keysize=key.tsize();
821         int res=_aaApply2(aa, keysize, cast(dg2_t) delegate int(void *k, void *v){
822             hash+=rt_hash_combine(key.getHash(k),value.getHash(v));
823             return 0;
824         });
825         return hash;
826     }
827 
828     override size_t tsize()
829     {
830         return (char[int]).sizeof;
831     }
832     override equals_t equals(in void* p1, in void* p2)
833     {
834         AA a=*cast(AA*)p1;
835         AA b=*cast(AA*)p2;
836         if (cast(void*)a.a==cast(void*)b.a) return true;
837         size_t l1=_aaLen(a);
838         size_t l2=_aaLen(b);
839         if (l1!=l2) return false;
840         size_t keysize=key.tsize();
841         equals_t same=true;
842         int res=_aaApply2(a, keysize, cast(dg2_t) delegate int(void *k, void *v){
843             void* v2=_aaGetRvalue(b, key, value.tsize(), k);
844             if (v2 is null || !value.equals(v,v2)) {
845                 same=false;
846                 return 1;
847             }
848             ++l1;
849             return 0;
850         });
851         return same;
852     }
853 
854     override int compare(in void* p1, in void* p2)
855     {
856         throw new Exception("non comparable",__FILE__,__LINE__);
857     }
858 
859     override TypeInfo next() { return value; }
860     override uint flags() { return 1; }
861     override PointerMap pointermap() { return exactpointer(); }
862 
863     TypeInfo value;
864     TypeInfo key;
865 
866     size_t talign()
867     {
868         return (char[int]).alignof;
869     }
870 
871     version (X86_64) override int argTypes(out TypeInfo arg1, out TypeInfo arg2)
872     {
873         arg1 = typeid(void*);
874         return 0;
875     }
876 }
877 
878 class TypeInfo_Function : TypeInfo
879 {
880     override char[] toString()
881     {
882         return next.toString() ~ "()";
883     }
884 
885     override equals_t opEquals(Object o)
886     {
887         TypeInfo_Function c;
888         return this is o ||
889                 ((c = cast(TypeInfo_Function)o) !is null &&
890                  this.next == c.next);
891     }
892 
893     // BUG: need to add the rest of the functions
894 
895     override size_t tsize()
896     {
897         return 0;       // no size for functions
898     }
899 
900     TypeInfo next;
901 }
902 
903 class TypeInfo_Delegate : TypeInfo
904 {
905     override char[] toString()
906     {
907         return (next.toString() ~ " delegate()");
908     }
909 
910     override equals_t opEquals(Object o)
911     {
912         TypeInfo_Delegate c;
913         return this is o ||
914                 ((c = cast(TypeInfo_Delegate)o) !is null &&
915                  this.next == c.next);
916     }
917 
918     override hash_t getHash(in void* p)
919     {
920         alias int delegate() dg;
921         return rt_hash_str(p,dg.sizeof,0);
922     }
923 
924     override equals_t equals(in void* p1, in void* p2)
925     {
926         alias int delegate() dg;
927         return memcmp(p1,p2,dg.sizeof);
928     }
929 
930     override size_t tsize()
931     {
932         alias int delegate() dg;
933         return dg.sizeof;
934     }
935 
936     override int compare(in void* p1, in void* p2)
937     {
938         alias int delegate() dg;
939         return memcmp(p1,p2,dg.sizeof);
940     }
941 
942     override uint flags() { return 1; }
943 
944     override PointerMap pointermap()
945     {
946         //return static mask for delegates
947         //  word 0: context pointer
948         //  word 1: function pointer (not scanned)
949         //work around for dmd bug #4397 (triggers infinite recursion)
950         static size_t[3] g_arr;
951         static PointerMap pm;
952         pm.bits = g_arr;
953         pm.bits[0] = 2;
954         pm.bits[1] = 0b01;
955         pm.bits[2] = 0b01; //moveable
956         return pm;
957     }
958 
959     TypeInfo next;
960 
961     size_t talign()
962     {
963         alias int delegate() dg;
964         return dg.alignof;
965     }
966 
967     version (X86_64) override int argTypes(out TypeInfo arg1, out TypeInfo arg2)
968     {   //arg1 = typeid(void*);
969         //arg2 = typeid(void*);
970         return 0;
971     }
972 
973 }
974 
975 class TypeInfo_Class : TypeInfo
976 {
977     override char[] toString() { return info.name; }
978 
979     override equals_t opEquals(Object o)
980     {
981         TypeInfo_Class c;
982         return this is o ||
983                 ((c = cast(TypeInfo_Class)o) !is null &&
984                  this.info.name == c.classinfo.name);
985     }
986 
987     override hash_t getHash(in void* p)
988     {
989         Object o = *cast(Object*)p;
990         return o ? o.toHash() : 0;
991     }
992 
993     override equals_t equals(in void* p1, in void* p2)
994     {
995         Object o1 = *cast(Object*)p1;
996         Object o2 = *cast(Object*)p2;
997 
998         return (o1 is o2) || (o1 && o1.opEquals(o2));
999     }
1000 
1001     override int compare(in void* p1, in void* p2)
1002     {
1003         Object o1 = *cast(Object*)p1;
1004         Object o2 = *cast(Object*)p2;
1005         int c = 0;
1006 
1007         // Regard null references as always being "less than"
1008         if (o1 !is o2)
1009         {
1010             if (o1)
1011             {
1012                 if (!o2)
1013                     c = 1;
1014                 else
1015                     c = o1.opCmp(o2);
1016             }
1017             else
1018                 c = -1;
1019         }
1020         return c;
1021     }
1022 
1023     override size_t tsize()
1024     {
1025         return Object.sizeof;
1026     }
1027 
1028     override uint flags() { return 1; }
1029     override PointerMap pointermap() { return exactpointer(); }
1030 
1031     override OffsetTypeInfo[] offTi()
1032     {
1033         return (info.flags & 4) ? info.offTi : null;
1034     }
1035 
1036     ClassInfo info;
1037 }
1038 
1039 class TypeInfo_Interface : TypeInfo
1040 {
1041     override char[] toString() { return info.name; }
1042 
1043     override equals_t opEquals(Object o)
1044     {
1045         TypeInfo_Interface c;
1046         return this is o ||
1047                 ((c = cast(TypeInfo_Interface)o) !is null &&
1048                  this.info.name == c.classinfo.name);
1049     }
1050 
1051     override hash_t getHash(in void* p)
1052     {
1053         Interface* pi = **cast(Interface ***)*cast(void**)p;
1054         Object o = cast(Object)(*cast(void**)p - pi.offset);
1055         assert(o);
1056         return o.toHash();
1057     }
1058 
1059     override equals_t equals(in void* p1, in void* p2)
1060     {
1061         Interface* pi = **cast(Interface ***)*cast(void**)p1;
1062         Object o1 = cast(Object)(*cast(void**)p1 - pi.offset);
1063         pi = **cast(Interface ***)*cast(void**)p2;
1064         Object o2 = cast(Object)(*cast(void**)p2 - pi.offset);
1065 
1066         return o1 == o2 || (o1 && o1.opCmp(o2) == 0);
1067     }
1068 
1069     override int compare(in void* p1, in void* p2)
1070     {
1071         Interface* pi = **cast(Interface ***)*cast(void**)p1;
1072         Object o1 = cast(Object)(*cast(void**)p1 - pi.offset);
1073         pi = **cast(Interface ***)*cast(void**)p2;
1074         Object o2 = cast(Object)(*cast(void**)p2 - pi.offset);
1075         int c = 0;
1076 
1077         // Regard null references as always being "less than"
1078         if (o1 != o2)
1079         {
1080             if (o1)
1081             {
1082                 if (!o2)
1083                     c = 1;
1084                 else
1085                     c = o1.opCmp(o2);
1086             }
1087             else
1088                 c = -1;
1089         }
1090         return c;
1091     }
1092 
1093     override size_t tsize()
1094     {
1095         return Object.sizeof;
1096     }
1097 
1098     override uint flags() { return 1; }
1099     override PointerMap pointermap() { return exactpointer(); }
1100 
1101     ClassInfo info;
1102 }
1103 
1104 class TypeInfo_Struct : TypeInfo
1105 {
1106     override char[] toString() { return name; }
1107 
1108     override equals_t opEquals(Object o)
1109     {
1110         TypeInfo_Struct s;
1111         return this is o ||
1112                 ((s = cast(TypeInfo_Struct)o) !is null &&
1113                  this.name == s.name &&
1114                  this.init.length == s.init.length);
1115     }
1116 
1117     override hash_t getHash(in void* p)
1118     {
1119         assert(p);
1120         if (xtoHash !is null)
1121         {
1122             debug(PRINTF) printf("getHash() using xtoHash\n");
1123             hash_t delegate() toHash;
1124             toHash.ptr = p;
1125             toHash.funcptr = cast(hash_t function())xtoHash;
1126             return toHash();
1127         }
1128         else
1129         {
1130             debug(PRINTF) printf("getHash() using default hash\n");
1131             // BUG: relies on the GC not moving objects
1132             return rt_hash_str(p,init.length,0);
1133         }
1134     }
1135 
1136     override equals_t equals(in void* p1, in void* p2)
1137     {
1138         if (p1 == p2)
1139             return true;
1140         else if (!p1 || !p2)
1141             return false;
1142         else if (xopEquals !is null) {
1143             int delegate(void*) opEquals;
1144             opEquals.ptr = p1;
1145             opEquals.funcptr = xopEquals;
1146             return opEquals(p2);
1147         } else
1148             // BUG: relies on the GC not moving objects
1149             return memcmp(p1, p2, init.length) == 0;
1150     }
1151 
1152     override int compare(in void* p1, in void* p2)
1153     {
1154         // Regard null references as always being "less than"
1155         if (p1 != p2)
1156         {
1157             if (p1)
1158             {
1159                 if (!p2)
1160                     return true;
1161                 else if (xopCmp !is null) {
1162                     int delegate(void*) opCmp;
1163                     opCmp.ptr = p1;
1164                     opCmp.funcptr = xopCmp;
1165                     return opCmp(p2);
1166                 } else
1167                     // BUG: relies on the GC not moving objects
1168                     return memcmp(p1, p2, init.length);
1169             }
1170             else
1171                 return -1;
1172         }
1173         return 0;
1174     }
1175 
1176     override size_t tsize()
1177     {
1178         return init.length;
1179     }
1180 
1181     override void[] init() { return m_init; }
1182 
1183     override uint flags() { return m_flags; }
1184 
1185     size_t talign() { return m_align; }
1186 
1187 
1188     char[] name;
1189     void[] m_init;      // initializer; init.ptr == null if 0 initialize
1190 
1191     // These are ONLY for use as a delegate.funcptr!
1192     hash_t function()   xtoHash;
1193     int function(void*) xopEquals;
1194     int function(void*) xopCmp;
1195     char[] function()   xtoString;
1196 
1197     uint m_flags;
1198     uint m_align;
1199 
1200     version (D_HavePointerMap) {
1201         PointerMap m_pointermap;
1202 
1203         override PointerMap pointermap() { return m_pointermap; }
1204     }
1205 
1206     version (X86_64)
1207     {
1208         int argTypes(out TypeInfo arg1, out TypeInfo arg2)
1209         {
1210             arg1 = m_arg1;
1211             arg2 = m_arg2;
1212             return 0;
1213         }
1214         TypeInfo m_arg1;
1215         TypeInfo m_arg2;
1216     }
1217 }
1218 
1219 class TypeInfo_Tuple : TypeInfo
1220 {
1221     TypeInfo[] elements;
1222 
1223     override char[] toString()
1224     {
1225         char[] s;
1226         s = "(";
1227         foreach (i, element; elements)
1228         {
1229             if (i)
1230                 s ~= ',';
1231             s ~= element.toString();
1232         }
1233         s ~= ")";
1234         return s;
1235     }
1236 
1237     override equals_t opEquals(Object o)
1238     {
1239         if (this is o)
1240             return true;
1241 
1242         auto t = cast(TypeInfo_Tuple)o;
1243         if (t && elements.length == t.elements.length)
1244         {
1245             for (size_t i = 0; i < elements.length; i++)
1246             {
1247                 if (elements[i] != t.elements[i])
1248                     return false;
1249             }
1250             return true;
1251         }
1252         return false;
1253     }
1254 
1255     override hash_t getHash(in void* p)
1256     {
1257         assert(0);
1258     }
1259 
1260     override equals_t equals(in void* p1, in void* p2)
1261     {
1262         assert(0);
1263     }
1264 
1265     override int compare(in void* p1, in void* p2)
1266     {
1267         assert(0);
1268     }
1269 
1270     override size_t tsize()
1271     {
1272         assert(0);
1273     }
1274 
1275     override void swap(void* p1, void* p2)
1276     {
1277         assert(0);
1278     }
1279 
1280     override PointerMap pointermap()
1281     {
1282         assert(0);
1283     }
1284 
1285     version (X86_64) int argTypes(out TypeInfo arg1, out TypeInfo arg2)
1286     {
1287         assert(0);
1288     }
1289 }
1290 
1291 
1292 ////////////////////////////////////////////////////////////////////////////////
1293 // Exception
1294 ////////////////////////////////////////////////////////////////////////////////
1295 class Exception : Object
1296 {
1297     struct FrameInfo{
1298         long line;
1299         size_t iframe;
1300         ptrdiff_t offsetSymb;
1301         size_t baseSymb;
1302         ptrdiff_t offsetImg;
1303         size_t baseImg;
1304         size_t address;
1305         char[] file;
1306         char[] func;
1307         char[] extra;
1308         bool exactAddress;
1309         bool internalFunction;
1310         alias void function(FrameInfo*,void delegate(char[])) FramePrintHandler;
1311         static FramePrintHandler defaultFramePrintingFunction;
1312         void writeOut(void delegate(char[])sink){
1313 
1314             if (defaultFramePrintingFunction){
1315                 defaultFramePrintingFunction(this,sink);
1316             } else {
1317                 // Imitate GDB backtrace format, something like:
1318                 // printf("#%-4td %p in %s (%s) at %s:%lld\n",
1319                 //     iframe, address, func, extra, file, line);
1320                 const M = 26;
1321                 char[M] buf;
1322                 auto len = snprintf(buf.ptr, M, "#%-4td ", this.iframe);
1323                 sink(buf[0..len]);
1324 
1325                 len = snprintf(buf.ptr, M, "%p", this.address);
1326                 sink(buf[0..len]);
1327 
1328                 sink(" in ");
1329                 sink(this.func.length ? this.func : "???");
1330                 sink(" (");
1331                 sink(this.extra);
1332                 sink(") at ");
1333 
1334                 sink(this.file);
1335                 sink(":");
1336 
1337                 len = snprintf(buf.ptr, M, "%zu", cast(size_t) this.line);
1338                 sink(buf[0..len]);
1339             }
1340         }
1341 
1342         void clear(){
1343             line=0;
1344             iframe=-1;
1345             offsetImg=0;
1346             baseImg=0;
1347             offsetSymb=0;
1348             baseSymb=0;
1349             address=0;
1350             exactAddress=true;
1351             internalFunction=false;
1352             file=null;
1353             func=null;
1354             extra=null;
1355         }
1356     }
1357     interface TraceInfo
1358     {
1359         int opApply( int delegate( ref FrameInfo fInfo ) );
1360         void writeOut(void delegate(char[])sink);
1361     }
1362 
1363     char[]      msg;
1364     char[]      file;
1365     size_t      line;  // long would be better
1366     TraceInfo   info;
1367     Exception   next;
1368 
1369     this( char[] msg, char[] file, long line, Exception next, TraceInfo info )
1370     {
1371         // main constructor, breakpoint this if you want...
1372         this.msg = msg;
1373         this.next = next;
1374         this.file = file;
1375         this.line = cast(size_t)line;
1376         this.info = info;
1377     }
1378 
1379     this( char[] msg, Exception next=null )
1380     {
1381         this(msg,"",0,next,rt_createTraceContext(null));
1382     }
1383 
1384     this( char[] msg, char[] file, long line, Exception next=null )
1385     {
1386         this(msg,file,line,next,rt_createTraceContext(null));
1387     }
1388 
1389     override char[] toString()
1390     {
1391         return msg;
1392     }
1393     void writeOutMsg(void delegate(char[])sink){
1394         sink(toString());
1395     }
1396     void writeOut(void delegate(char[])sink){
1397         if (file.length>0 || line!=0)
1398         {
1399             char[25]buf;
1400             sink(this.classinfo.name);
1401             sink("@");
1402             sink(file);
1403             sink("(");
1404             sink(ulongToUtf8(buf, line));
1405             sink("): ");
1406             writeOutMsg(sink);
1407             sink("\n");
1408         }
1409         else
1410         {
1411            sink(this.classinfo.name);
1412            sink(": ");
1413            writeOutMsg(sink);
1414            sink("\n");
1415         }
1416         if (info)
1417         {
1418             sink("----------------\n");
1419             info.writeOut(sink);
1420         }
1421         if (next){
1422             sink("\n++++++++++++++++\n");
1423             next.writeOut(sink);
1424         }
1425     }
1426 }
1427 
1428 
1429 alias Exception.TraceInfo function( void* ptr = null ) TraceHandler;
1430 private TraceHandler traceHandler = null;
1431 
1432 
1433 /**
1434  * Overrides the default trace hander with a user-supplied version.
1435  *
1436  * Params:
1437  *  h = The new trace handler.  Set to null to use the default handler.
1438  */
1439 extern (C) void  rt_setTraceHandler( TraceHandler h )
1440 {
1441     traceHandler = h;
1442 }
1443 
1444 /**
1445  * This function will be called when an Exception is constructed.  The
1446  * user-supplied trace handler will be called if one has been supplied,
1447  * otherwise no trace will be generated.
1448  *
1449  * Params:
1450  *  ptr = A pointer to the location from which to generate the trace, or null
1451  *        if the trace should be generated from within the trace handler
1452  *        itself.
1453  *
1454  * Returns:
1455  *  An object describing the current calling context or null if no handler is
1456  *  supplied.
1457  */
1458 extern(C) Exception.TraceInfo rt_createTraceContext( void* ptr ){
1459     if( traceHandler is null )
1460         return null;
1461     return traceHandler( ptr );
1462 }
1463 
1464 ////////////////////////////////////////////////////////////////////////////////
1465 // ModuleInfo
1466 ////////////////////////////////////////////////////////////////////////////////
1467 
1468 
1469 enum
1470 {
1471     MIctorstart  = 1,   // we've started constructing it
1472     MIctordone   = 2,   // finished construction
1473     MIstandalone = 4,   // module ctor does not depend on other module
1474                         // ctors being done first
1475     MIhasictor   = 8,   // has ictor member
1476 }
1477 
1478 
1479 class ModuleInfo
1480 {
1481     char[]          name;
1482     ModuleInfo[]    importedModules;
1483     ClassInfo[]     localClasses;
1484     uint            flags;
1485 
1486     void function() ctor;       // module static constructor (order dependent)
1487     void function() dtor;       // module static destructor
1488     void function() unitTest;   // module unit tests
1489 
1490     void* xgetMembers;          // module getMembers() function
1491 
1492     void function() ictor;      // module static constructor (order independent)
1493 
1494     static int opApply( int delegate( ref ModuleInfo ) dg )
1495     {
1496         int ret = 0;
1497 
1498         foreach( m; _moduleinfo_array )
1499         {
1500             ret = dg( m );
1501             if( ret )
1502                 break;
1503         }
1504         return ret;
1505     }
1506 }
1507 
1508 
1509 // Win32: this gets initialized by minit.asm
1510 // linux: this gets initialized in _moduleCtor()
1511 extern (C) ModuleInfo[] _moduleinfo_array;
1512 
1513 
1514 version (linux)
1515 {
1516     // This linked list is created by a compiler generated function inserted
1517     // into the .ctor list by the compiler.
1518     struct ModuleReference
1519     {
1520         ModuleReference* next;
1521         ModuleInfo       mod;
1522     }
1523 
1524     extern (C) ModuleReference* _Dmodule_ref;   // start of linked list
1525 }
1526 
1527 version( freebsd )
1528 {
1529     // This linked list is created by a compiler generated function inserted
1530     // into the .ctor list by the compiler.
1531     struct ModuleReference
1532     {
1533         ModuleReference* next;
1534         ModuleInfo mod;
1535      }
1536     extern (C) ModuleReference *_Dmodule_ref;   // start of linked list
1537 }
1538 
1539 ModuleInfo[] _moduleinfo_dtors;
1540 uint         _moduleinfo_dtors_i;
1541 
1542 // Register termination function pointers
1543 extern (C) int _fatexit(void *);
1544 
1545 /**
1546  * Initialize the modules.
1547  */
1548 
1549 extern (C) void _moduleCtor()
1550 {
1551     debug(PRINTF) printf("_moduleCtor()\n");
1552     version (linux)
1553     {
1554         int len = 0;
1555         ModuleReference *mr;
1556 
1557         for (mr = _Dmodule_ref; mr; mr = mr.next)
1558             len++;
1559         _moduleinfo_array = new ModuleInfo[len];
1560         len = 0;
1561         for (mr = _Dmodule_ref; mr; mr = mr.next)
1562         {   _moduleinfo_array[len] = mr.mod;
1563             len++;
1564         }
1565 
1566         debug(PRINTF) foreach (m; _moduleinfo_array)
1567         {
1568             //printf("\t%p\n", m);
1569             printf("\t%.*s\n", m.name.length,m.name.ptr);
1570         }
1571 
1572     }
1573 
1574     version( freebsd )
1575     {
1576         int len = 0;
1577         ModuleReference *mr;
1578 
1579         for (mr = _Dmodule_ref; mr; mr = mr.next)
1580             len++;
1581         _moduleinfo_array = new ModuleInfo[len];
1582         len = 0;
1583         for (mr = _Dmodule_ref; mr; mr = mr.next)
1584         {
1585             _moduleinfo_array[len] = mr.mod;
1586             len++;
1587         }
1588     }
1589 
1590     version( OSX )
1591     {
1592     /* The ModuleInfo references are stored in the special segment
1593      * __minfodata, which is bracketed by the segments __minfo_beg
1594      * and __minfo_end. The variables _minfo_beg and _minfo_end
1595      * are of zero size and are in the two bracketing segments,
1596      * respectively.
1597      *
1598      * The __minfo_beg and __minfo_end sections are not put into
1599      * dynamic libraries therefore we cannot use them or the
1600      * _minfo_beg and _minfo_end variables. Instead we loop through
1601      * all the loaded images (executables and dynamic libraries) and
1602      * collect all the ModuleInfo references.
1603      */
1604         _moduleinfo_array = getSectionData!(ModuleInfo, "__DATA", "__minfodata");
1605         debug(PRINTF) printf("moduleinfo: ptr = %p, length = %d\n", _moduleinfo_array.ptr, _moduleinfo_array.length);
1606 
1607         debug(PRINTF) foreach (m; _moduleinfo_array)
1608         {
1609             //printf("\t%p\n", m);
1610             printf("\t%.*s\n", m.name.length,m.name.ptr);
1611         }
1612     }
1613 
1614     version (Win32)
1615     {
1616         // Ensure module destructors also get called on program termination
1617         //_fatexit(&_STD_moduleDtor);
1618     }
1619 
1620     _moduleinfo_dtors = new ModuleInfo[_moduleinfo_array.length];
1621     debug(PRINTF) printf("_moduleinfo_dtors = x%x\n", cast(void*)_moduleinfo_dtors);
1622     _moduleIndependentCtors();
1623     _moduleCtor2(null,_moduleinfo_array, 0);
1624 }
1625 
1626 extern (C) void _moduleIndependentCtors()
1627 {
1628     debug(PRINTF) printf("_moduleIndependentCtors()\n");
1629     foreach (m; _moduleinfo_array)
1630     {
1631         if (m && m.flags & MIhasictor && m.ictor)
1632         {
1633             (*m.ictor)();
1634         }
1635     }
1636 }
1637 
1638 void _moduleCtor2(ModuleInfo from, ModuleInfo[] mi, int skip)
1639 {
1640     debug(PRINTF) printf("_moduleCtor2(): %d modules\n", mi.length);
1641     for (uint i = 0; i < mi.length; i++)
1642     {
1643         ModuleInfo m = mi[i];
1644 
1645         debug(PRINTF) printf("\tmodule[%d] = '%p'\n", i, m);
1646         if (!m)
1647             continue;
1648         debug(PRINTF) printf("\tmodule[%d].name = '%s'\n", i, m.name);
1649         if (m.flags & MIctordone)
1650             continue;
1651         debug(PRINTF) printf("\tmodule[%d] = '%.*s', m = x%x\n", i, m.name, m);
1652 
1653         if (m.ctor || m.dtor)
1654         {
1655             if (m.flags & MIctorstart)
1656             {   if (skip || m.flags & MIstandalone)
1657                     continue;
1658                 throw new Exception( "Cyclic dependency in module " ~ (from is null ? "*null*" : from.name) ~ " for import " ~ m.name);
1659             }
1660 
1661             m.flags |= MIctorstart;
1662             _moduleCtor2(m,m.importedModules, 0);
1663             if (m.ctor)
1664                 (*m.ctor)();
1665             m.flags &= ~MIctorstart;
1666             m.flags |= MIctordone;
1667 
1668             // Now that construction is done, register the destructor
1669             //printf("\tadding module dtor x%x\n", m);
1670             assert(_moduleinfo_dtors_i < _moduleinfo_dtors.length);
1671             _moduleinfo_dtors[_moduleinfo_dtors_i++] = m;
1672         }
1673         else
1674         {
1675             m.flags |= MIctordone;
1676             _moduleCtor2(m,m.importedModules, 1);
1677         }
1678     }
1679 }
1680 
1681 /**
1682  * Destruct the modules.
1683  */
1684 
1685 // Starting the name with "_STD" means under linux a pointer to the
1686 // function gets put in the .dtors segment.
1687 
1688 extern (C) void _moduleDtor()
1689 {
1690     debug(PRINTF) printf("_moduleDtor(): %d modules\n", _moduleinfo_dtors_i);
1691 
1692     for (uint i = _moduleinfo_dtors_i; i-- != 0;)
1693     {
1694         ModuleInfo m = _moduleinfo_dtors[i];
1695 
1696         debug(PRINTF) printf("\tmodule[%d] = '%.*s', x%x\n", i, m.name, m);
1697         if (m.dtor)
1698         {
1699             (*m.dtor)();
1700         }
1701     }
1702     debug(PRINTF) printf("_moduleDtor() done\n");
1703 }
1704 
1705 ////////////////////////////////////////////////////////////////////////////////
1706 // Monitor
1707 ////////////////////////////////////////////////////////////////////////////////
1708 
1709 alias Object.Monitor        IMonitor;
1710 alias void delegate(Object) DEvent;
1711 
1712 // NOTE: The dtor callback feature is only supported for monitors that are not
1713 //       supplied by the user.  The assumption is that any object with a user-
1714 //       supplied monitor may have special storage or lifetime requirements and
1715 //       that as a result, storing references to local objects within Monitor
1716 //       may not be safe or desirable.  Thus, devt is only valid if impl is
1717 //       null.
1718 struct Monitor
1719 {
1720     IMonitor impl;
1721     /* internal */
1722     DEvent[] devt;
1723     /* stuff */
1724 }
1725 
1726 Monitor* getMonitor(Object h)
1727 {
1728     return cast(Monitor*) (cast(void**) h)[1];
1729 }
1730 
1731 void setMonitor(Object h, Monitor* m)
1732 {
1733     (cast(void**) h)[1] = m;
1734 }
1735 
1736 extern (C) void _d_monitor_create(Object);
1737 extern (C) void _d_monitor_destroy(Object);
1738 extern (C) void _d_monitor_lock(Object);
1739 extern (C) int  _d_monitor_unlock(Object);
1740 
1741 extern (C) void _d_monitordelete(Object h, bool det)
1742 {
1743     Monitor* m = getMonitor(h);
1744 
1745     if (m !is null)
1746     {
1747         IMonitor i = m.impl;
1748         if (i is null)
1749         {
1750             _d_monitor_devt(m, h);
1751             _d_monitor_destroy(h);
1752             setMonitor(h, null);
1753             return;
1754         }
1755         if (det && (cast(void*) i) !is (cast(void*) h))
1756             delete i;
1757         setMonitor(h, null);
1758     }
1759 }
1760 
1761 extern (C) void _d_monitorenter(Object h)
1762 {
1763     Monitor* m = getMonitor(h);
1764 
1765     if (m is null)
1766     {
1767         _d_monitor_create(h);
1768         m = getMonitor(h);
1769     }
1770 
1771     IMonitor i = m.impl;
1772 
1773     if (i is null)
1774     {
1775         _d_monitor_lock(h);
1776         return;
1777     }
1778     i.lock();
1779 }
1780 
1781 extern (C) void _d_monitorexit(Object h)
1782 {
1783     Monitor* m = getMonitor(h);
1784     IMonitor i = m.impl;
1785 
1786     if (i is null)
1787     {
1788         _d_monitor_unlock(h);
1789         return;
1790     }
1791     i.unlock();
1792 }
1793 
1794 extern (C) void _d_monitor_devt(Monitor* m, Object h)
1795 {
1796     if (m.devt.length)
1797     {
1798         DEvent[] devt;
1799 
1800         synchronized (h)
1801         {
1802             devt = m.devt;
1803             m.devt = null;
1804         }
1805         foreach (v; devt)
1806         {
1807             if (v)
1808                 v(h);
1809         }
1810         free(devt.ptr);
1811     }
1812 }
1813 
1814 extern (C) void rt_attachDisposeEvent(Object h, DEvent e)
1815 {
1816     synchronized (h)
1817     {
1818         Monitor* m = getMonitor(h);
1819         assert(m.impl is null);
1820 
1821         foreach (ref v; m.devt)
1822         {
1823             if (v is null || v == e)
1824             {
1825                 v = e;
1826                 return;
1827             }
1828         }
1829 
1830         auto len = m.devt.length + 4; // grow by 4 elements
1831         auto pos = m.devt.length;     // insert position
1832         auto p = realloc(m.devt.ptr, DEvent.sizeof * len);
1833         if (!p)
1834             onOutOfMemoryError();
1835         m.devt = (cast(DEvent*)p)[0 .. len];
1836         m.devt[pos+1 .. len] = null;
1837         m.devt[pos] = e;
1838     }
1839 }
1840 
1841 extern (C) bool rt_detachDisposeEvent(Object h, DEvent e)
1842 {
1843     synchronized (h)
1844     {
1845         return rt_detachDisposeEventNoLock(h, e);
1846     }
1847 }
1848 
1849 extern (C) bool rt_detachDisposeEventNoLock(Object h, DEvent e)
1850 {
1851     Monitor* m = getMonitor(h);
1852     assert(m.impl is null);
1853 
1854     foreach (p, v; m.devt)
1855     {
1856         if (v == e)
1857         {
1858             memmove(&m.devt[p],
1859                     &m.devt[p+1],
1860                     (m.devt.length - p - 1) * DEvent.sizeof);
1861             m.devt[$ - 1] = null;
1862             return true;
1863         }
1864     }
1865     return false;
1866 }