Wiki Roadmap Timeline Tickets New Ticket Source Search Help / Guide About Trac Login

root/runtime/internal/genobj.d

Revision 1512:09734fb929c0, 35.5 kB (checked in by Christian Kamm <kamm incasoftware de>, 3 years ago)

Make == for associative arrays test for equality, not identity.

_aaEq was added to runtime/internal/aaA.d which forwards to
TypeInfo?_AssociativeArray.equals in genobj.d. On the codegen side, DtoAAEquals
was added to gen/aa.cpp and is called from EqualExp::toElem in gen/toir.cpp.

I assume that the frontend will produce an error if == is used on associative
arrays of different type.

This fixes DMD bug 1429.

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