Mercurial > projects > ldc
view lphobos/internal/objectimpl.d @ 323:0d52412d5b1a trunk
[svn r344] Fixed some very minor issues with the usage listing when calling llvmdc with no arguments.
Changed the way moduleinfo is registered to use the same approach as DMD, this eliminates the need for correct linking order and should make the way for using a natively compiled runtime library. This should speed up linking tremendously and should now be possible.
Fixed the llvm.used array to only be emitted if really necessary.
author | lindquist |
---|---|
date | Wed, 09 Jul 2008 23:43:51 +0200 |
parents | a2c2c3c1a73d |
children | 373489eeaf90 |
line wrap: on
line source
/** * 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 = Phobos/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. */ /* * This copy is modified to work with LLVMDC * by Tomas Lindquist Olsen, September 2007 */ module object; import std.outofmemory; /** * An unsigned integral type large enough to span the memory space. Use for * array indices and pointer offsets for maximal portability to * architectures that have different memory address ranges. This is * analogous to C's size_t. */ alias typeof(int.sizeof) size_t; /** * A signed integral type large enough to span the memory space. Use for * pointer differences and for size_t differences for maximal portability to * architectures that have different memory address ranges. This is * analogous to C's ptrdiff_t. */ alias typeof(cast(void*)0 - cast(void*)0) ptrdiff_t; alias size_t hash_t; extern (C) { /// C's printf function. int printf(char *, ...); void trace_term(); int memcmp(void *, void *, size_t); void* memcpy(void *, void *, size_t); void* calloc(size_t, size_t); void* realloc(void*, size_t); void free(void*); //Object _d_newclass(ClassInfo ci); } /// Standard boolean type. alias bool bit; alias char[] string; alias wchar[] wstring; alias dchar[] dstring; /+ /* ************************* * Internal struct pointed to by the hidden .monitor member. */ struct Monitor { void delegate(Object)[] delegates; /* More stuff goes here defined by internal/monitor.c */ } +/ /****************** * All D class objects inherit from Object. */ class Object { void print() { char[] s = toString(); printf("%.*s\n", s.length, s.ptr); } /** * 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 Error("need opCmp for class " ~ this.classinfo.name); } /** * Returns !=0 if this object does have the same contents as obj. */ int opEquals(Object o) { return cast(int)(this is o); } /* ** * Call delegate dg, passing this to it, when this object gets destroyed. * Use extreme caution, as the list of delegates is stored in a place * not known to the gc. Thus, if any objects pointed to by one of these * delegates gets freed by the gc, calling the delegate will cause a * crash. * This is only for use by library developers, as it will need to be * redone if weak pointers are added or a moving gc is developed. */ final void notifyRegister(void delegate(Object) dg) { /+ //printf("notifyRegister(dg = %llx, o = %p)\n", dg, this); synchronized (this) { Monitor* m = cast(Monitor*)(cast(void**)this)[1]; foreach (inout x; m.delegates) { if (!x || x == dg) { x = dg; return; } } // Increase size of delegates[] auto len = m.delegates.length; auto startlen = len; if (len == 0) { len = 4; auto p = calloc((void delegate(Object)).sizeof, len); if (!p) _d_OutOfMemory(); m.delegates = (cast(void delegate(Object)*)p)[0 .. len]; } else { len += len + 4; auto p = realloc(m.delegates.ptr, (void delegate(Object)).sizeof * len); if (!p) _d_OutOfMemory(); m.delegates = (cast(void delegate(Object)*)p)[0 .. len]; m.delegates[startlen .. len] = null; } m.delegates[startlen] = dg; } +/ } /* ** * Remove delegate dg from the notify list. * This is only for use by library developers, as it will need to be * redone if weak pointers are added or a moving gc is developed. */ final void notifyUnRegister(void delegate(Object) dg) { /+ synchronized (this) { Monitor* m = cast(Monitor*)(cast(void**)this)[1]; foreach (inout x; m.delegates) { if (x == dg) x = null; } } +/ } /****** * Create instance of class specified by classname. * The class must either have no constructors or have * a default constructor. * Returns: * null if failed */ static Object factory(char[] classname) { /+ auto ci = ClassInfo.find(classname); if (ci) { return ci.create(); } +/ return null; } } /+ extern (C) void _d_notify_release(Object o) { //printf("_d_notify_release(o = %p)\n", o); Monitor* m = cast(Monitor*)(cast(void**)o)[1]; if (m.delegates.length) { auto dgs = m.delegates; synchronized (o) { dgs = m.delegates; m.delegates = null; } foreach (dg; dgs) { if (dg) { //printf("calling dg = %llx (%p)\n", dg, o); dg(o); } } free(dgs.ptr); } } +/ /** * Information about an interface. * A pointer to this appears as the first entry in the interface's vtbl[]. */ struct Interface { ClassInfo classinfo; /// .classinfo for this interface (not for containing class) void *[] vtbl; int offset; /// offset to Interface 'this' from Object 'this' } import std.moduleinit; /** * 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.modules()) { //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; +/ return null; } } //private import std.string; /** * 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 } private int string_cmp(char[] s1, char[] s2) { auto len = s1.length; if (s2.length < len) len = s2.length; int result = memcmp(s1.ptr, s2.ptr, len); if (result == 0) result = cast(int)(cast(ptrdiff_t)s1.length - cast(ptrdiff_t)s2.length); return result; } /** * 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 string_cmp(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(uint)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(uint)*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; } } private const char[10] digits = "0123456789"; /// 0..9 private char[] lengthToString(uint u) { char[uint.sizeof * 3] buffer = void; int ndigits; char[] result; ndigits = 0; if (u < 10) // Avoid storage allocation for simple stuff result = digits[u .. u + 1]; else { while (u) { uint c = (u % 10) + '0'; u /= 10; ndigits++; buffer[buffer.length - ndigits] = cast(char)c; } result = new char[ndigits]; result[] = buffer[buffer.length - ndigits .. buffer.length]; } return result; } private char[] lengthToString(ulong u) { char[ulong.sizeof * 3] buffer; int ndigits; char[] result; if (u < 0x1_0000_0000) return lengthToString(cast(uint)u); ndigits = 0; while (u) { char c = cast(char)((u % 10) + '0'); u /= 10; ndigits++; buffer[buffer.length - ndigits] = c; } result = new char[ndigits]; result[] = buffer[buffer.length - ndigits .. buffer.length]; return result; } class TypeInfo_StaticArray : TypeInfo { char[] toString() { return value.toString() ~ "[" ~ lengthToString(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 { if (value.flags() & 1) tmp = pbuffer = (new void[sz]).ptr; else tmp = pbuffer = (new byte[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 value.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; assert(o); return o.toHash(); } 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) { //printf("getHash() using xtoHash\n"); h = (*xtoHash)(p); } else { //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 < 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, 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, init.length); } else c = -1; } return c; } size_t tsize() { return init.length; } void[] init() { return m_init; } uint flags() { return m_flags; } char[] name; void[] m_init; // initializer; init.ptr == null if 0 initialize 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); } } class TypeInfo_Const : TypeInfo { char[] toString() { return "const " ~ base.toString(); } int opEquals(Object o) { return base.opEquals(o); } 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.next(); } uint flags() { return base.flags(); } void[] init() { return base.init(); } TypeInfo base; } class TypeInfo_Invariant : TypeInfo_Const { char[] toString() { return "invariant " ~ base.toString(); } } /** * Information about each module. */ class ModuleInfo { char[] name; ModuleInfo[] importedModules; ClassInfo[] localClasses; uint flags; // initialization state void function() ctor; void function() dtor; void function() unitTest; /****************** * Return collection of all modules in the program. */ static ModuleInfo[] modules() { return std.moduleinit._moduleinfo_array; } } /** * All recoverable exceptions should be derived from class Exception. */ class Exception : Object { char[] msg; /** * Constructor; msg is a descriptive message for the exception. */ this(char[] msg) { this.msg = msg; } void print() { char[] s = toString(); printf("%.*s\n", s.length, s.ptr); } char[] toString() { return msg; } } /** * All irrecoverable exceptions should be derived from class Error. */ class Error : Exception { Error next; /** * Constructor; msg is a descriptive message for the exception. */ this(char[] msg) { super(msg); } this(char[] msg, Error next) { super(msg); this.next = next; } } //extern (C) int nullext = 0;