comparison runtime/internal/genobj.d @ 443:44f08170f4ef

Removed tango from the repository and instead added a runtime dir with the files needed to patch and build tango from svn. Reworked the LLVMDC specific pragmas.
author Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
date Fri, 01 Aug 2008 00:32:06 +0200
parents
children eef8ac26c66c
comparison
equal deleted inserted replaced
442:76078c8ab5b9 443:44f08170f4ef
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 * Modified by Tomas Lindquist Olsen <tomas@famolsen.dk> for use with LLVMDC.
37 */
38
39 module object;
40
41 //debug=PRINTF
42
43 private
44 {
45 import tango.stdc.string; // : memcmp, memcpy, memmove;
46 import tango.stdc.stdlib; // : calloc, realloc, free;
47 import util.string;
48 debug(PRINTF) import tango.stdc.stdio; // : printf;
49
50 extern (C) void onOutOfMemoryError();
51 extern (C) Object _d_newclass(ClassInfo ci);
52 }
53
54 // NOTE: For some reason, this declaration method doesn't work
55 // in this particular file (and this file only). It must
56 // be a DMD thing.
57 //alias typeof(int.sizeof) size_t;
58 //alias typeof(cast(void*)0 - cast(void*)0) ptrdiff_t;
59
60 version( LLVM64 )
61 {
62 alias ulong size_t;
63 alias long ptrdiff_t;
64 }
65 else
66 {
67 alias uint size_t;
68 alias int ptrdiff_t;
69 }
70
71 alias size_t hash_t;
72
73 /**
74 * All D class objects inherit from Object.
75 */
76 class Object
77 {
78 /**
79 * Convert Object to a human readable string.
80 */
81 char[] toString()
82 {
83 return this.classinfo.name;
84 }
85
86 /**
87 * Compute hash function for Object.
88 */
89 hash_t toHash()
90 {
91 // BUG: this prevents a compacting GC from working, needs to be fixed
92 return cast(hash_t)cast(void*)this;
93 }
94
95 /**
96 * Compare with another Object obj.
97 * Returns:
98 * $(TABLE
99 * $(TR $(TD this &lt; obj) $(TD &lt; 0))
100 * $(TR $(TD this == obj) $(TD 0))
101 * $(TR $(TD this &gt; obj) $(TD &gt; 0))
102 * )
103 */
104 int opCmp(Object o)
105 {
106 // BUG: this prevents a compacting GC from working, needs to be fixed
107 //return cast(int)cast(void*)this - cast(int)cast(void*)o;
108
109 //throw new Exception("need opCmp for class " ~ this.classinfo.name);
110 return this !is o;
111 }
112
113 /**
114 * Returns !=0 if this object does have the same contents as obj.
115 */
116 int opEquals(Object o)
117 {
118 return cast(int)(this is o);
119 }
120
121 interface Monitor
122 {
123 void lock();
124 void unlock();
125 }
126 }
127
128 /**
129 * Information about an interface.
130 * When an object is accessed via an interface, an Interface* appears as the
131 * first entry in its vtbl.
132 */
133 struct Interface
134 {
135 ClassInfo classinfo; /// .classinfo for this interface (not for containing class)
136 void*[] vtbl;
137 ptrdiff_t offset; /// offset to Interface 'this' from Object 'this'
138 }
139
140 /**
141 * Runtime type information about a class. Can be retrieved for any class type
142 * or instance by using the .classinfo property.
143 * A pointer to this appears as the first entry in the class's vtbl[].
144 */
145 class ClassInfo : Object
146 {
147 byte[] init; /** class static initializer
148 * (init.length gives size in bytes of class)
149 */
150 char[] name; /// class name
151 void*[] vtbl; /// virtual function pointer table
152 Interface[] interfaces; /// interfaces this class implements
153 ClassInfo base; /// base class
154 void* destructor;
155 void function(Object) classInvariant;
156 uint flags;
157 // 1: // IUnknown
158 // 2: // has no possible pointers into GC memory
159 // 4: // has offTi[] member
160 // 8: // has constructors
161 void* deallocator;
162 OffsetTypeInfo[] offTi;
163 void function(Object) defaultConstructor; // default Constructor
164
165 /**
166 * Search all modules for ClassInfo corresponding to classname.
167 * Returns: null if not found
168 */
169 static ClassInfo find(char[] classname)
170 {
171 foreach (m; ModuleInfo)
172 {
173 //writefln("module %s, %d", m.name, m.localClasses.length);
174 foreach (c; m.localClasses)
175 {
176 //writefln("\tclass %s", c.name);
177 if (c.name == classname)
178 return c;
179 }
180 }
181 return null;
182 }
183
184 /**
185 * Create instance of Object represented by 'this'.
186 */
187 Object create()
188 {
189 if (flags & 8 && !defaultConstructor)
190 return null;
191 Object o = _d_newclass(this);
192 if (flags & 8 && defaultConstructor)
193 {
194 defaultConstructor(o);
195 }
196 return o;
197 }
198 }
199
200 /**
201 * Array of pairs giving the offset and type information for each
202 * member in an aggregate.
203 */
204 struct OffsetTypeInfo
205 {
206 size_t offset; /// Offset of member from start of object
207 TypeInfo ti; /// TypeInfo for this member
208 }
209
210 /**
211 * Runtime type information about a type.
212 * Can be retrieved for any type using a
213 * <a href="../expression.html#typeidexpression">TypeidExpression</a>.
214 */
215 class TypeInfo
216 {
217 hash_t toHash()
218 { hash_t hash;
219
220 foreach (char c; this.toString())
221 hash = hash * 9 + c;
222 return hash;
223 }
224
225 int opCmp(Object o)
226 {
227 if (this is o)
228 return 0;
229 TypeInfo ti = cast(TypeInfo)o;
230 if (ti is null)
231 return 1;
232 return stringCompare(this.toString(), ti.toString());
233 }
234
235 int opEquals(Object o)
236 {
237 /* TypeInfo instances are singletons, but duplicates can exist
238 * across DLL's. Therefore, comparing for a name match is
239 * sufficient.
240 */
241 if (this is o)
242 return 1;
243 TypeInfo ti = cast(TypeInfo)o;
244 return cast(int)(ti && this.toString() == ti.toString());
245 }
246
247 /// Returns a hash of the instance of a type.
248 hash_t getHash(void *p) { return cast(hash_t)p; }
249
250 /// Compares two instances for equality.
251 int equals(void *p1, void *p2) { return cast(int)(p1 == p2); }
252
253 /// Compares two instances for &lt;, ==, or &gt;.
254 int compare(void *p1, void *p2) { return 0; }
255
256 /// Returns size of the type.
257 size_t tsize() { return 0; }
258
259 /// Swaps two instances of the type.
260 void swap(void *p1, void *p2)
261 {
262 size_t n = tsize();
263 for (size_t i = 0; i < n; i++)
264 { byte t;
265
266 t = (cast(byte *)p1)[i];
267 (cast(byte *)p1)[i] = (cast(byte *)p2)[i];
268 (cast(byte *)p2)[i] = t;
269 }
270 }
271
272 /// Get TypeInfo for 'next' type, as defined by what kind of type this is,
273 /// null if none.
274 TypeInfo next() { return null; }
275
276 /// Return default initializer, null if default initialize to 0
277 void[] init() { return null; }
278
279 /// Get flags for type: 1 means GC should scan for pointers
280 uint flags() { return 0; }
281
282 /// Get type information on the contents of the type; null if not available
283 OffsetTypeInfo[] offTi() { return null; }
284 }
285
286 class TypeInfo_Typedef : TypeInfo
287 {
288 char[] toString() { return name; }
289
290 int opEquals(Object o)
291 { TypeInfo_Typedef c;
292
293 return cast(int)
294 (this is o ||
295 ((c = cast(TypeInfo_Typedef)o) !is null &&
296 this.name == c.name &&
297 this.base == c.base));
298 }
299
300 hash_t getHash(void *p) { return base.getHash(p); }
301 int equals(void *p1, void *p2) { return base.equals(p1, p2); }
302 int compare(void *p1, void *p2) { return base.compare(p1, p2); }
303 size_t tsize() { return base.tsize(); }
304 void swap(void *p1, void *p2) { return base.swap(p1, p2); }
305
306 TypeInfo next() { return base; }
307 uint flags() { return base.flags(); }
308 void[] init() { return m_init.length ? m_init : base.init(); }
309
310 TypeInfo base;
311 char[] name;
312 void[] m_init;
313 }
314
315 class TypeInfo_Enum : TypeInfo_Typedef
316 {
317 }
318
319 class TypeInfo_Pointer : TypeInfo
320 {
321 char[] toString() { return m_next.toString() ~ "*"; }
322
323 int opEquals(Object o)
324 { TypeInfo_Pointer c;
325
326 return this is o ||
327 ((c = cast(TypeInfo_Pointer)o) !is null &&
328 this.m_next == c.m_next);
329 }
330
331 hash_t getHash(void *p)
332 {
333 return cast(hash_t)*cast(void**)p;
334 }
335
336 int equals(void *p1, void *p2)
337 {
338 return cast(int)(*cast(void* *)p1 == *cast(void* *)p2);
339 }
340
341 int compare(void *p1, void *p2)
342 {
343 if (*cast(void* *)p1 < *cast(void* *)p2)
344 return -1;
345 else if (*cast(void* *)p1 > *cast(void* *)p2)
346 return 1;
347 else
348 return 0;
349 }
350
351 size_t tsize()
352 {
353 return (void*).sizeof;
354 }
355
356 void swap(void *p1, void *p2)
357 { void* tmp;
358 tmp = *cast(void**)p1;
359 *cast(void**)p1 = *cast(void**)p2;
360 *cast(void**)p2 = tmp;
361 }
362
363 TypeInfo next() { return m_next; }
364 uint flags() { return 1; }
365
366 TypeInfo m_next;
367 }
368
369 class TypeInfo_Array : TypeInfo
370 {
371 char[] toString() { return value.toString() ~ "[]"; }
372
373 int opEquals(Object o)
374 { TypeInfo_Array c;
375
376 return cast(int)
377 (this is o ||
378 ((c = cast(TypeInfo_Array)o) !is null &&
379 this.value == c.value));
380 }
381
382 hash_t getHash(void *p)
383 { size_t sz = value.tsize();
384 hash_t hash = 0;
385 void[] a = *cast(void[]*)p;
386 for (size_t i = 0; i < a.length; i++)
387 hash += value.getHash(a.ptr + i * sz);
388 return hash;
389 }
390
391 int equals(void *p1, void *p2)
392 {
393 void[] a1 = *cast(void[]*)p1;
394 void[] a2 = *cast(void[]*)p2;
395 if (a1.length != a2.length)
396 return 0;
397 size_t sz = value.tsize();
398 for (size_t i = 0; i < a1.length; i++)
399 {
400 if (!value.equals(a1.ptr + i * sz, a2.ptr + i * sz))
401 return 0;
402 }
403 return 1;
404 }
405
406 int compare(void *p1, void *p2)
407 {
408 void[] a1 = *cast(void[]*)p1;
409 void[] a2 = *cast(void[]*)p2;
410 size_t sz = value.tsize();
411 size_t len = a1.length;
412
413 if (a2.length < len)
414 len = a2.length;
415 for (size_t u = 0; u < len; u++)
416 {
417 int result = value.compare(a1.ptr + u * sz, a2.ptr + u * sz);
418 if (result)
419 return result;
420 }
421 return cast(int)a1.length - cast(int)a2.length;
422 }
423
424 size_t tsize()
425 {
426 return (void[]).sizeof;
427 }
428
429 void swap(void *p1, void *p2)
430 { void[] tmp;
431 tmp = *cast(void[]*)p1;
432 *cast(void[]*)p1 = *cast(void[]*)p2;
433 *cast(void[]*)p2 = tmp;
434 }
435
436 TypeInfo value;
437
438 TypeInfo next()
439 {
440 return value;
441 }
442
443 uint flags() { return 1; }
444 }
445
446 class TypeInfo_StaticArray : TypeInfo
447 {
448 char[] toString()
449 {
450 char [10] tmp = void;
451 return value.toString() ~ "[" ~ intToUtf8(tmp, len) ~ "]";
452 }
453
454 int opEquals(Object o)
455 { TypeInfo_StaticArray c;
456
457 return cast(int)
458 (this is o ||
459 ((c = cast(TypeInfo_StaticArray)o) !is null &&
460 this.len == c.len &&
461 this.value == c.value));
462 }
463
464 hash_t getHash(void *p)
465 { size_t sz = value.tsize();
466 hash_t hash = 0;
467 for (size_t i = 0; i < len; i++)
468 hash += value.getHash(p + i * sz);
469 return hash;
470 }
471
472 int equals(void *p1, void *p2)
473 {
474 size_t sz = value.tsize();
475
476 for (size_t u = 0; u < len; u++)
477 {
478 if (!value.equals(p1 + u * sz, p2 + u * sz))
479 return 0;
480 }
481 return 1;
482 }
483
484 int compare(void *p1, void *p2)
485 {
486 size_t sz = value.tsize();
487
488 for (size_t u = 0; u < len; u++)
489 {
490 int result = value.compare(p1 + u * sz, p2 + u * sz);
491 if (result)
492 return result;
493 }
494 return 0;
495 }
496
497 size_t tsize()
498 {
499 return len * value.tsize();
500 }
501
502 void swap(void *p1, void *p2)
503 { void* tmp;
504 size_t sz = value.tsize();
505 ubyte[16] buffer;
506 void* pbuffer;
507
508 if (sz < buffer.sizeof)
509 tmp = buffer.ptr;
510 else
511 tmp = pbuffer = (new void[sz]).ptr;
512
513 for (size_t u = 0; u < len; u += sz)
514 { size_t o = u * sz;
515 memcpy(tmp, p1 + o, sz);
516 memcpy(p1 + o, p2 + o, sz);
517 memcpy(p2 + o, tmp, sz);
518 }
519 if (pbuffer)
520 delete pbuffer;
521 }
522
523 void[] init() { return value.init(); }
524 TypeInfo next() { return value; }
525 uint flags() { return value.flags(); }
526
527 TypeInfo value;
528 size_t len;
529 }
530
531 class TypeInfo_AssociativeArray : TypeInfo
532 {
533 char[] toString()
534 {
535 return next.toString() ~ "[" ~ key.toString() ~ "]";
536 }
537
538 int opEquals(Object o)
539 { TypeInfo_AssociativeArray c;
540
541 return this is o ||
542 ((c = cast(TypeInfo_AssociativeArray)o) !is null &&
543 this.key == c.key &&
544 this.value == c.value);
545 }
546
547 // BUG: need to add the rest of the functions
548
549 size_t tsize()
550 {
551 return (char[int]).sizeof;
552 }
553
554 TypeInfo next() { return value; }
555 uint flags() { return 1; }
556
557 TypeInfo value;
558 TypeInfo key;
559 }
560
561 class TypeInfo_Function : TypeInfo
562 {
563 char[] toString()
564 {
565 return next.toString() ~ "()";
566 }
567
568 int opEquals(Object o)
569 { TypeInfo_Function c;
570
571 return this is o ||
572 ((c = cast(TypeInfo_Function)o) !is null &&
573 this.next == c.next);
574 }
575
576 // BUG: need to add the rest of the functions
577
578 size_t tsize()
579 {
580 return 0; // no size for functions
581 }
582
583 TypeInfo next;
584 }
585
586 class TypeInfo_Delegate : TypeInfo
587 {
588 char[] toString()
589 {
590 return next.toString() ~ " delegate()";
591 }
592
593 int opEquals(Object o)
594 { TypeInfo_Delegate c;
595
596 return this is o ||
597 ((c = cast(TypeInfo_Delegate)o) !is null &&
598 this.next == c.next);
599 }
600
601 // BUG: need to add the rest of the functions
602
603 size_t tsize()
604 { alias int delegate() dg;
605 return dg.sizeof;
606 }
607
608 uint flags() { return 1; }
609
610 TypeInfo next;
611 }
612
613 class TypeInfo_Class : TypeInfo
614 {
615 char[] toString() { return info.name; }
616
617 int opEquals(Object o)
618 { TypeInfo_Class c;
619
620 return this is o ||
621 ((c = cast(TypeInfo_Class)o) !is null &&
622 this.info.name == c.classinfo.name);
623 }
624
625 hash_t getHash(void *p)
626 {
627 Object o = *cast(Object*)p;
628 return o ? o.toHash() : 0;
629 }
630
631 int equals(void *p1, void *p2)
632 {
633 Object o1 = *cast(Object*)p1;
634 Object o2 = *cast(Object*)p2;
635
636 return (o1 is o2) || (o1 && o1.opEquals(o2));
637 }
638
639 int compare(void *p1, void *p2)
640 {
641 Object o1 = *cast(Object*)p1;
642 Object o2 = *cast(Object*)p2;
643 int c = 0;
644
645 // Regard null references as always being "less than"
646 if (o1 !is o2)
647 {
648 if (o1)
649 { if (!o2)
650 c = 1;
651 else
652 c = o1.opCmp(o2);
653 }
654 else
655 c = -1;
656 }
657 return c;
658 }
659
660 size_t tsize()
661 {
662 return Object.sizeof;
663 }
664
665 uint flags() { return 1; }
666
667 OffsetTypeInfo[] offTi()
668 {
669 return (info.flags & 4) ? info.offTi : null;
670 }
671
672 ClassInfo info;
673 }
674
675 class TypeInfo_Interface : TypeInfo
676 {
677 char[] toString() { return info.name; }
678
679 int opEquals(Object o)
680 { TypeInfo_Interface c;
681
682 return this is o ||
683 ((c = cast(TypeInfo_Interface)o) !is null &&
684 this.info.name == c.classinfo.name);
685 }
686
687 hash_t getHash(void *p)
688 {
689 Interface* pi = **cast(Interface ***)*cast(void**)p;
690 Object o = cast(Object)(*cast(void**)p - pi.offset);
691 assert(o);
692 return o.toHash();
693 }
694
695 int equals(void *p1, void *p2)
696 {
697 Interface* pi = **cast(Interface ***)*cast(void**)p1;
698 Object o1 = cast(Object)(*cast(void**)p1 - pi.offset);
699 pi = **cast(Interface ***)*cast(void**)p2;
700 Object o2 = cast(Object)(*cast(void**)p2 - pi.offset);
701
702 return o1 == o2 || (o1 && o1.opCmp(o2) == 0);
703 }
704
705 int compare(void *p1, void *p2)
706 {
707 Interface* pi = **cast(Interface ***)*cast(void**)p1;
708 Object o1 = cast(Object)(*cast(void**)p1 - pi.offset);
709 pi = **cast(Interface ***)*cast(void**)p2;
710 Object o2 = cast(Object)(*cast(void**)p2 - pi.offset);
711 int c = 0;
712
713 // Regard null references as always being "less than"
714 if (o1 != o2)
715 {
716 if (o1)
717 { if (!o2)
718 c = 1;
719 else
720 c = o1.opCmp(o2);
721 }
722 else
723 c = -1;
724 }
725 return c;
726 }
727
728 size_t tsize()
729 {
730 return Object.sizeof;
731 }
732
733 uint flags() { return 1; }
734
735 ClassInfo info;
736 }
737
738 class TypeInfo_Struct : TypeInfo
739 {
740 char[] toString() { return name; }
741
742 int opEquals(Object o)
743 { TypeInfo_Struct s;
744
745 return this is o ||
746 ((s = cast(TypeInfo_Struct)o) !is null &&
747 this.name == s.name &&
748 this.init.length == s.init.length);
749 }
750
751 hash_t getHash(void *p)
752 { hash_t h;
753
754 assert(p);
755 if (xtoHash)
756 { debug(PRINTF) printf("getHash() using xtoHash\n");
757 h = (*xtoHash)(p);
758 }
759 else
760 {
761 debug(PRINTF) printf("getHash() using default hash\n");
762 // A sorry hash algorithm.
763 // Should use the one for strings.
764 // BUG: relies on the GC not moving objects
765 for (size_t i = 0; i < m_init.length; i++)
766 { h = h * 9 + *cast(ubyte*)p;
767 p++;
768 }
769 }
770 return h;
771 }
772
773 int equals(void *p1, void *p2)
774 { int c;
775
776 if (p1 == p2)
777 c = 1;
778 else if (!p1 || !p2)
779 c = 0;
780 else if (xopEquals)
781 c = (*xopEquals)(p1, p2);
782 else
783 // BUG: relies on the GC not moving objects
784 c = (memcmp(p1, p2, m_init.length) == 0);
785 return c;
786 }
787
788 int compare(void *p1, void *p2)
789 {
790 int c = 0;
791
792 // Regard null references as always being "less than"
793 if (p1 != p2)
794 {
795 if (p1)
796 { if (!p2)
797 c = 1;
798 else if (xopCmp)
799 c = (*xopCmp)(p1, p2);
800 else
801 // BUG: relies on the GC not moving objects
802 c = memcmp(p1, p2, m_init.length);
803 }
804 else
805 c = -1;
806 }
807 return c;
808 }
809
810 size_t tsize()
811 {
812 return m_init.length;
813 }
814
815 void[] init() { return m_init; }
816
817 uint flags() { return m_flags; }
818
819 char[] name;
820 void[] m_init; // initializer; never null
821
822 hash_t function(void*) xtoHash;
823 int function(void*,void*) xopEquals;
824 int function(void*,void*) xopCmp;
825 char[] function(void*) xtoString;
826
827 uint m_flags;
828 }
829
830 class TypeInfo_Tuple : TypeInfo
831 {
832 TypeInfo[] elements;
833
834 char[] toString()
835 {
836 char[] s;
837 s = "(";
838 foreach (i, element; elements)
839 {
840 if (i)
841 s ~= ',';
842 s ~= element.toString();
843 }
844 s ~= ")";
845 return s;
846 }
847
848 int opEquals(Object o)
849 {
850 if (this is o)
851 return 1;
852
853 auto t = cast(TypeInfo_Tuple)o;
854 if (t && elements.length == t.elements.length)
855 {
856 for (size_t i = 0; i < elements.length; i++)
857 {
858 if (elements[i] != t.elements[i])
859 return 0;
860 }
861 return 1;
862 }
863 return 0;
864 }
865
866 hash_t getHash(void *p)
867 {
868 assert(0);
869 }
870
871 int equals(void *p1, void *p2)
872 {
873 assert(0);
874 }
875
876 int compare(void *p1, void *p2)
877 {
878 assert(0);
879 }
880
881 size_t tsize()
882 {
883 assert(0);
884 }
885
886 void swap(void *p1, void *p2)
887 {
888 assert(0);
889 }
890 }
891
892
893 ////////////////////////////////////////////////////////////////////////////////
894 // Exception
895 ////////////////////////////////////////////////////////////////////////////////
896
897
898 class Exception : Object
899 {
900 interface TraceInfo
901 {
902 int opApply( int delegate( inout char[] ) );
903 }
904
905 char[] msg;
906 char[] file;
907 size_t line;
908 TraceInfo info;
909 Exception next;
910
911 this( char[] msg, Exception next = null )
912 {
913 this.msg = msg;
914 this.next = next;
915 this.info = traceContext();
916 }
917
918 this( char[] msg, char[] file, size_t line, Exception next = null )
919 {
920 this(msg, next);
921 this.file = file;
922 this.line = line;
923 this.info = traceContext();
924 }
925
926 char[] toString()
927 {
928 return msg;
929 }
930 }
931
932
933 alias Exception.TraceInfo function( void* ptr = null ) TraceHandler;
934 private TraceHandler traceHandler = null;
935
936
937 /**
938 * Overrides the default trace hander with a user-supplied version.
939 *
940 * Params:
941 * h = The new trace handler. Set to null to use the default handler.
942 */
943 extern (C) void rt_setTraceHandler( TraceHandler h )
944 {
945 traceHandler = h;
946 }
947
948
949 /**
950 * This function will be called when an Exception is constructed. The
951 * user-supplied trace handler will be called if one has been supplied,
952 * otherwise no trace will be generated.
953 *
954 * Params:
955 * ptr = A pointer to the location from which to generate the trace, or null
956 * if the trace should be generated from within the trace handler
957 * itself.
958 *
959 * Returns:
960 * An object describing the current calling context or null if no handler is
961 * supplied.
962 */
963 Exception.TraceInfo traceContext( void* ptr = null )
964 {
965 if( traceHandler is null )
966 return null;
967 return traceHandler( ptr );
968 }
969
970
971 ////////////////////////////////////////////////////////////////////////////////
972 // ModuleInfo
973 ////////////////////////////////////////////////////////////////////////////////
974
975
976 enum
977 {
978 MIctorstart = 1, // we've started constructing it
979 MIctordone = 2, // finished construction
980 MIstandalone = 4, // module ctor does not depend on other module
981 // ctors being done first
982 MIhasictor = 8, // has ictor member
983 }
984
985
986 class ModuleInfo
987 {
988 char[] name;
989 ModuleInfo[] importedModules;
990 ClassInfo[] localClasses;
991 uint flags;
992
993 void function() ctor; // module static constructor (order dependent)
994 void function() dtor; // module static destructor
995 void function() unitTest; // module unit tests
996
997 void* xgetMembers; // module getMembers() function
998
999 void function() ictor; // module static constructor (order independent)
1000
1001 static int opApply( int delegate( inout ModuleInfo ) dg )
1002 {
1003 int ret = 0;
1004
1005 foreach( m; _moduleinfo_array )
1006 {
1007 ret = dg( m );
1008 if( ret )
1009 break;
1010 }
1011 return ret;
1012 }
1013 }
1014
1015
1016 // this gets initialized in _moduleCtor()
1017 extern (C) ModuleInfo[] _moduleinfo_array;
1018
1019 // This linked list is created by a compiler generated function inserted
1020 // into the .ctor list by the compiler.
1021 struct ModuleReference
1022 {
1023 ModuleReference* next;
1024 ModuleInfo mod;
1025 }
1026 extern (C) ModuleReference* _Dmodule_ref; // start of linked list
1027
1028 // this list is built from the linked list above
1029 ModuleInfo[] _moduleinfo_dtors;
1030 uint _moduleinfo_dtors_i;
1031
1032 /**
1033 * Initialize the modules.
1034 */
1035
1036 extern (C) void _moduleCtor()
1037 {
1038 debug(PRINTF) printf("_moduleCtor()\n");
1039
1040 int len = 0;
1041 ModuleReference *mr;
1042
1043 for (mr = _Dmodule_ref; mr; mr = mr.next)
1044 len++;
1045 _moduleinfo_array = new ModuleInfo[len];
1046 len = 0;
1047 for (mr = _Dmodule_ref; mr; mr = mr.next)
1048 { _moduleinfo_array[len] = mr.mod;
1049 len++;
1050 }
1051
1052 _moduleinfo_dtors = new ModuleInfo[_moduleinfo_array.length];
1053 debug(PRINTF) printf("_moduleinfo_dtors = x%x\n", cast(void *)_moduleinfo_dtors);
1054 _moduleIndependentCtors();
1055 _moduleCtor2(_moduleinfo_array, 0);
1056 }
1057
1058 extern (C) void _moduleIndependentCtors()
1059 {
1060 debug(PRINTF) printf("_moduleIndependentCtors()\n");
1061 foreach (m; _moduleinfo_array)
1062 {
1063 if (m && m.flags & MIhasictor && m.ictor)
1064 {
1065 (*m.ictor)();
1066 }
1067 }
1068 debug(PRINTF) printf("_moduleIndependentCtors() DONE\n");
1069 }
1070
1071 void _moduleCtor2(ModuleInfo[] mi, int skip)
1072 {
1073 debug(PRINTF) printf("_moduleCtor2(): %d modules\n", mi.length);
1074 for (uint i = 0; i < mi.length; i++)
1075 {
1076 ModuleInfo m = mi[i];
1077
1078 debug(PRINTF) printf("\tmodule[%d] = '%p'\n", i, m);
1079 if (!m)
1080 continue;
1081 debug(PRINTF) printf("\tmodule[%d] = '%.*s'\n", i, m.name.length, m.name.ptr);
1082 if (m.flags & MIctordone)
1083 continue;
1084 debug(PRINTF) printf("\tmodule[%d] = '%.*s', m = x%x\n", i, m.name.length, m.name.ptr, m);
1085
1086 if (m.ctor || m.dtor)
1087 {
1088 if (m.flags & MIctorstart)
1089 { if (skip || m.flags & MIstandalone)
1090 continue;
1091 throw new Exception( "Cyclic dependency in module " ~ m.name );
1092 }
1093
1094 m.flags |= MIctorstart;
1095 _moduleCtor2(m.importedModules, 0);
1096 if (m.ctor)
1097 (*m.ctor)();
1098 m.flags &= ~MIctorstart;
1099 m.flags |= MIctordone;
1100
1101 // Now that construction is done, register the destructor
1102 //printf("\tadding module dtor x%x\n", m);
1103 assert(_moduleinfo_dtors_i < _moduleinfo_dtors.length);
1104 _moduleinfo_dtors[_moduleinfo_dtors_i++] = m;
1105 }
1106 else
1107 {
1108 m.flags |= MIctordone;
1109 _moduleCtor2(m.importedModules, 1);
1110 }
1111 }
1112 debug(PRINTF) printf("_moduleCtor2() DONE\n");
1113 }
1114
1115 /**
1116 * Destruct the modules.
1117 */
1118
1119 // Starting the name with "_STD" means under linux a pointer to the
1120 // function gets put in the .dtors segment.
1121
1122 extern (C) void _moduleDtor()
1123 {
1124 debug(PRINTF) printf("_moduleDtor(): %d modules\n", _moduleinfo_dtors_i);
1125
1126 for (uint i = _moduleinfo_dtors_i; i-- != 0;)
1127 {
1128 ModuleInfo m = _moduleinfo_dtors[i];
1129
1130 debug(PRINTF) printf("\tmodule[%d] = '%.*s', x%x\n", i, m.name, m);
1131 if (m.dtor)
1132 {
1133 (*m.dtor)();
1134 }
1135 }
1136 debug(PRINTF) printf("_moduleDtor() done\n");
1137 }
1138
1139 ////////////////////////////////////////////////////////////////////////////////
1140 // Monitor
1141 ////////////////////////////////////////////////////////////////////////////////
1142
1143 alias Object.Monitor IMonitor;
1144 alias void delegate(Object) DEvent;
1145
1146 // NOTE: The dtor callback feature is only supported for monitors that are not
1147 // supplied by the user. The assumption is that any object with a user-
1148 // supplied monitor may have special storage or lifetime requirements and
1149 // that as a result, storing references to local objects within Monitor
1150 // may not be safe or desirable. Thus, devt is only valid if impl is
1151 // null.
1152 struct Monitor
1153 {
1154 IMonitor impl;
1155 /* internal */
1156 DEvent[] devt;
1157 /* stuff */
1158 }
1159
1160 Monitor* getMonitor(Object h)
1161 {
1162 return cast(Monitor*) (cast(void**) h)[1];
1163 }
1164
1165 void setMonitor(Object h, Monitor* m)
1166 {
1167 (cast(void**) h)[1] = m;
1168 }
1169
1170 extern (C) void _d_monitor_create(Object);
1171 extern (C) void _d_monitor_destroy(Object);
1172 extern (C) void _d_monitor_lock(Object);
1173 extern (C) int _d_monitor_unlock(Object);
1174
1175 extern (C) void _d_monitordelete(Object h, bool det)
1176 {
1177 Monitor* m = getMonitor(h);
1178
1179 if (m !is null)
1180 {
1181 IMonitor i = m.impl;
1182 if (i is null)
1183 {
1184 _d_monitor_devt(m, h);
1185 _d_monitor_destroy(h);
1186 setMonitor(h, null);
1187 return;
1188 }
1189 if (det && (cast(void*) i) !is (cast(void*) h))
1190 delete i;
1191 setMonitor(h, null);
1192 }
1193 }
1194
1195 extern (C) void _d_monitorenter(Object h)
1196 {
1197 Monitor* m = getMonitor(h);
1198
1199 if (m is null)
1200 {
1201 _d_monitor_create(h);
1202 m = getMonitor(h);
1203 }
1204
1205 IMonitor i = m.impl;
1206
1207 if (i is null)
1208 {
1209 _d_monitor_lock(h);
1210 return;
1211 }
1212 i.lock();
1213 }
1214
1215 extern (C) void _d_monitorexit(Object h)
1216 {
1217 Monitor* m = getMonitor(h);
1218 IMonitor i = m.impl;
1219
1220 if (i is null)
1221 {
1222 _d_monitor_unlock(h);
1223 return;
1224 }
1225 i.unlock();
1226 }
1227
1228 extern (C) void _d_monitor_devt(Monitor* m, Object h)
1229 {
1230 if (m.devt.length)
1231 {
1232 DEvent[] devt;
1233
1234 synchronized (h)
1235 {
1236 devt = m.devt;
1237 m.devt = null;
1238 }
1239 foreach (v; devt)
1240 {
1241 if (v)
1242 v(h);
1243 }
1244 free(devt.ptr);
1245 }
1246 }
1247
1248 extern (C) void rt_attachDisposeEvent(Object h, DEvent e)
1249 {
1250 synchronized (h)
1251 {
1252 Monitor* m = getMonitor(h);
1253 assert(m.impl is null);
1254
1255 foreach (inout v; m.devt)
1256 {
1257 if (v is null || v == e)
1258 {
1259 v = e;
1260 return;
1261 }
1262 }
1263
1264 auto len = m.devt.length + 4; // grow by 4 elements
1265 auto pos = m.devt.length; // insert position
1266 auto p = realloc(m.devt.ptr, DEvent.sizeof * len);
1267 if (!p)
1268 onOutOfMemoryError();
1269 m.devt = (cast(DEvent*)p)[0 .. len];
1270 m.devt[pos+1 .. len] = null;
1271 m.devt[pos] = e;
1272 }
1273 }
1274
1275 extern (C) void rt_detachDisposeEvent(Object h, DEvent e)
1276 {
1277 synchronized (h)
1278 {
1279 Monitor* m = getMonitor(h);
1280 assert(m.impl is null);
1281
1282 foreach (p, v; m.devt)
1283 {
1284 if (v == e)
1285 {
1286 memmove(&m.devt[p],
1287 &m.devt[p+1],
1288 (m.devt.length - p - 1) * DEvent.sizeof);
1289 m.devt[$ - 1] = null;
1290 return;
1291 }
1292 }
1293 }
1294 }