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 }