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.
6 * This module is implicitly imported.
12 * Copyright (C) 2004-2007 by Digital Mars, www.digitalmars.com
13 * Written by Walter Bright
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.
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
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
35 * Modified by Sean Kelly for use with the D Runtime Project
45 debug(PRINTF) import stdc.stdio;
47 extern (C) void onOutOfMemoryError();
48 extern (C) Object _d_newclass(ClassInfo ci);
51 // NOTE: For some reason, this declaration method doesn't work
52 // in this particular file (and this file only). It must
54 //alias typeof(int.sizeof) size_t;
55 //alias typeof(cast(void*)0 - cast(void*)0) ptrdiff_t;
72 alias wchar[] wstring;
73 alias dchar[] dstring;
76 * All D class objects inherit from Object.
81 * Convert Object to a human readable string.
85 return this.classinfo.name;
89 * Compute hash function for Object.
93 // BUG: this prevents a compacting GC from working, needs to be fixed
94 return cast(hash_t)cast(void*)this;
98 * Compare with another Object obj.
101 * $(TR $(TD this < obj) $(TD < 0))
102 * $(TR $(TD this == obj) $(TD 0))
103 * $(TR $(TD this > obj) $(TD > 0))
108 // BUG: this prevents a compacting GC from working, needs to be fixed
109 //return cast(int)cast(void*)this - cast(int)cast(void*)o;
111 //throw new Exception("need opCmp for class " ~ this.classinfo.name);
116 * Returns !=0 if this object does have the same contents as obj.
118 equals_t opEquals(Object o)
131 * Information about an interface.
132 * When an object is accessed via an interface, an Interface* appears as the
133 * first entry in its vtbl.
137 ClassInfo classinfo; /// .classinfo for this interface (not for containing class)
139 ptrdiff_t offset; /// offset to Interface 'this' from Object 'this'
143 * Runtime type information about a class. Can be retrieved for any class type
144 * or instance by using the .classinfo property.
145 * A pointer to this appears as the first entry in the class's vtbl[].
147 class ClassInfo : Object
149 byte[] init; /** class static initializer
150 * (init.length gives size in bytes of class)
152 string name; /// class name
153 void*[] vtbl; /// virtual function pointer table
154 Interface[] interfaces; /// interfaces this class implements
155 ClassInfo base; /// base class
157 void function(Object) classInvariant;
159 // 1: // is IUnknown or is derived from IUnknown
160 // 2: // has no possible pointers into GC memory
161 // 4: // has offTi[] member
162 // 8: // has constructors
164 OffsetTypeInfo[] offTi;
165 void function(Object) defaultConstructor; // default Constructor
168 * Search all modules for ClassInfo corresponding to classname.
169 * Returns: null if not found
171 static ClassInfo find(in char[] classname)
173 foreach (m; ModuleInfo)
175 //writefln("module %s, %d", m.name, m.localClasses.length);
176 foreach (c; m.localClasses)
178 //writefln("\tclass %s", c.name);
179 if (c.name == classname)
187 * Create instance of Object represented by 'this'.
191 if (flags & 8 && !defaultConstructor)
193 Object o = _d_newclass(this);
194 if (flags & 8 && defaultConstructor)
196 defaultConstructor(o);
203 * Array of pairs giving the offset and type information for each
204 * member in an aggregate.
206 struct OffsetTypeInfo
208 size_t offset; /// Offset of member from start of object
209 TypeInfo ti; /// TypeInfo for this member
213 * Runtime type information about a type.
214 * Can be retrieved for any type using a
215 * <a href="../expression.html#typeidexpression">TypeidExpression</a>.
222 foreach (char c; this.toString())
231 TypeInfo ti = cast(TypeInfo)o;
234 return dstrcmp(this.toString(), ti.toString());
237 equals_t opEquals(Object o)
239 /* TypeInfo instances are singletons, but duplicates can exist
240 * across DLL's. Therefore, comparing for a name match is
245 TypeInfo ti = cast(TypeInfo)o;
246 return ti && this.toString() == ti.toString();
249 /// Returns a hash of the instance of a type.
250 hash_t getHash(in void* p) { return cast(hash_t)p; }
252 /// Compares two instances for equality.
253 equals_t equals(in void* p1, in void* p2) { return cast(int)(p1 == p2); }
255 /// Compares two instances for <, ==, or >.
256 int compare(in void* p1, in void* p2) { return 0; }
258 /// Returns size of the type.
259 size_t tsize() { return 0; }
261 /// Swaps two instances of the type.
262 void swap(void* p1, void* p2)
265 for (size_t i = 0; i < n; i++)
268 t = (cast(byte *)p1)[i];
269 (cast(byte *)p1)[i] = (cast(byte *)p2)[i];
270 (cast(byte *)p2)[i] = t;
274 /// Get TypeInfo for 'next' type, as defined by what kind of type this is,
276 TypeInfo next() { return null; }
278 /// Return default initializer, null if default initialize to 0
279 void[] init() { return null; }
281 /// Get flags for type: 1 means GC should scan for pointers
282 uint flags() { return 0; }
284 /// Get type information on the contents of the type; null if not available
285 OffsetTypeInfo[] offTi() { return null; }
288 class TypeInfo_Typedef : TypeInfo
290 string toString() { return name; }
292 equals_t opEquals(Object o)
293 { TypeInfo_Typedef c;
296 ((c = cast(TypeInfo_Typedef)o) !is null &&
297 this.name == c.name &&
298 this.base == c.base);
301 hash_t getHash(in void* p) { return base.getHash(p); }
302 equals_t equals(in void* p1, in void* p2) { return base.equals(p1, p2); }
303 int compare(in void* p1, in void* p2) { return base.compare(p1, p2); }
304 size_t tsize() { return base.tsize(); }
305 void swap(void* p1, void* p2) { return base.swap(p1, p2); }
307 TypeInfo next() { return base.next(); }
308 uint flags() { return base.flags(); }
309 void[] init() { return m_init.length ? m_init : base.init(); }
316 class TypeInfo_Enum : TypeInfo_Typedef
320 class TypeInfo_Pointer : TypeInfo
322 string toString() { return m_next.toString() ~ "*"; }
324 equals_t opEquals(Object o)
325 { TypeInfo_Pointer c;
328 ((c = cast(TypeInfo_Pointer)o) !is null &&
329 this.m_next == c.m_next);
332 hash_t getHash(in void* p)
334 return cast(hash_t)*cast(void**)p;
337 equals_t equals(in void* p1, in void* p2)
339 return cast(int)(*cast(void* *)p1 == *cast(void* *)p2);
342 int compare(in void* p1, in void* p2)
344 if (*cast(void* *)p1 < *cast(void* *)p2)
346 else if (*cast(void* *)p1 > *cast(void* *)p2)
354 return (void*).sizeof;
357 void swap(void* p1, void* p2)
359 tmp = *cast(void**)p1;
360 *cast(void**)p1 = *cast(void**)p2;
361 *cast(void**)p2 = tmp;
364 TypeInfo next() { return m_next; }
365 uint flags() { return 1; }
370 class TypeInfo_Array : TypeInfo
372 string toString() { return value.toString() ~ "[]"; }
374 equals_t opEquals(Object o)
378 ((c = cast(TypeInfo_Array)o) !is null &&
379 this.value == c.value);
382 hash_t getHash(in void* p)
383 { size_t sz = value.tsize();
385 void[] a = *cast(void[]*)p;
386 for (size_t i = 0; i < a.length; i++)
387 hash += value.getHash(a.ptr + i * sz);
391 equals_t equals(in void* p1, in void* p2)
393 void[] a1 = *cast(void[]*)p1;
394 void[] a2 = *cast(void[]*)p2;
395 if (a1.length != a2.length)
397 size_t sz = value.tsize();
398 for (size_t i = 0; i < a1.length; i++)
400 if (!value.equals(a1.ptr + i * sz, a2.ptr + i * sz))
406 int compare(in void* p1, in void* p2)
408 void[] a1 = *cast(void[]*)p1;
409 void[] a2 = *cast(void[]*)p2;
410 size_t sz = value.tsize();
411 size_t len = a1.length;
415 for (size_t u = 0; u < len; u++)
417 int result = value.compare(a1.ptr + u * sz, a2.ptr + u * sz);
421 return cast(int)a1.length - cast(int)a2.length;
426 return (void[]).sizeof;
429 void swap(void* p1, void* p2)
431 tmp = *cast(void[]*)p1;
432 *cast(void[]*)p1 = *cast(void[]*)p2;
433 *cast(void[]*)p2 = tmp;
443 uint flags() { return 1; }
446 class TypeInfo_StaticArray : TypeInfo
450 char [10] tmp = void;
451 return value.toString() ~ "[" ~ tmp.intToString(len) ~ "]";
454 equals_t opEquals(Object o)
455 { TypeInfo_StaticArray c;
458 ((c = cast(TypeInfo_StaticArray)o) !is null &&
460 this.value == c.value);
463 hash_t getHash(in void* p)
464 { size_t sz = value.tsize();
466 for (size_t i = 0; i < len; i++)
467 hash += value.getHash(p + i * sz);
471 equals_t equals(in void* p1, in void* p2)
473 size_t sz = value.tsize();
475 for (size_t u = 0; u < len; u++)
477 if (!value.equals(p1 + u * sz, p2 + u * sz))
483 int compare(in void* p1, in void* p2)
485 size_t sz = value.tsize();
487 for (size_t u = 0; u < len; u++)
489 int result = value.compare(p1 + u * sz, p2 + u * sz);
498 return len * value.tsize();
501 void swap(void* p1, void* p2)
503 size_t sz = value.tsize();
507 if (sz < buffer.sizeof)
510 tmp = pbuffer = (new void[sz]).ptr;
512 for (size_t u = 0; u < len; u += sz)
514 memcpy(tmp, p1 + o, sz);
515 memcpy(p1 + o, p2 + o, sz);
516 memcpy(p2 + o, tmp, sz);
522 void[] init() { return value.init(); }
523 TypeInfo next() { return value; }
524 uint flags() { return value.flags(); }
530 class TypeInfo_AssociativeArray : TypeInfo
534 return next.toString() ~ "[" ~ key.toString() ~ "]";
537 equals_t opEquals(Object o)
538 { TypeInfo_AssociativeArray c;
541 ((c = cast(TypeInfo_AssociativeArray)o) !is null &&
543 this.value == c.value);
546 // BUG: need to add the rest of the functions
550 return (char[int]).sizeof;
553 TypeInfo next() { return value; }
554 uint flags() { return 1; }
560 class TypeInfo_Function : TypeInfo
564 return next.toString() ~ "()";
567 equals_t opEquals(Object o)
568 { TypeInfo_Function c;
571 ((c = cast(TypeInfo_Function)o) !is null &&
572 this.next == c.next);
575 // BUG: need to add the rest of the functions
579 return 0; // no size for functions
585 class TypeInfo_Delegate : TypeInfo
589 return next.toString() ~ " delegate()";
592 equals_t opEquals(Object o)
593 { TypeInfo_Delegate c;
596 ((c = cast(TypeInfo_Delegate)o) !is null &&
597 this.next == c.next);
600 // BUG: need to add the rest of the functions
603 { alias int delegate() dg;
607 uint flags() { return 1; }
612 class TypeInfo_Class : TypeInfo
614 string toString() { return info.name; }
616 equals_t opEquals(Object o)
620 ((c = cast(TypeInfo_Class)o) !is null &&
621 this.info.name == c.classinfo.name);
624 hash_t getHash(in void* p)
626 Object o = *cast(Object*)p;
627 return o ? o.toHash() : 0;
630 equals_t equals(in void* p1, in void* p2)
632 Object o1 = *cast(Object*)p1;
633 Object o2 = *cast(Object*)p2;
635 return (o1 is o2) || (o1 && o1.opEquals(o2));
638 int compare(in void* p1, in void* p2)
640 Object o1 = *cast(Object*)p1;
641 Object o2 = *cast(Object*)p2;
644 // Regard null references as always being "less than"
661 return Object.sizeof;
664 uint flags() { return 1; }
666 OffsetTypeInfo[] offTi()
668 return (info.flags & 4) ? info.offTi : null;
674 class TypeInfo_Interface : TypeInfo
676 string toString() { return info.name; }
678 equals_t opEquals(Object o)
679 { TypeInfo_Interface c;
682 ((c = cast(TypeInfo_Interface)o) !is null &&
683 this.info.name == c.classinfo.name);
686 hash_t getHash(in void* p)
688 Interface* pi = **cast(Interface ***)*cast(void**)p;
689 Object o = cast(Object)(*cast(void**)p - pi.offset);
694 equals_t equals(in void* p1, in void* p2)
696 Interface* pi = **cast(Interface ***)*cast(void**)p1;
697 Object o1 = cast(Object)(*cast(void**)p1 - pi.offset);
698 pi = **cast(Interface ***)*cast(void**)p2;
699 Object o2 = cast(Object)(*cast(void**)p2 - pi.offset);
701 return o1 == o2 || (o1 && o1.opCmp(o2) == 0);
704 int compare(in void* p1, in void* p2)
706 Interface* pi = **cast(Interface ***)*cast(void**)p1;
707 Object o1 = cast(Object)(*cast(void**)p1 - pi.offset);
708 pi = **cast(Interface ***)*cast(void**)p2;
709 Object o2 = cast(Object)(*cast(void**)p2 - pi.offset);
712 // Regard null references as always being "less than"
729 return Object.sizeof;
732 uint flags() { return 1; }
737 class TypeInfo_Struct : TypeInfo
739 string toString() { return name; }
741 equals_t opEquals(Object o)
745 ((s = cast(TypeInfo_Struct)o) !is null &&
746 this.name == s.name &&
747 this.init.length == s.init.length);
750 hash_t getHash(in void* p)
755 { debug(PRINTF) printf("getHash() using xtoHash\n");
760 debug(PRINTF) printf("getHash() using default hash\n");
761 // A sorry hash algorithm.
762 // Should use the one for strings.
763 // BUG: relies on the GC not moving objects
764 for (size_t i = 0; i < init.length; i++)
765 { h = h * 9 + *cast(ubyte*)p;
772 equals_t equals(in void* p1, in void* p2)
780 c = (*xopEquals)(p1, p2);
782 // BUG: relies on the GC not moving objects
783 c = (memcmp(p1, p2, init.length) == 0);
787 int compare(in void* p1, in void* p2)
791 // Regard null references as always being "less than"
798 c = (*xopCmp)(p2, p1);
800 // BUG: relies on the GC not moving objects
801 c = memcmp(p1, p2, init.length);
814 void[] init() { return m_init; }
816 uint flags() { return m_flags; }
819 void[] m_init; // initializer; init.ptr == null if 0 initialize
821 hash_t function(void*) xtoHash;
822 int function(void*,void*) xopEquals;
823 int function(void*,void*) xopCmp;
824 char[] function(void*) xtoString;
829 class TypeInfo_Tuple : TypeInfo
837 foreach (i, element; elements)
841 s ~= element.toString();
847 equals_t opEquals(Object o)
852 auto t = cast(TypeInfo_Tuple)o;
853 if (t && elements.length == t.elements.length)
855 for (size_t i = 0; i < elements.length; i++)
857 if (elements[i] != t.elements[i])
865 hash_t getHash(in void* p)
870 equals_t equals(in void* p1, in void* p2)
875 int compare(in void* p1, in void* p2)
885 void swap(void* p1, void* p2)
892 ///////////////////////////////////////////////////////////////////////////////
894 ///////////////////////////////////////////////////////////////////////////////
897 class Exception : Object
901 int opApply( int delegate( inout char[] ) );
910 this( char[] msg, Exception next = null )
914 this.info = traceContext();
917 this( char[] msg, char[] file, size_t line, Exception next = null )
922 this.info = traceContext();
932 alias Exception.TraceInfo function( void* ptr = null ) TraceHandler;
933 private TraceHandler traceHandler = null;
937 * Overrides the default trace hander with a user-supplied version.
940 * h = The new trace handler. Set to null to use the default handler.
942 extern (C) void rt_setTraceHandler( TraceHandler h )
949 * This function will be called when an Exception is constructed. The
950 * user-supplied trace handler will be called if one has been supplied,
951 * otherwise no trace will be generated.
954 * ptr = A pointer to the location from which to generate the trace, or null
955 * if the trace should be generated from within the trace handler
959 * An object describing the current calling context or null if no handler is
962 Exception.TraceInfo traceContext( void* ptr = null )
964 if( traceHandler is null )
966 return traceHandler( ptr );
970 ///////////////////////////////////////////////////////////////////////////////
972 ///////////////////////////////////////////////////////////////////////////////
977 MIctorstart = 1, // we've started constructing it
978 MIctordone = 2, // finished construction
979 MIstandalone = 4, // module ctor does not depend on other module
980 // ctors being done first
981 MIhasictor = 8, // has ictor member
988 ModuleInfo[] importedModules;
989 ClassInfo[] localClasses;
992 void function() ctor; // module static constructor (order dependent)
993 void function() dtor; // module static destructor
994 void function() unitTest; // module unit tests
996 void* xgetMembers; // module getMembers() function
998 void function() ictor; // module static constructor (order independent)
1000 static int opApply( int delegate( inout ModuleInfo ) dg )
1004 foreach( m; _moduleinfo_array )
1015 // Windows: this gets initialized by minit.asm
1016 // linux: this gets initialized in _moduleCtor()
1017 extern (C) ModuleInfo[] _moduleinfo_array;
1022 // This linked list is created by a compiler generated function inserted
1023 // into the .ctor list by the compiler.
1024 struct ModuleReference
1026 ModuleReference* next;
1030 extern (C) ModuleReference* _Dmodule_ref; // start of linked list
1033 ModuleInfo[] _moduleinfo_dtors;
1034 uint _moduleinfo_dtors_i;
1036 // Register termination function pointers
1037 extern (C) int _fatexit(void*);
1040 * Initialize the modules.
1043 extern (C) void _moduleCtor()
1045 debug(PRINTF) printf("_moduleCtor()\n");
1049 ModuleReference *mr;
1051 for (mr = _Dmodule_ref; mr; mr = mr.next)
1053 _moduleinfo_array = new ModuleInfo[len];
1055 for (mr = _Dmodule_ref; mr; mr = mr.next)
1056 { _moduleinfo_array[len] = mr.mod;
1063 // Ensure module destructors also get called on program termination
1064 //_fatexit(&_STD_moduleDtor);
1067 _moduleinfo_dtors = new ModuleInfo[_moduleinfo_array.length];
1068 debug(PRINTF) printf("_moduleinfo_dtors = x%x\n", cast(void*)_moduleinfo_dtors);
1069 _moduleIndependentCtors();
1070 _moduleCtor2(_moduleinfo_array, 0);
1073 extern (C) void _moduleIndependentCtors()
1075 debug(PRINTF) printf("_moduleIndependentCtors()\n");
1076 foreach (m; _moduleinfo_array)
1078 if (m && m.flags & MIhasictor && m.ictor)
1085 void _moduleCtor2(ModuleInfo[] mi, int skip)
1087 debug(PRINTF) printf("_moduleCtor2(): %d modules\n", mi.length);
1088 for (uint i = 0; i < mi.length; i++)
1090 ModuleInfo m = mi[i];
1092 debug(PRINTF) printf("\tmodule[%d] = '%p'\n", i, m);
1095 debug(PRINTF) printf("\tmodule[%d] = '%.*s'\n", i, m.name);
1096 if (m.flags & MIctordone)
1098 debug(PRINTF) printf("\tmodule[%d] = '%.*s', m = x%x\n", i, m.name, m);
1100 if (m.ctor || m.dtor)
1102 if (m.flags & MIctorstart)
1103 { if (skip || m.flags & MIstandalone)
1105 throw new Exception( "Cyclic dependency in module " ~ m.name );
1108 m.flags |= MIctorstart;
1109 _moduleCtor2(m.importedModules, 0);
1112 m.flags &= ~MIctorstart;
1113 m.flags |= MIctordone;
1115 // Now that construction is done, register the destructor
1116 //printf("\tadding module dtor x%x\n", m);
1117 assert(_moduleinfo_dtors_i < _moduleinfo_dtors.length);
1118 _moduleinfo_dtors[_moduleinfo_dtors_i++] = m;
1122 m.flags |= MIctordone;
1123 _moduleCtor2(m.importedModules, 1);
1129 * Destruct the modules.
1132 // Starting the name with "_STD" means under linux a pointer to the
1133 // function gets put in the .dtors segment.
1135 extern (C) void _moduleDtor()
1137 debug(PRINTF) printf("_moduleDtor(): %d modules\n", _moduleinfo_dtors_i);
1139 for (uint i = _moduleinfo_dtors_i; i-- != 0;)
1141 ModuleInfo m = _moduleinfo_dtors[i];
1143 debug(PRINTF) printf("\tmodule[%d] = '%.*s', x%x\n", i, m.name, m);
1149 debug(PRINTF) printf("_moduleDtor() done\n");
1152 ///////////////////////////////////////////////////////////////////////////////
1154 ///////////////////////////////////////////////////////////////////////////////
1156 alias Object.Monitor IMonitor;
1157 alias void delegate(Object) DEvent;
1159 // NOTE: The dtor callback feature is only supported for monitors that are not
1160 // supplied by the user. The assumption is that any object with a user-
1161 // supplied monitor may have special storage or lifetime requirements and
1162 // that as a result, storing references to local objects within Monitor
1163 // may not be safe or desirable. Thus, devt is only valid if impl is
1173 Monitor* getMonitor(Object h)
1175 return cast(Monitor*) (cast(void**) h)[1];
1178 void setMonitor(Object h, Monitor* m)
1180 (cast(void**) h)[1] = m;
1183 extern (C) void _d_monitor_create(Object);
1184 extern (C) void _d_monitor_destroy(Object);
1185 extern (C) void _d_monitor_lock(Object);
1186 extern (C) int _d_monitor_unlock(Object);
1188 extern (C) void _d_monitordelete(Object h, bool det)
1190 Monitor* m = getMonitor(h);
1194 IMonitor i = m.impl;
1197 _d_monitor_devt(m, h);
1198 _d_monitor_destroy(h);
1199 setMonitor(h, null);
1202 if (det && (cast(void*) i) !is (cast(void*) h))
1204 setMonitor(h, null);
1208 extern (C) void _d_monitorenter(Object h)
1210 Monitor* m = getMonitor(h);
1214 _d_monitor_create(h);
1218 IMonitor i = m.impl;
1228 extern (C) void _d_monitorexit(Object h)
1230 Monitor* m = getMonitor(h);
1231 IMonitor i = m.impl;
1235 _d_monitor_unlock(h);
1241 extern (C) void _d_monitor_devt(Monitor* m, Object h)
1261 extern (C) void rt_attachDisposeEvent(Object h, DEvent e)
1265 Monitor* m = getMonitor(h);
1266 assert(m.impl is null);
1268 foreach (inout v; m.devt)
1270 if (v is null || v == e)
1277 auto len = m.devt.length + 4; // grow by 4 elements
1278 auto pos = m.devt.length; // insert position
1279 auto p = realloc(m.devt.ptr, DEvent.sizeof * len);
1281 onOutOfMemoryError();
1282 m.devt = (cast(DEvent*)p)[0 .. len];
1283 m.devt[pos+1 .. len] = null;
1288 extern (C) void rt_detachDisposeEvent(Object h, DEvent e)
1292 Monitor* m = getMonitor(h);
1293 assert(m.impl is null);
1295 foreach (p, v; m.devt)
1301 (m.devt.length - p - 1) * DEvent.sizeof);
1302 m.devt[$ - 1] = null;