Mercurial > projects > ldc
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/runtime/internal/genobj.d Fri Aug 01 00:32:06 2008 +0200 @@ -0,0 +1,1294 @@ +/** + * Part of the D programming language runtime library. + * Forms the symbols available to all D programs. Includes + * Object, which is the root of the class object hierarchy. + * + * This module is implicitly imported. + * Macros: + * WIKI = Object + */ + +/* + * Copyright (C) 2004-2007 by Digital Mars, www.digitalmars.com + * Written by Walter Bright + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, in both source and binary form, subject to the following + * restrictions: + * + * o The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * o Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * o This notice may not be removed or altered from any source + * distribution. + */ + +/* + * Modified by Sean Kelly <sean@f4.ca> for use with Tango. + * Modified by Tomas Lindquist Olsen <tomas@famolsen.dk> for use with LLVMDC. + */ + +module object; + +//debug=PRINTF + +private +{ + import tango.stdc.string; // : memcmp, memcpy, memmove; + import tango.stdc.stdlib; // : calloc, realloc, free; + import util.string; + debug(PRINTF) import tango.stdc.stdio; // : printf; + + extern (C) void onOutOfMemoryError(); + extern (C) Object _d_newclass(ClassInfo ci); +} + +// NOTE: For some reason, this declaration method doesn't work +// in this particular file (and this file only). It must +// be a DMD thing. +//alias typeof(int.sizeof) size_t; +//alias typeof(cast(void*)0 - cast(void*)0) ptrdiff_t; + +version( LLVM64 ) +{ + alias ulong size_t; + alias long ptrdiff_t; +} +else +{ + alias uint size_t; + alias int ptrdiff_t; +} + +alias size_t hash_t; + +/** + * All D class objects inherit from Object. + */ +class Object +{ + /** + * Convert Object to a human readable string. + */ + char[] toString() + { + return this.classinfo.name; + } + + /** + * Compute hash function for Object. + */ + hash_t toHash() + { + // BUG: this prevents a compacting GC from working, needs to be fixed + return cast(hash_t)cast(void*)this; + } + + /** + * Compare with another Object obj. + * Returns: + * $(TABLE + * $(TR $(TD this < obj) $(TD < 0)) + * $(TR $(TD this == obj) $(TD 0)) + * $(TR $(TD this > obj) $(TD > 0)) + * ) + */ + int opCmp(Object o) + { + // BUG: this prevents a compacting GC from working, needs to be fixed + //return cast(int)cast(void*)this - cast(int)cast(void*)o; + + //throw new Exception("need opCmp for class " ~ this.classinfo.name); + return this !is o; + } + + /** + * Returns !=0 if this object does have the same contents as obj. + */ + int opEquals(Object o) + { + return cast(int)(this is o); + } + + interface Monitor + { + void lock(); + void unlock(); + } +} + +/** + * Information about an interface. + * When an object is accessed via an interface, an Interface* appears as the + * first entry in its vtbl. + */ +struct Interface +{ + ClassInfo classinfo; /// .classinfo for this interface (not for containing class) + void*[] vtbl; + ptrdiff_t offset; /// offset to Interface 'this' from Object 'this' +} + +/** + * Runtime type information about a class. Can be retrieved for any class type + * or instance by using the .classinfo property. + * A pointer to this appears as the first entry in the class's vtbl[]. + */ +class ClassInfo : Object +{ + byte[] init; /** class static initializer + * (init.length gives size in bytes of class) + */ + char[] name; /// class name + void*[] vtbl; /// virtual function pointer table + Interface[] interfaces; /// interfaces this class implements + ClassInfo base; /// base class + void* destructor; + void function(Object) classInvariant; + uint flags; + // 1: // IUnknown + // 2: // has no possible pointers into GC memory + // 4: // has offTi[] member + // 8: // has constructors + void* deallocator; + OffsetTypeInfo[] offTi; + void function(Object) defaultConstructor; // default Constructor + + /** + * Search all modules for ClassInfo corresponding to classname. + * Returns: null if not found + */ + static ClassInfo find(char[] classname) + { + foreach (m; ModuleInfo) + { + //writefln("module %s, %d", m.name, m.localClasses.length); + foreach (c; m.localClasses) + { + //writefln("\tclass %s", c.name); + if (c.name == classname) + return c; + } + } + return null; + } + + /** + * Create instance of Object represented by 'this'. + */ + Object create() + { + if (flags & 8 && !defaultConstructor) + return null; + Object o = _d_newclass(this); + if (flags & 8 && defaultConstructor) + { + defaultConstructor(o); + } + return o; + } +} + +/** + * Array of pairs giving the offset and type information for each + * member in an aggregate. + */ +struct OffsetTypeInfo +{ + size_t offset; /// Offset of member from start of object + TypeInfo ti; /// TypeInfo for this member +} + +/** + * Runtime type information about a type. + * Can be retrieved for any type using a + * <a href="../expression.html#typeidexpression">TypeidExpression</a>. + */ +class TypeInfo +{ + hash_t toHash() + { hash_t hash; + + foreach (char c; this.toString()) + hash = hash * 9 + c; + return hash; + } + + int opCmp(Object o) + { + if (this is o) + return 0; + TypeInfo ti = cast(TypeInfo)o; + if (ti is null) + return 1; + return stringCompare(this.toString(), ti.toString()); + } + + int opEquals(Object o) + { + /* TypeInfo instances are singletons, but duplicates can exist + * across DLL's. Therefore, comparing for a name match is + * sufficient. + */ + if (this is o) + return 1; + TypeInfo ti = cast(TypeInfo)o; + return cast(int)(ti && this.toString() == ti.toString()); + } + + /// Returns a hash of the instance of a type. + hash_t getHash(void *p) { return cast(hash_t)p; } + + /// Compares two instances for equality. + int equals(void *p1, void *p2) { return cast(int)(p1 == p2); } + + /// Compares two instances for <, ==, or >. + int compare(void *p1, void *p2) { return 0; } + + /// Returns size of the type. + size_t tsize() { return 0; } + + /// Swaps two instances of the type. + void swap(void *p1, void *p2) + { + size_t n = tsize(); + for (size_t i = 0; i < n; i++) + { byte t; + + t = (cast(byte *)p1)[i]; + (cast(byte *)p1)[i] = (cast(byte *)p2)[i]; + (cast(byte *)p2)[i] = t; + } + } + + /// Get TypeInfo for 'next' type, as defined by what kind of type this is, + /// null if none. + TypeInfo next() { return null; } + + /// Return default initializer, null if default initialize to 0 + void[] init() { return null; } + + /// Get flags for type: 1 means GC should scan for pointers + uint flags() { return 0; } + + /// Get type information on the contents of the type; null if not available + OffsetTypeInfo[] offTi() { return null; } +} + +class TypeInfo_Typedef : TypeInfo +{ + char[] toString() { return name; } + + int opEquals(Object o) + { TypeInfo_Typedef c; + + return cast(int) + (this is o || + ((c = cast(TypeInfo_Typedef)o) !is null && + this.name == c.name && + this.base == c.base)); + } + + hash_t getHash(void *p) { return base.getHash(p); } + int equals(void *p1, void *p2) { return base.equals(p1, p2); } + int compare(void *p1, void *p2) { return base.compare(p1, p2); } + size_t tsize() { return base.tsize(); } + void swap(void *p1, void *p2) { return base.swap(p1, p2); } + + TypeInfo next() { return base; } + uint flags() { return base.flags(); } + void[] init() { return m_init.length ? m_init : base.init(); } + + TypeInfo base; + char[] name; + void[] m_init; +} + +class TypeInfo_Enum : TypeInfo_Typedef +{ +} + +class TypeInfo_Pointer : TypeInfo +{ + char[] toString() { return m_next.toString() ~ "*"; } + + int opEquals(Object o) + { TypeInfo_Pointer c; + + return this is o || + ((c = cast(TypeInfo_Pointer)o) !is null && + this.m_next == c.m_next); + } + + hash_t getHash(void *p) + { + return cast(hash_t)*cast(void**)p; + } + + int equals(void *p1, void *p2) + { + return cast(int)(*cast(void* *)p1 == *cast(void* *)p2); + } + + int compare(void *p1, void *p2) + { + if (*cast(void* *)p1 < *cast(void* *)p2) + return -1; + else if (*cast(void* *)p1 > *cast(void* *)p2) + return 1; + else + return 0; + } + + size_t tsize() + { + return (void*).sizeof; + } + + void swap(void *p1, void *p2) + { void* tmp; + tmp = *cast(void**)p1; + *cast(void**)p1 = *cast(void**)p2; + *cast(void**)p2 = tmp; + } + + TypeInfo next() { return m_next; } + uint flags() { return 1; } + + TypeInfo m_next; +} + +class TypeInfo_Array : TypeInfo +{ + char[] toString() { return value.toString() ~ "[]"; } + + int opEquals(Object o) + { TypeInfo_Array c; + + return cast(int) + (this is o || + ((c = cast(TypeInfo_Array)o) !is null && + this.value == c.value)); + } + + hash_t getHash(void *p) + { size_t sz = value.tsize(); + hash_t hash = 0; + void[] a = *cast(void[]*)p; + for (size_t i = 0; i < a.length; i++) + hash += value.getHash(a.ptr + i * sz); + return hash; + } + + int equals(void *p1, void *p2) + { + void[] a1 = *cast(void[]*)p1; + void[] a2 = *cast(void[]*)p2; + if (a1.length != a2.length) + return 0; + size_t sz = value.tsize(); + for (size_t i = 0; i < a1.length; i++) + { + if (!value.equals(a1.ptr + i * sz, a2.ptr + i * sz)) + return 0; + } + return 1; + } + + int compare(void *p1, void *p2) + { + void[] a1 = *cast(void[]*)p1; + void[] a2 = *cast(void[]*)p2; + size_t sz = value.tsize(); + size_t len = a1.length; + + if (a2.length < len) + len = a2.length; + for (size_t u = 0; u < len; u++) + { + int result = value.compare(a1.ptr + u * sz, a2.ptr + u * sz); + if (result) + return result; + } + return cast(int)a1.length - cast(int)a2.length; + } + + size_t tsize() + { + return (void[]).sizeof; + } + + void swap(void *p1, void *p2) + { void[] tmp; + tmp = *cast(void[]*)p1; + *cast(void[]*)p1 = *cast(void[]*)p2; + *cast(void[]*)p2 = tmp; + } + + TypeInfo value; + + TypeInfo next() + { + return value; + } + + uint flags() { return 1; } +} + +class TypeInfo_StaticArray : TypeInfo +{ + char[] toString() + { + char [10] tmp = void; + return value.toString() ~ "[" ~ intToUtf8(tmp, len) ~ "]"; + } + + int opEquals(Object o) + { TypeInfo_StaticArray c; + + return cast(int) + (this is o || + ((c = cast(TypeInfo_StaticArray)o) !is null && + this.len == c.len && + this.value == c.value)); + } + + hash_t getHash(void *p) + { size_t sz = value.tsize(); + hash_t hash = 0; + for (size_t i = 0; i < len; i++) + hash += value.getHash(p + i * sz); + return hash; + } + + int equals(void *p1, void *p2) + { + size_t sz = value.tsize(); + + for (size_t u = 0; u < len; u++) + { + if (!value.equals(p1 + u * sz, p2 + u * sz)) + return 0; + } + return 1; + } + + int compare(void *p1, void *p2) + { + size_t sz = value.tsize(); + + for (size_t u = 0; u < len; u++) + { + int result = value.compare(p1 + u * sz, p2 + u * sz); + if (result) + return result; + } + return 0; + } + + size_t tsize() + { + return len * value.tsize(); + } + + void swap(void *p1, void *p2) + { void* tmp; + size_t sz = value.tsize(); + ubyte[16] buffer; + void* pbuffer; + + if (sz < buffer.sizeof) + tmp = buffer.ptr; + else + tmp = pbuffer = (new void[sz]).ptr; + + for (size_t u = 0; u < len; u += sz) + { size_t o = u * sz; + memcpy(tmp, p1 + o, sz); + memcpy(p1 + o, p2 + o, sz); + memcpy(p2 + o, tmp, sz); + } + if (pbuffer) + delete pbuffer; + } + + void[] init() { return value.init(); } + TypeInfo next() { return value; } + uint flags() { return value.flags(); } + + TypeInfo value; + size_t len; +} + +class TypeInfo_AssociativeArray : TypeInfo +{ + char[] toString() + { + return next.toString() ~ "[" ~ key.toString() ~ "]"; + } + + int opEquals(Object o) + { TypeInfo_AssociativeArray c; + + return this is o || + ((c = cast(TypeInfo_AssociativeArray)o) !is null && + this.key == c.key && + this.value == c.value); + } + + // BUG: need to add the rest of the functions + + size_t tsize() + { + return (char[int]).sizeof; + } + + TypeInfo next() { return value; } + uint flags() { return 1; } + + TypeInfo value; + TypeInfo key; +} + +class TypeInfo_Function : TypeInfo +{ + char[] toString() + { + return next.toString() ~ "()"; + } + + int opEquals(Object o) + { TypeInfo_Function c; + + return this is o || + ((c = cast(TypeInfo_Function)o) !is null && + this.next == c.next); + } + + // BUG: need to add the rest of the functions + + size_t tsize() + { + return 0; // no size for functions + } + + TypeInfo next; +} + +class TypeInfo_Delegate : TypeInfo +{ + char[] toString() + { + return next.toString() ~ " delegate()"; + } + + int opEquals(Object o) + { TypeInfo_Delegate c; + + return this is o || + ((c = cast(TypeInfo_Delegate)o) !is null && + this.next == c.next); + } + + // BUG: need to add the rest of the functions + + size_t tsize() + { alias int delegate() dg; + return dg.sizeof; + } + + uint flags() { return 1; } + + TypeInfo next; +} + +class TypeInfo_Class : TypeInfo +{ + char[] toString() { return info.name; } + + int opEquals(Object o) + { TypeInfo_Class c; + + return this is o || + ((c = cast(TypeInfo_Class)o) !is null && + this.info.name == c.classinfo.name); + } + + hash_t getHash(void *p) + { + Object o = *cast(Object*)p; + return o ? o.toHash() : 0; + } + + int equals(void *p1, void *p2) + { + Object o1 = *cast(Object*)p1; + Object o2 = *cast(Object*)p2; + + return (o1 is o2) || (o1 && o1.opEquals(o2)); + } + + int compare(void *p1, void *p2) + { + Object o1 = *cast(Object*)p1; + Object o2 = *cast(Object*)p2; + int c = 0; + + // Regard null references as always being "less than" + if (o1 !is o2) + { + if (o1) + { if (!o2) + c = 1; + else + c = o1.opCmp(o2); + } + else + c = -1; + } + return c; + } + + size_t tsize() + { + return Object.sizeof; + } + + uint flags() { return 1; } + + OffsetTypeInfo[] offTi() + { + return (info.flags & 4) ? info.offTi : null; + } + + ClassInfo info; +} + +class TypeInfo_Interface : TypeInfo +{ + char[] toString() { return info.name; } + + int opEquals(Object o) + { TypeInfo_Interface c; + + return this is o || + ((c = cast(TypeInfo_Interface)o) !is null && + this.info.name == c.classinfo.name); + } + + hash_t getHash(void *p) + { + Interface* pi = **cast(Interface ***)*cast(void**)p; + Object o = cast(Object)(*cast(void**)p - pi.offset); + assert(o); + return o.toHash(); + } + + int equals(void *p1, void *p2) + { + Interface* pi = **cast(Interface ***)*cast(void**)p1; + Object o1 = cast(Object)(*cast(void**)p1 - pi.offset); + pi = **cast(Interface ***)*cast(void**)p2; + Object o2 = cast(Object)(*cast(void**)p2 - pi.offset); + + return o1 == o2 || (o1 && o1.opCmp(o2) == 0); + } + + int compare(void *p1, void *p2) + { + Interface* pi = **cast(Interface ***)*cast(void**)p1; + Object o1 = cast(Object)(*cast(void**)p1 - pi.offset); + pi = **cast(Interface ***)*cast(void**)p2; + Object o2 = cast(Object)(*cast(void**)p2 - pi.offset); + int c = 0; + + // Regard null references as always being "less than" + if (o1 != o2) + { + if (o1) + { if (!o2) + c = 1; + else + c = o1.opCmp(o2); + } + else + c = -1; + } + return c; + } + + size_t tsize() + { + return Object.sizeof; + } + + uint flags() { return 1; } + + ClassInfo info; +} + +class TypeInfo_Struct : TypeInfo +{ + char[] toString() { return name; } + + int opEquals(Object o) + { TypeInfo_Struct s; + + return this is o || + ((s = cast(TypeInfo_Struct)o) !is null && + this.name == s.name && + this.init.length == s.init.length); + } + + hash_t getHash(void *p) + { hash_t h; + + assert(p); + if (xtoHash) + { debug(PRINTF) printf("getHash() using xtoHash\n"); + h = (*xtoHash)(p); + } + else + { + debug(PRINTF) printf("getHash() using default hash\n"); + // A sorry hash algorithm. + // Should use the one for strings. + // BUG: relies on the GC not moving objects + for (size_t i = 0; i < m_init.length; i++) + { h = h * 9 + *cast(ubyte*)p; + p++; + } + } + return h; + } + + int equals(void *p1, void *p2) + { int c; + + if (p1 == p2) + c = 1; + else if (!p1 || !p2) + c = 0; + else if (xopEquals) + c = (*xopEquals)(p1, p2); + else + // BUG: relies on the GC not moving objects + c = (memcmp(p1, p2, m_init.length) == 0); + return c; + } + + int compare(void *p1, void *p2) + { + int c = 0; + + // Regard null references as always being "less than" + if (p1 != p2) + { + if (p1) + { if (!p2) + c = 1; + else if (xopCmp) + c = (*xopCmp)(p1, p2); + else + // BUG: relies on the GC not moving objects + c = memcmp(p1, p2, m_init.length); + } + else + c = -1; + } + return c; + } + + size_t tsize() + { + return m_init.length; + } + + void[] init() { return m_init; } + + uint flags() { return m_flags; } + + char[] name; + void[] m_init; // initializer; never null + + hash_t function(void*) xtoHash; + int function(void*,void*) xopEquals; + int function(void*,void*) xopCmp; + char[] function(void*) xtoString; + + uint m_flags; +} + +class TypeInfo_Tuple : TypeInfo +{ + TypeInfo[] elements; + + char[] toString() + { + char[] s; + s = "("; + foreach (i, element; elements) + { + if (i) + s ~= ','; + s ~= element.toString(); + } + s ~= ")"; + return s; + } + + int opEquals(Object o) + { + if (this is o) + return 1; + + auto t = cast(TypeInfo_Tuple)o; + if (t && elements.length == t.elements.length) + { + for (size_t i = 0; i < elements.length; i++) + { + if (elements[i] != t.elements[i]) + return 0; + } + return 1; + } + return 0; + } + + hash_t getHash(void *p) + { + assert(0); + } + + int equals(void *p1, void *p2) + { + assert(0); + } + + int compare(void *p1, void *p2) + { + assert(0); + } + + size_t tsize() + { + assert(0); + } + + void swap(void *p1, void *p2) + { + assert(0); + } +} + + +//////////////////////////////////////////////////////////////////////////////// +// Exception +//////////////////////////////////////////////////////////////////////////////// + + +class Exception : Object +{ + interface TraceInfo + { + int opApply( int delegate( inout char[] ) ); + } + + char[] msg; + char[] file; + size_t line; + TraceInfo info; + Exception next; + + this( char[] msg, Exception next = null ) + { + this.msg = msg; + this.next = next; + this.info = traceContext(); + } + + this( char[] msg, char[] file, size_t line, Exception next = null ) + { + this(msg, next); + this.file = file; + this.line = line; + this.info = traceContext(); + } + + char[] toString() + { + return msg; + } +} + + +alias Exception.TraceInfo function( void* ptr = null ) TraceHandler; +private TraceHandler traceHandler = null; + + +/** + * Overrides the default trace hander with a user-supplied version. + * + * Params: + * h = The new trace handler. Set to null to use the default handler. + */ +extern (C) void rt_setTraceHandler( TraceHandler h ) +{ + traceHandler = h; +} + + +/** + * This function will be called when an Exception is constructed. The + * user-supplied trace handler will be called if one has been supplied, + * otherwise no trace will be generated. + * + * Params: + * ptr = A pointer to the location from which to generate the trace, or null + * if the trace should be generated from within the trace handler + * itself. + * + * Returns: + * An object describing the current calling context or null if no handler is + * supplied. + */ +Exception.TraceInfo traceContext( void* ptr = null ) +{ + if( traceHandler is null ) + return null; + return traceHandler( ptr ); +} + + +//////////////////////////////////////////////////////////////////////////////// +// ModuleInfo +//////////////////////////////////////////////////////////////////////////////// + + +enum +{ + MIctorstart = 1, // we've started constructing it + MIctordone = 2, // finished construction + MIstandalone = 4, // module ctor does not depend on other module + // ctors being done first + MIhasictor = 8, // has ictor member +} + + +class ModuleInfo +{ + char[] name; + ModuleInfo[] importedModules; + ClassInfo[] localClasses; + uint flags; + + void function() ctor; // module static constructor (order dependent) + void function() dtor; // module static destructor + void function() unitTest; // module unit tests + + void* xgetMembers; // module getMembers() function + + void function() ictor; // module static constructor (order independent) + + static int opApply( int delegate( inout ModuleInfo ) dg ) + { + int ret = 0; + + foreach( m; _moduleinfo_array ) + { + ret = dg( m ); + if( ret ) + break; + } + return ret; + } +} + + +// this gets initialized in _moduleCtor() +extern (C) ModuleInfo[] _moduleinfo_array; + +// This linked list is created by a compiler generated function inserted +// into the .ctor list by the compiler. +struct ModuleReference +{ + ModuleReference* next; + ModuleInfo mod; +} +extern (C) ModuleReference* _Dmodule_ref; // start of linked list + +// this list is built from the linked list above +ModuleInfo[] _moduleinfo_dtors; +uint _moduleinfo_dtors_i; + +/** + * Initialize the modules. + */ + +extern (C) void _moduleCtor() +{ + debug(PRINTF) printf("_moduleCtor()\n"); + + int len = 0; + ModuleReference *mr; + + for (mr = _Dmodule_ref; mr; mr = mr.next) + len++; + _moduleinfo_array = new ModuleInfo[len]; + len = 0; + for (mr = _Dmodule_ref; mr; mr = mr.next) + { _moduleinfo_array[len] = mr.mod; + len++; + } + + _moduleinfo_dtors = new ModuleInfo[_moduleinfo_array.length]; + debug(PRINTF) printf("_moduleinfo_dtors = x%x\n", cast(void *)_moduleinfo_dtors); + _moduleIndependentCtors(); + _moduleCtor2(_moduleinfo_array, 0); +} + +extern (C) void _moduleIndependentCtors() +{ + debug(PRINTF) printf("_moduleIndependentCtors()\n"); + foreach (m; _moduleinfo_array) + { + if (m && m.flags & MIhasictor && m.ictor) + { + (*m.ictor)(); + } + } + debug(PRINTF) printf("_moduleIndependentCtors() DONE\n"); +} + +void _moduleCtor2(ModuleInfo[] mi, int skip) +{ + debug(PRINTF) printf("_moduleCtor2(): %d modules\n", mi.length); + for (uint i = 0; i < mi.length; i++) + { + ModuleInfo m = mi[i]; + + debug(PRINTF) printf("\tmodule[%d] = '%p'\n", i, m); + if (!m) + continue; + debug(PRINTF) printf("\tmodule[%d] = '%.*s'\n", i, m.name.length, m.name.ptr); + if (m.flags & MIctordone) + continue; + debug(PRINTF) printf("\tmodule[%d] = '%.*s', m = x%x\n", i, m.name.length, m.name.ptr, m); + + if (m.ctor || m.dtor) + { + if (m.flags & MIctorstart) + { if (skip || m.flags & MIstandalone) + continue; + throw new Exception( "Cyclic dependency in module " ~ m.name ); + } + + m.flags |= MIctorstart; + _moduleCtor2(m.importedModules, 0); + if (m.ctor) + (*m.ctor)(); + m.flags &= ~MIctorstart; + m.flags |= MIctordone; + + // Now that construction is done, register the destructor + //printf("\tadding module dtor x%x\n", m); + assert(_moduleinfo_dtors_i < _moduleinfo_dtors.length); + _moduleinfo_dtors[_moduleinfo_dtors_i++] = m; + } + else + { + m.flags |= MIctordone; + _moduleCtor2(m.importedModules, 1); + } + } + debug(PRINTF) printf("_moduleCtor2() DONE\n"); +} + +/** + * Destruct the modules. + */ + +// Starting the name with "_STD" means under linux a pointer to the +// function gets put in the .dtors segment. + +extern (C) void _moduleDtor() +{ + debug(PRINTF) printf("_moduleDtor(): %d modules\n", _moduleinfo_dtors_i); + + for (uint i = _moduleinfo_dtors_i; i-- != 0;) + { + ModuleInfo m = _moduleinfo_dtors[i]; + + debug(PRINTF) printf("\tmodule[%d] = '%.*s', x%x\n", i, m.name, m); + if (m.dtor) + { + (*m.dtor)(); + } + } + debug(PRINTF) printf("_moduleDtor() done\n"); +} + +//////////////////////////////////////////////////////////////////////////////// +// Monitor +//////////////////////////////////////////////////////////////////////////////// + +alias Object.Monitor IMonitor; +alias void delegate(Object) DEvent; + +// NOTE: The dtor callback feature is only supported for monitors that are not +// supplied by the user. The assumption is that any object with a user- +// supplied monitor may have special storage or lifetime requirements and +// that as a result, storing references to local objects within Monitor +// may not be safe or desirable. Thus, devt is only valid if impl is +// null. +struct Monitor +{ + IMonitor impl; + /* internal */ + DEvent[] devt; + /* stuff */ +} + +Monitor* getMonitor(Object h) +{ + return cast(Monitor*) (cast(void**) h)[1]; +} + +void setMonitor(Object h, Monitor* m) +{ + (cast(void**) h)[1] = m; +} + +extern (C) void _d_monitor_create(Object); +extern (C) void _d_monitor_destroy(Object); +extern (C) void _d_monitor_lock(Object); +extern (C) int _d_monitor_unlock(Object); + +extern (C) void _d_monitordelete(Object h, bool det) +{ + Monitor* m = getMonitor(h); + + if (m !is null) + { + IMonitor i = m.impl; + if (i is null) + { + _d_monitor_devt(m, h); + _d_monitor_destroy(h); + setMonitor(h, null); + return; + } + if (det && (cast(void*) i) !is (cast(void*) h)) + delete i; + setMonitor(h, null); + } +} + +extern (C) void _d_monitorenter(Object h) +{ + Monitor* m = getMonitor(h); + + if (m is null) + { + _d_monitor_create(h); + m = getMonitor(h); + } + + IMonitor i = m.impl; + + if (i is null) + { + _d_monitor_lock(h); + return; + } + i.lock(); +} + +extern (C) void _d_monitorexit(Object h) +{ + Monitor* m = getMonitor(h); + IMonitor i = m.impl; + + if (i is null) + { + _d_monitor_unlock(h); + return; + } + i.unlock(); +} + +extern (C) void _d_monitor_devt(Monitor* m, Object h) +{ + if (m.devt.length) + { + DEvent[] devt; + + synchronized (h) + { + devt = m.devt; + m.devt = null; + } + foreach (v; devt) + { + if (v) + v(h); + } + free(devt.ptr); + } +} + +extern (C) void rt_attachDisposeEvent(Object h, DEvent e) +{ + synchronized (h) + { + Monitor* m = getMonitor(h); + assert(m.impl is null); + + foreach (inout v; m.devt) + { + if (v is null || v == e) + { + v = e; + return; + } + } + + auto len = m.devt.length + 4; // grow by 4 elements + auto pos = m.devt.length; // insert position + auto p = realloc(m.devt.ptr, DEvent.sizeof * len); + if (!p) + onOutOfMemoryError(); + m.devt = (cast(DEvent*)p)[0 .. len]; + m.devt[pos+1 .. len] = null; + m.devt[pos] = e; + } +} + +extern (C) void rt_detachDisposeEvent(Object h, DEvent e) +{ + synchronized (h) + { + Monitor* m = getMonitor(h); + assert(m.impl is null); + + foreach (p, v; m.devt) + { + if (v == e) + { + memmove(&m.devt[p], + &m.devt[p+1], + (m.devt.length - p - 1) * DEvent.sizeof); + m.devt[$ - 1] = null; + return; + } + } + } +}