1 module object;
2 
3 import util;
4 import rtoslink;
5 import lifetime.throwable;
6 
7 version(LWDR_DynamicArray)
8 public import lifetime.array_ : _d_arraysetlengthTImpl;
9 
10 version (D_LP64)
11 {
12     alias size_t = ulong;
13     alias ptrdiff_t = long;
14 }
15 else
16 {
17     alias size_t = uint;
18     alias ptrdiff_t = int;
19 }
20 
21 alias sizediff_t = ptrdiff_t; //For backwards compatibility only.
22 
23 alias hash_t = size_t; //For backwards compatibility only.
24 alias equals_t = bool; //For backwards compatibility only.
25 
26 alias string  = immutable(char)[];
27 alias wstring = immutable(wchar)[];
28 alias dstring = immutable(dchar)[];
29 
30 extern(C) void _d_assert(string f, uint l) { rtosbackend_assert(f, l); }
31 extern(C) void _d_assert_msg(string msg, string f, uint l) { rtosbackend_assertmsg(msg, f, l); }
32 extern(C) void _d_arraybounds(string f, size_t l) {rtosbackend_arrayBoundFailure(f, l);}
33 
34 extern(C) bool _xopEquals(in void*, in void*) { return false; }
35 extern(C) int _xopCmp(in void*, in void*) { return 0; }
36 
37 class Object 
38 {
39 	/// Convert Object to human readable string
40 	string toString() { return "Object"; }
41 	/// Compute hash function for Object
42 	size_t toHash() @trusted nothrow
43 	{
44 		auto addr = cast(size_t)cast(void*)this;
45 		return addr ^ (addr >>> 4);
46 	}
47 	
48 	int opCmp(Object o) { assert(false, "not implemented"); }
49 	bool opEquals(Object o) { return this is o; }
50 	
51 	static Object factory(string classname) { return null; }
52 }
53 
54 bool opEquals(Object lhs, Object rhs)
55 {
56     // If aliased to the same object or both null => equal
57     if (lhs is rhs) return true;
58 
59     // If either is null => non-equal
60     if (lhs is null || rhs is null) return false;
61 
62     if (!lhs.opEquals(rhs)) return false;
63 
64     // If same exact type => one call to method opEquals
65     if (typeid(lhs) is typeid(rhs) ||
66         !__ctfe && typeid(lhs).opEquals(typeid(rhs)))
67             /* CTFE doesn't like typeid much. 'is' works, but opEquals doesn't
68             (issue 7147). But CTFE also guarantees that equal TypeInfos are
69             always identical. So, no opEquals needed during CTFE. */
70     {
71         return true;
72     }
73 
74     // General case => symmetric calls to method opEquals
75     return rhs.opEquals(lhs);
76 }
77 
78 /************************
79 * Returns true if lhs and rhs are equal.
80 */
81 bool opEquals(const Object lhs, const Object rhs)
82 {
83     // A hack for the moment.
84     return opEquals(cast()lhs, cast()rhs);
85 }
86 
87 struct Interface
88 {
89     TypeInfo_Class   classinfo;  /// .classinfo for this interface (not for containing class)
90     void*[]     vtbl;
91     size_t      offset;     /// offset to Interface 'this' from Object 'this'
92 }
93 
94 /**
95  * Array of pairs giving the offset and type information for each
96  * member in an aggregate.
97  */
98 struct OffsetTypeInfo
99 {
100     size_t   offset;    /// Offset of member from start of object
101     TypeInfo ti;        /// TypeInfo for this member
102 }
103 //enum immutable(void)* rtinfoHasPointers = cast(void*)1;
104 
105 version(LWDR_DynamicArray)
106 {
107     version = LWDR_INTERNAL_ti_next;
108 }
109 
110 class TypeInfo 
111 {
112     /// Compares two instances for equality.
113 	bool equals(in void* p1, in void* p2) const { return p1 == p2; }
114 
115     /// Returns size of the type.
116     @property size_t tsize() nothrow pure const @safe @nogc { return 0; }
117 
118 	/** Get TypeInfo for 'next' type, as defined by what kind of type this is,
119     null if none. */
120     version(LWDR_INTERNAL_ti_next)
121     @property inout(TypeInfo) next() nothrow pure inout @nogc { return null; }
122 
123     /**
124 	* Return default initializer.  If the type should be initialized to all
125 	* zeros, an array with a null ptr and a length equal to the type size will
126 	* be returned. For static arrays, this returns the default initializer for
127 	* a single element of the array, use `tsize` to get the correct size.
128 	*/
129     abstract const(void)[] initializer() nothrow pure const @safe @nogc;
130 }
131 
132 class TypeInfo_Enum : TypeInfo 
133 {
134 	TypeInfo base;
135 	string name;
136 	void[] m_init; 
137 	
138 	override bool equals(in void* p1, in void* p2) const
139 	{ return base.equals(p1, p2); }
140     override @property size_t tsize() nothrow pure const { return base.tsize; }
141 
142 	override const(void)[] initializer() const
143     { return m_init.length ? m_init : base.initializer(); }
144 
145     version(LWDR_INTERNAL_ti_next)
146     override @property inout(TypeInfo) next() nothrow pure inout 
147 	{ return base.next; }
148 }
149 
150 class TypeInfo_Pointer : TypeInfo 
151 { 
152     TypeInfo m_next; 
153 
154     override bool equals(in void* p1, in void* p2) const
155 	{ return *cast(void**)p1 == *cast(void**)p2; }
156     override @property size_t tsize() nothrow pure const { return (void*).sizeof; }
157 
158 	override const(void)[] initializer() const @trusted
159     { return (cast(void *)null)[0 .. (void*).sizeof]; }
160 
161     version(LWDR_INTERNAL_ti_next)
162     override @property inout(TypeInfo) next() nothrow pure inout 
163 	{ return m_next; }
164 }
165 
166 class TypeInfo_Array : TypeInfo 
167 {
168 	TypeInfo value;
169 
170     override bool equals(in void* p1, in void* p2) const
171 	{
172         void[] a1 = *cast(void[]*)p1;
173         void[] a2 = *cast(void[]*)p2;
174         if(a1.length != a2.length) return false;
175         immutable sz = value.tsize;
176         foreach(size_t i; 0 .. a1.length)
177             if(!value.equals(a1.ptr + i * sz, a2.ptr + i * sz))
178                 return false;
179         return true;
180 	}
181 
182     override @property size_t tsize() nothrow pure const
183     { return (void[]).sizeof; }
184 
185 	override const(void)[] initializer() const @trusted
186     { return (cast(void *)null)[0 .. (void[]).sizeof]; }
187 
188     version(LWDR_INTERNAL_ti_next)
189     override @property inout(TypeInfo) next() nothrow pure inout
190     { return value; }
191 }
192 
193 class TypeInfo_StaticArray : TypeInfo 
194 { 
195 	TypeInfo value;
196 	size_t len;
197 
198 	override bool equals(in void* p1, in void* p2) const
199     {
200         size_t sz = value.tsize;
201 
202         for (size_t u = 0; u < len; u++)
203             if (!value.equals(p1 + u * sz, p2 + u * sz))
204                 return false;
205         return true;
206     }
207 
208     override @property size_t tsize() nothrow pure const
209     { return len * value.tsize; }
210 
211     override const(void)[] initializer() nothrow pure const
212     { return value.initializer(); }
213 
214     version(LWDR_INTERNAL_ti_next)
215     override @property inout(TypeInfo) next() nothrow pure inout 
216 	{ return value; }
217 }
218 
219 class TypeInfo_AssociativeArray : TypeInfo {
220 	TypeInfo value, key;
221 
222 	override const(void)[] initializer() const @trusted
223     { return (cast(void *)null)[0 .. (char[int]).sizeof]; }
224 
225     version(LWDR_INTERNAL_ti_next)
226     override @property inout(TypeInfo) next() nothrow pure inout { return value; }
227 }
228 
229 class TypeInfo_Vector : TypeInfo 
230 {
231     TypeInfo base;
232 
233     override bool equals(in void* p1, in void* p2) const { return base.equals(p1, p2); }
234 
235 	override const(void)[] initializer() nothrow pure const
236     { return base.initializer(); }
237 
238     version(LWDR_INTERNAL_ti_next)
239     override @property inout(TypeInfo) next() nothrow pure inout 
240 	{ return base.next; }
241 }
242 
243 class TypeInfo_Function : TypeInfo 
244 {
245 	string deco;
246 
247     override const(void)[] initializer() const @safe
248     {
249         return null;
250     }
251 }
252 
253 class TypeInfo_Delegate : TypeInfo 
254 {
255 	string deco; 
256 
257     override bool equals(in void* p1, in void* p2) const
258     {
259         auto dg1 = *cast(void delegate()*)p1;
260         auto dg2 = *cast(void delegate()*)p2;
261         return dg1 == dg2;
262     }
263 
264     override const(void)[] initializer() const @trusted
265     {
266         return (cast(void *)null)[0 .. (int delegate()).sizeof];
267     }
268 }
269 
270 //class TypeInfo_v : TypeInfo { const: nothrow: pure: @trusted: }
271 
272 class TypeInfo_Interface : TypeInfo 
273 {
274 	TypeInfo_Class info;
275 	
276 	override bool equals(in void* p1, in void* p2) const
277     {
278         Interface* pi = **cast(Interface ***)*cast(void**)p1;
279         Object o1 = cast(Object)(*cast(void**)p1 - pi.offset);
280         pi = **cast(Interface ***)*cast(void**)p2;
281         Object o2 = cast(Object)(*cast(void**)p2 - pi.offset);
282 
283         return o1 == o2 || (o1 && o1.opCmp(o2) == 0);
284     }
285 
286 	override const(void)[] initializer() const @trusted
287     {
288         return (cast(void *)null)[0 .. Object.sizeof];
289     }
290 
291     override @property size_t tsize() nothrow pure const
292     {
293         return Object.sizeof;
294     }
295 }
296 
297 class TypeInfo_Tuple : TypeInfo
298 {
299     TypeInfo[] elements;
300 
301 	override bool opEquals(Object o)
302     {
303         if (this is o)
304             return true;
305 
306         auto t = cast(const TypeInfo_Tuple)o;
307         if (t && elements.length == t.elements.length)
308         {
309             for (size_t i = 0; i < elements.length; i++)
310                 if (elements[i] != t.elements[i])
311                     return false;
312             return true;
313         }
314         return false;
315     }
316 
317 	override @property size_t tsize() nothrow pure const
318     {
319         assert(0);
320     }
321 
322     override const(void)[] initializer() const @trusted
323     {
324         assert(0);
325     }
326 }
327 
328 class TypeInfo_Class : TypeInfo 
329 {
330 	ubyte[] m_init; /// class static initializer (length gives class size)
331 	string name; /// name of class
332 	void*[] vtbl; // virtual function pointer table
333 	Interface[] interfaces;
334 	TypeInfo_Class base;
335 	void* destructor;
336 	void function(Object) classInvariant;
337 	uint m_flags;
338 	void* deallocator;
339 	void*[] m_offTi;
340 	void function(Object) defaultConstructor;
341 	immutable(void)* rtInfo;
342 
343 	override @property size_t tsize() nothrow pure const
344     { return Object.sizeof; }
345 
346 	override bool equals(in void* p1, in void* p2) const
347     {
348         Object o1 = *cast(Object*)p1;
349         Object o2 = *cast(Object*)p2;
350 
351         return (o1 is o2) || (o1 && o1.opEquals(o2));
352     }
353 
354 	override const(void)[] initializer() nothrow pure const @safe
355     {
356         return m_init;
357     }
358 }
359 alias ClassInfo = TypeInfo_Class;
360 
361 class TypeInfo_Const : TypeInfo {
362 	size_t getHash(scope const void*) const nothrow { return 0; }
363 	TypeInfo base; 
364 
365     override bool equals(in void *p1, in void *p2) const { return base.equals(p1, p2); }
366 
367     override @property size_t tsize() nothrow pure const { return base.tsize; }
368 
369     version(LWDR_INTERNAL_ti_next)
370     override @property inout(TypeInfo) next() nothrow pure inout 
371 	{ return base.next; }
372 
373 	override const(void)[] initializer() nothrow pure const
374     { return base.initializer(); }
375 }
376 
377 class TypeInfo_Struct : TypeInfo {
378 	string name;
379 	void[] m_init;
380 	void* xtohash;
381 	void* xopequals;
382 	void* xopcmp;
383 	void* xtostring;
384 	uint flags;
385 	union {
386 		void function(void*) dtor;
387 		void function(void*, const TypeInfo_Struct) xdtor;
388 	}
389 	void function(void*) postblit;
390 	uint align_;
391 	immutable(void)* rtinfo;
392 
393     override bool equals(in void* p1, in void* p2) @trusted pure nothrow const
394     {
395         if (!p1 || !p2)
396             return false;
397         else if (xopequals)
398             return (*cast(bool function(in void*, in void*) pure nothrow @safe *)xopequals)(p1, p2);
399         else if (p1 == p2)
400             return true;
401         else
402 		{
403             immutable len = m_init.length;
404             auto p1B = cast(ubyte[])p1[0..len];
405             auto p2B = cast(ubyte[])p2[0..len];
406             foreach(i; 0 .. len)
407 			    if(p1B[i] != p2B[i]) 
408                     return false;
409             return true;
410 		}
411     }
412 
413     override @property size_t tsize() nothrow pure const
414     {
415         return initializer().length;
416     }
417 
418     override const(void)[] initializer() nothrow pure const @safe
419     {
420         return m_init;
421     }
422 }
423 
424 class TypeInfo_Invariant : TypeInfo_Const {}
425 class TypeInfo_Shared : TypeInfo_Const {}
426 class TypeInfo_Inout : TypeInfo_Const {}
427 
428 class Throwable : Object 
429 {
430 	interface TraceInfo
431 	{
432 		int opApply(scope int delegate(ref const(char[]))) const;
433 		int opApply(scope int delegate(ref size_t, ref const(char[]))) const;
434 		string toString() const;
435 	}
436 	
437 	string msg;
438 	string file;
439 	size_t line;
440 	TraceInfo info;
441 	
442 	private Throwable nextInChain;
443 	
444 	private uint _refcount;
445 	
446 	@property inout(Throwable) next() @safe inout return scope pure nothrow @nogc { return nextInChain; }
447 	@property void next(Throwable tail) @safe scope nothrow @nogc
448     {
449         if (tail && tail._refcount)
450             ++tail._refcount;           // increment the replacement *first*
451 
452         auto n = nextInChain;
453         nextInChain = null;             // sever the tail before deleting it
454 
455         if (n && n._refcount)
456             _d_delThrowable(n);         // now delete the old tail
457 
458         nextInChain = tail;             // and set the new tail
459     }
460 	 @system @nogc final pure nothrow ref uint refcount() return { return _refcount; }
461 	 int opApply(scope int delegate(Throwable) dg)
462     {
463         int result = 0;
464         for (Throwable t = this; t; t = t.nextInChain)
465         {
466             result = dg(t);
467             if (result)
468                 break;
469         }
470         return result;
471     }
472 	static @__future @system @nogc pure nothrow Throwable chainTogether(return scope Throwable e1, return scope Throwable e2)
473     {
474         if (!e1)
475             return e2;
476         if (!e2)
477             return e1;
478         if (e2.refcount())
479             ++e2.refcount();
480 
481         for (auto e = e1; 1; e = e.nextInChain)
482         {
483             if (!e.nextInChain)
484             {
485                 e.nextInChain = e2;
486                 break;
487             }
488         }
489         return e1;
490     }
491 	@nogc @safe pure nothrow this(string msg, Throwable nextInChain = null)
492     {
493         this.msg = msg;
494         this.nextInChain = nextInChain;
495         //this.info = _d_traceContext();
496     }
497 	@nogc @safe pure nothrow this(string msg, string file, size_t line, Throwable nextInChain = null)
498     {
499         this(msg, nextInChain);
500         this.file = file;
501         this.line = line;
502         //this.info = _d_traceContext();
503     }
504 	@trusted nothrow ~this()
505     {
506         if (nextInChain && nextInChain._refcount)
507             _d_delThrowable(nextInChain);
508     }
509 	
510 	@__future const(char)[] message() const
511     {
512         return this.msg;
513     }
514 }
515 
516 class Exception : Throwable
517 {
518     @nogc @safe pure nothrow this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable nextInChain = null)
519     {
520         super(msg, file, line, nextInChain);
521     }
522 
523     @nogc @safe pure nothrow this(string msg, Throwable nextInChain, string file = __FILE__, size_t line = __LINE__)
524     {
525         super(msg, file, line, nextInChain);
526     }
527 }
528 
529 class Error : Throwable
530 {
531     @nogc @safe pure nothrow this(string msg, Throwable nextInChain = null)
532     {
533         super(msg, nextInChain);
534         bypassedException = null;
535     }
536 
537     @nogc @safe pure nothrow this(string msg, string file, size_t line, Throwable nextInChain = null)
538     {
539         super(msg, file, line, nextInChain);
540         bypassedException = null;
541     }
542 	
543     Throwable bypassedException;
544 }
545 
546 bool __equals(T1, T2)(scope const T1[] lhs, scope const T2[] rhs)
547 @nogc nothrow pure @trusted
548 if (__traits(isScalar, T1) && __traits(isScalar, T2))
549 {
550     if (lhs.length != rhs.length)
551         return false;
552 
553     foreach (const i; 0 .. lhs.length)
554         if (lhs.ptr[i] != rhs.ptr[i])
555             return false;
556     return true;
557 }
558 
559 // Used in Exception Handling LSDA tables to 'wrap' C++ type info
560 // so it can be distinguished from D TypeInfo
561 class __cpp_type_info_ptr
562 {
563     void* ptr;          // opaque pointer to C++ RTTI type info
564 }