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 public import rt.arrcast : __ArrayCast; 11 12 version (D_LP64) 13 { 14 alias size_t = ulong; 15 alias ptrdiff_t = long; 16 } 17 else 18 { 19 alias size_t = uint; 20 alias ptrdiff_t = int; 21 } 22 23 alias sizediff_t = ptrdiff_t; //For backwards compatibility only. 24 25 alias hash_t = size_t; //For backwards compatibility only. 26 alias equals_t = bool; //For backwards compatibility only. 27 28 alias string = immutable(char)[]; 29 alias wstring = immutable(wchar)[]; 30 alias dstring = immutable(dchar)[]; 31 32 /// assert(bool exp) was called 33 extern(C) void _d_assert(string f, uint l) { rtosbackend_assert(f, l); } 34 /// assert(bool exp, string msg) was called 35 extern(C) void _d_assert_msg(string msg, string f, uint l) { rtosbackend_assertmsg(msg, f, l); } 36 /// A D array was incorrectly accessed 37 extern(C) void _d_arraybounds(string f, size_t l) {rtosbackend_arrayBoundFailure(f, l);} 38 39 extern(C) bool _xopEquals(in void*, in void*) { return false; } 40 extern(C) int _xopCmp(in void*, in void*) { return 0; } 41 42 /// Base Object class. All other classes implicitly inherit this. 43 class Object 44 { 45 /// Convert Object to human readable string 46 string toString() { return "Object"; } 47 /// Compute hash function for Object 48 size_t toHash() @trusted nothrow 49 { 50 auto addr = cast(size_t)cast(void*)this; 51 return addr ^ (addr >>> 4); 52 } 53 54 /// Compare against another object. NOT IMPLEMENTED! 55 int opCmp(Object o) { assert(false, "not implemented"); } 56 /// Check equivalence againt another object 57 bool opEquals(Object o) { return this is o; } 58 59 /++ Object factory. NOT IMPLEMENTED! 60 ++/ 61 static Object factory(string classname) { return null; } 62 63 version(LWDR_Sync) 64 { 65 interface Monitor 66 { 67 /// Lock the monitor 68 void lock(); 69 /// Unlock the monitor 70 void unlock(); 71 } 72 } 73 } 74 75 /// Compare to objects 76 bool opEquals(Object lhs, Object rhs) 77 { 78 // If aliased to the same object or both null => equal 79 if (lhs is rhs) return true; 80 81 // If either is null => non-equal 82 if (lhs is null || rhs is null) return false; 83 84 if (!lhs.opEquals(rhs)) return false; 85 86 // If same exact type => one call to method opEquals 87 if (typeid(lhs) is typeid(rhs) || 88 !__ctfe && typeid(lhs).opEquals(typeid(rhs))) 89 /* CTFE doesn't like typeid much. 'is' works, but opEquals doesn't 90 (issue 7147). But CTFE also guarantees that equal TypeInfos are 91 always identical. So, no opEquals needed during CTFE. */ 92 { 93 return true; 94 } 95 96 // General case => symmetric calls to method opEquals 97 return rhs.opEquals(lhs); 98 } 99 100 /************************ 101 * Returns true if lhs and rhs are equal. 102 */ 103 bool opEquals(const Object lhs, const Object rhs) 104 { 105 // A hack for the moment. 106 return opEquals(cast()lhs, cast()rhs); 107 } 108 109 /// Raw implementation of an interface 110 struct Interface 111 { 112 TypeInfo_Class classinfo; /// .classinfo for this interface (not for containing class) 113 void*[] vtbl; 114 size_t offset; /// offset to Interface 'this' from Object 'this' 115 } 116 117 /** 118 * Array of pairs giving the offset and type information for each 119 * member in an aggregate. 120 */ 121 struct OffsetTypeInfo 122 { 123 size_t offset; /// Offset of member from start of object 124 TypeInfo ti; /// TypeInfo for this member 125 } 126 //enum immutable(void)* rtinfoHasPointers = cast(void*)1; 127 128 version(LWDR_DynamicArray) 129 { 130 version = LWDR_INTERNAL_ti_next; 131 } 132 133 /// TypeInfo contains necessary RTTI for a target type. 134 class TypeInfo 135 { 136 /// Compares two instances for equality. 137 bool equals(in void* p1, in void* p2) const { return p1 == p2; } 138 139 /// Returns size of the type. 140 @property size_t tsize() nothrow pure const @safe @nogc { return 0; } 141 142 /** Get TypeInfo for 'next' type, as defined by what kind of type this is, 143 null if none. */ 144 version(LWDR_INTERNAL_ti_next) 145 @property inout(TypeInfo) next() nothrow pure inout @nogc { return null; } 146 147 /** 148 * Return default initializer. If the type should be initialized to all 149 * zeros, an array with a null ptr and a length equal to the type size will 150 * be returned. For static arrays, this returns the default initializer for 151 * a single element of the array, use `tsize` to get the correct size. 152 */ 153 abstract const(void)[] initializer() nothrow pure const @safe @nogc; 154 } 155 156 class TypeInfo_Enum : TypeInfo 157 { 158 TypeInfo base; 159 string name; 160 void[] m_init; 161 162 override bool equals(in void* p1, in void* p2) const 163 { return base.equals(p1, p2); } 164 override @property size_t tsize() nothrow pure const { return base.tsize; } 165 166 override const(void)[] initializer() const 167 { return m_init.length ? m_init : base.initializer(); } 168 169 version(LWDR_INTERNAL_ti_next) 170 override @property inout(TypeInfo) next() nothrow pure inout 171 { return base.next; } 172 } 173 174 class TypeInfo_Pointer : TypeInfo 175 { 176 TypeInfo m_next; 177 178 override bool equals(in void* p1, in void* p2) const 179 { return *cast(void**)p1 == *cast(void**)p2; } 180 override @property size_t tsize() nothrow pure const { return (void*).sizeof; } 181 182 override const(void)[] initializer() const @trusted 183 { return (cast(void *)null)[0 .. (void*).sizeof]; } 184 185 version(LWDR_INTERNAL_ti_next) 186 override @property inout(TypeInfo) next() nothrow pure inout 187 { return m_next; } 188 } 189 190 class TypeInfo_Array : TypeInfo 191 { 192 TypeInfo value; 193 194 override bool equals(in void* p1, in void* p2) const 195 { 196 void[] a1 = *cast(void[]*)p1; 197 void[] a2 = *cast(void[]*)p2; 198 if(a1.length != a2.length) return false; 199 immutable sz = value.tsize; 200 foreach(size_t i; 0 .. a1.length) 201 if(!value.equals(a1.ptr + i * sz, a2.ptr + i * sz)) 202 return false; 203 return true; 204 } 205 206 override @property size_t tsize() nothrow pure const 207 { return (void[]).sizeof; } 208 209 override const(void)[] initializer() const @trusted 210 { return (cast(void *)null)[0 .. (void[]).sizeof]; } 211 212 version(LWDR_INTERNAL_ti_next) 213 override @property inout(TypeInfo) next() nothrow pure inout 214 { return value; } 215 } 216 217 class TypeInfo_StaticArray : TypeInfo 218 { 219 TypeInfo value; 220 size_t len; 221 222 override bool equals(in void* p1, in void* p2) const 223 { 224 size_t sz = value.tsize; 225 226 for (size_t u = 0; u < len; u++) 227 if (!value.equals(p1 + u * sz, p2 + u * sz)) 228 return false; 229 return true; 230 } 231 232 override @property size_t tsize() nothrow pure const 233 { return len * value.tsize; } 234 235 override const(void)[] initializer() nothrow pure const 236 { return value.initializer(); } 237 238 version(LWDR_INTERNAL_ti_next) 239 override @property inout(TypeInfo) next() nothrow pure inout 240 { return value; } 241 } 242 243 class TypeInfo_AssociativeArray : TypeInfo { 244 TypeInfo value, key; 245 246 override const(void)[] initializer() const @trusted 247 { return (cast(void *)null)[0 .. (char[int]).sizeof]; } 248 249 version(LWDR_INTERNAL_ti_next) 250 override @property inout(TypeInfo) next() nothrow pure inout { return value; } 251 } 252 253 class TypeInfo_Vector : TypeInfo 254 { 255 TypeInfo base; 256 257 override bool equals(in void* p1, in void* p2) const { return base.equals(p1, p2); } 258 259 override const(void)[] initializer() nothrow pure const 260 { return base.initializer(); } 261 262 version(LWDR_INTERNAL_ti_next) 263 override @property inout(TypeInfo) next() nothrow pure inout 264 { return base.next; } 265 } 266 267 class TypeInfo_Function : TypeInfo 268 { 269 string deco; 270 271 override const(void)[] initializer() const @safe 272 { 273 return null; 274 } 275 } 276 277 class TypeInfo_Delegate : TypeInfo 278 { 279 string deco; 280 281 override bool equals(in void* p1, in void* p2) const 282 { 283 auto dg1 = *cast(void delegate()*)p1; 284 auto dg2 = *cast(void delegate()*)p2; 285 return dg1 == dg2; 286 } 287 288 override const(void)[] initializer() const @trusted 289 { 290 return (cast(void *)null)[0 .. (int delegate()).sizeof]; 291 } 292 } 293 294 //class TypeInfo_v : TypeInfo { const: nothrow: pure: @trusted: } 295 296 class TypeInfo_Interface : TypeInfo 297 { 298 TypeInfo_Class info; 299 300 override bool equals(in void* p1, in void* p2) const 301 { 302 Interface* pi = **cast(Interface ***)*cast(void**)p1; 303 Object o1 = cast(Object)(*cast(void**)p1 - pi.offset); 304 pi = **cast(Interface ***)*cast(void**)p2; 305 Object o2 = cast(Object)(*cast(void**)p2 - pi.offset); 306 307 return o1 == o2 || (o1 && o1.opCmp(o2) == 0); 308 } 309 310 override const(void)[] initializer() const @trusted 311 { 312 return (cast(void *)null)[0 .. Object.sizeof]; 313 } 314 315 override @property size_t tsize() nothrow pure const 316 { 317 return Object.sizeof; 318 } 319 } 320 321 class TypeInfo_Tuple : TypeInfo 322 { 323 TypeInfo[] elements; 324 325 override bool opEquals(Object o) 326 { 327 if (this is o) 328 return true; 329 330 auto t = cast(const TypeInfo_Tuple)o; 331 if (t && elements.length == t.elements.length) 332 { 333 for (size_t i = 0; i < elements.length; i++) 334 if (elements[i] != t.elements[i]) 335 return false; 336 return true; 337 } 338 return false; 339 } 340 341 override @property size_t tsize() nothrow pure const 342 { 343 assert(0); 344 } 345 346 override const(void)[] initializer() const @trusted 347 { 348 assert(0); 349 } 350 } 351 352 class TypeInfo_Class : TypeInfo 353 { 354 ubyte[] m_init; /// class static initializer (length gives class size) 355 string name; /// name of class 356 void*[] vtbl; // virtual function pointer table 357 Interface[] interfaces; 358 TypeInfo_Class base; 359 void* destructor; 360 void function(Object) classInvariant; 361 uint m_flags; 362 void* deallocator; 363 void*[] m_offTi; 364 void function(Object) defaultConstructor; 365 immutable(void)* rtInfo; 366 367 override @property size_t tsize() nothrow pure const 368 { return Object.sizeof; } 369 370 override bool equals(in void* p1, in void* p2) const 371 { 372 Object o1 = *cast(Object*)p1; 373 Object o2 = *cast(Object*)p2; 374 375 return (o1 is o2) || (o1 && o1.opEquals(o2)); 376 } 377 378 override const(void)[] initializer() nothrow pure const @safe 379 { 380 return m_init; 381 } 382 } 383 alias ClassInfo = TypeInfo_Class; 384 385 class TypeInfo_Const : TypeInfo { 386 size_t getHash(scope const void*) const nothrow { return 0; } 387 TypeInfo base; 388 389 override bool equals(in void *p1, in void *p2) const { return base.equals(p1, p2); } 390 391 override @property size_t tsize() nothrow pure const { return base.tsize; } 392 393 version(LWDR_INTERNAL_ti_next) 394 override @property inout(TypeInfo) next() nothrow pure inout 395 { return base.next; } 396 397 override const(void)[] initializer() nothrow pure const 398 { return base.initializer(); } 399 } 400 401 class TypeInfo_Struct : TypeInfo { 402 string name; 403 void[] m_init; 404 void* xtohash; 405 void* xopequals; 406 void* xopcmp; 407 void* xtostring; 408 uint flags; 409 union { 410 void function(void*) dtor; 411 void function(void*, const TypeInfo_Struct) xdtor; 412 } 413 void function(void*) postblit; 414 uint align_; 415 immutable(void)* rtinfo; 416 417 override bool equals(in void* p1, in void* p2) @trusted pure nothrow const 418 { 419 if (!p1 || !p2) 420 return false; 421 else if (xopequals) 422 return (*cast(bool function(in void*, in void*) pure nothrow @safe *)xopequals)(p1, p2); 423 else if (p1 == p2) 424 return true; 425 else 426 { 427 immutable len = m_init.length; 428 auto p1B = cast(ubyte[])p1[0..len]; 429 auto p2B = cast(ubyte[])p2[0..len]; 430 foreach(i; 0 .. len) 431 if(p1B[i] != p2B[i]) 432 return false; 433 return true; 434 } 435 } 436 437 override @property size_t tsize() nothrow pure const 438 { 439 return initializer().length; 440 } 441 442 override const(void)[] initializer() nothrow pure const @safe 443 { 444 return m_init; 445 } 446 } 447 448 class TypeInfo_Invariant : TypeInfo_Const {} 449 class TypeInfo_Shared : TypeInfo_Const {} 450 class TypeInfo_Inout : TypeInfo_Const {} 451 452 class Throwable : Object 453 { 454 interface TraceInfo 455 { 456 int opApply(scope int delegate(ref const(char[]))) const; 457 int opApply(scope int delegate(ref size_t, ref const(char[]))) const; 458 string toString() const; 459 } 460 461 string msg; 462 string file; 463 size_t line; 464 TraceInfo info; 465 466 private Throwable nextInChain; 467 468 private uint _refcount; 469 470 @property inout(Throwable) next() @safe inout return scope pure nothrow @nogc { return nextInChain; } 471 @property void next(Throwable tail) @safe scope nothrow @nogc 472 { 473 if (tail && tail._refcount) 474 ++tail._refcount; // increment the replacement *first* 475 476 auto n = nextInChain; 477 nextInChain = null; // sever the tail before deleting it 478 479 if (n && n._refcount) 480 _d_delThrowable(n); // now delete the old tail 481 482 nextInChain = tail; // and set the new tail 483 } 484 @system @nogc final pure nothrow ref uint refcount() return { return _refcount; } 485 int opApply(scope int delegate(Throwable) dg) 486 { 487 int result = 0; 488 for (Throwable t = this; t; t = t.nextInChain) 489 { 490 result = dg(t); 491 if (result) 492 break; 493 } 494 return result; 495 } 496 static @__future @system @nogc pure nothrow Throwable chainTogether(return scope Throwable e1, return scope Throwable e2) 497 { 498 if (!e1) 499 return e2; 500 if (!e2) 501 return e1; 502 if (e2.refcount()) 503 ++e2.refcount(); 504 505 for (auto e = e1; 1; e = e.nextInChain) 506 { 507 if (!e.nextInChain) 508 { 509 e.nextInChain = e2; 510 break; 511 } 512 } 513 return e1; 514 } 515 @nogc @safe pure nothrow this(string msg, Throwable nextInChain = null) 516 { 517 this.msg = msg; 518 this.nextInChain = nextInChain; 519 //this.info = _d_traceContext(); 520 } 521 @nogc @safe pure nothrow this(string msg, string file, size_t line, Throwable nextInChain = null) 522 { 523 this(msg, nextInChain); 524 this.file = file; 525 this.line = line; 526 //this.info = _d_traceContext(); 527 } 528 @trusted nothrow ~this() 529 { 530 if (nextInChain && nextInChain._refcount) 531 _d_delThrowable(nextInChain); 532 } 533 534 @__future const(char)[] message() const 535 { 536 return this.msg; 537 } 538 } 539 540 class Exception : Throwable 541 { 542 @nogc @safe pure nothrow this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable nextInChain = null) 543 { 544 super(msg, file, line, nextInChain); 545 } 546 547 @nogc @safe pure nothrow this(string msg, Throwable nextInChain, string file = __FILE__, size_t line = __LINE__) 548 { 549 super(msg, file, line, nextInChain); 550 } 551 } 552 553 class Error : Throwable 554 { 555 @nogc @safe pure nothrow this(string msg, Throwable nextInChain = null) 556 { 557 super(msg, nextInChain); 558 bypassedException = null; 559 } 560 561 @nogc @safe pure nothrow this(string msg, string file, size_t line, Throwable nextInChain = null) 562 { 563 super(msg, file, line, nextInChain); 564 bypassedException = null; 565 } 566 567 Throwable bypassedException; 568 } 569 570 bool __equals(T1, T2)(scope const T1[] lhs, scope const T2[] rhs) 571 @nogc nothrow pure @trusted 572 if (__traits(isScalar, T1) && __traits(isScalar, T2)) 573 { 574 if (lhs.length != rhs.length) 575 return false; 576 577 foreach (const i; 0 .. lhs.length) 578 if (lhs.ptr[i] != rhs.ptr[i]) 579 return false; 580 return true; 581 } 582 583 // Used in Exception Handling LSDA tables to 'wrap' C++ type info 584 // so it can be distinguished from D TypeInfo 585 class __cpp_type_info_ptr 586 { 587 void* ptr; // opaque pointer to C++ RTTI type info 588 } 589 590 // Contents of Moduleinfo._flags 591 enum 592 { 593 MIctorstart = 0x1, // we've started constructing it 594 MIctordone = 0x2, // finished construction 595 MIstandalone = 0x4, // module ctor does not depend on other module 596 // ctors being done first 597 MItlsctor = 8, 598 MItlsdtor = 0x10, 599 MIctor = 0x20, 600 MIdtor = 0x40, 601 MIxgetMembers = 0x80, 602 MIictor = 0x100, 603 MIunitTest = 0x200, 604 MIimportedModules = 0x400, 605 MIlocalClasses = 0x800, 606 MIname = 0x1000, 607 } 608 609 /***************************************** 610 * An instance of ModuleInfo is generated into the object file for each compiled module. 611 * 612 * It provides access to various aspects of the module. 613 * It is not generated for betterC. 614 */ 615 version(LWDR_ModuleCtors) 616 struct ModuleInfo 617 { 618 uint _flags; // MIxxxx 619 uint _index; // index into _moduleinfo_array[] 620 621 version (all) 622 { 623 deprecated("ModuleInfo cannot be copy-assigned because it is a variable-sized struct.") 624 void opAssign(const scope ModuleInfo m) { _flags = m._flags; _index = m._index; } 625 } 626 else 627 { 628 @disable this(); 629 } 630 631 const: 632 private void* addrOf(int flag) return nothrow pure @nogc 633 in 634 { 635 assert(flag >= MItlsctor && flag <= MIname); 636 assert(!(flag & (flag - 1)) && !(flag & ~(flag - 1) << 1)); 637 } 638 do 639 { 640 import core.stdc.string : strlen; 641 642 void* p = cast(void*)&this + ModuleInfo.sizeof; 643 644 if (flags & MItlsctor) 645 { 646 if (flag == MItlsctor) return p; 647 p += typeof(tlsctor).sizeof; 648 } 649 if (flags & MItlsdtor) 650 { 651 if (flag == MItlsdtor) return p; 652 p += typeof(tlsdtor).sizeof; 653 } 654 if (flags & MIctor) 655 { 656 if (flag == MIctor) return p; 657 p += typeof(ctor).sizeof; 658 } 659 if (flags & MIdtor) 660 { 661 if (flag == MIdtor) return p; 662 p += typeof(dtor).sizeof; 663 } 664 if (flags & MIxgetMembers) 665 { 666 if (flag == MIxgetMembers) return p; 667 p += typeof(xgetMembers).sizeof; 668 } 669 if (flags & MIictor) 670 { 671 if (flag == MIictor) return p; 672 p += typeof(ictor).sizeof; 673 } 674 if (flags & MIunitTest) 675 { 676 if (flag == MIunitTest) return p; 677 version(unittest) 678 p += typeof(unitTest).sizeof; 679 else 680 p += (void function()).sizeof; 681 } 682 if (flags & MIimportedModules) 683 { 684 if (flag == MIimportedModules) return p; 685 p += size_t.sizeof + *cast(size_t*)p * typeof(importedModules[0]).sizeof; 686 } 687 if (flags & MIlocalClasses) 688 { 689 if (flag == MIlocalClasses) return p; 690 p += size_t.sizeof + *cast(size_t*)p * typeof(localClasses[0]).sizeof; 691 } 692 if (true || flags & MIname) // always available for now 693 { 694 if (flag == MIname) return p; 695 p += strlen(cast(immutable char*)p); 696 } 697 assert(0); 698 } 699 700 @property uint index() nothrow pure @nogc { return _index; } 701 702 @property uint flags() nothrow pure @nogc { return _flags; } 703 704 /************************ 705 * Returns: 706 * module constructor for thread locals, `null` if there isn't one 707 */ 708 @property void function() tlsctor() nothrow pure @nogc 709 { 710 return flags & MItlsctor ? *cast(typeof(return)*)addrOf(MItlsctor) : null; 711 } 712 713 /************************ 714 * Returns: 715 * module destructor for thread locals, `null` if there isn't one 716 */ 717 @property void function() tlsdtor() nothrow pure @nogc 718 { 719 return flags & MItlsdtor ? *cast(typeof(return)*)addrOf(MItlsdtor) : null; 720 } 721 722 /***************************** 723 * Returns: 724 * address of a module's `const(MemberInfo)[] getMembers(string)` function, `null` if there isn't one 725 */ 726 @property void* xgetMembers() nothrow pure @nogc 727 { 728 return flags & MIxgetMembers ? *cast(typeof(return)*)addrOf(MIxgetMembers) : null; 729 } 730 731 /************************ 732 * Returns: 733 * module constructor, `null` if there isn't one 734 */ 735 @property void function() ctor() nothrow pure @nogc 736 { 737 return flags & MIctor ? *cast(typeof(return)*)addrOf(MIctor) : null; 738 } 739 740 /************************ 741 * Returns: 742 * module destructor, `null` if there isn't one 743 */ 744 @property void function() dtor() nothrow pure @nogc 745 { 746 return flags & MIdtor ? *cast(typeof(return)*)addrOf(MIdtor) : null; 747 } 748 749 /************************ 750 * Returns: 751 * module order independent constructor, `null` if there isn't one 752 */ 753 @property void function() ictor() nothrow pure @nogc 754 { 755 return flags & MIictor ? *cast(typeof(return)*)addrOf(MIictor) : null; 756 } 757 758 /************* 759 * Returns: 760 * address of function that runs the module's unittests, `null` if there isn't one 761 */ 762 version(unittest) 763 @property void function() unitTest() nothrow pure @nogc 764 { 765 return flags & MIunitTest ? *cast(typeof(return)*)addrOf(MIunitTest) : null; 766 } 767 768 /**************** 769 * Returns: 770 * array of pointers to the ModuleInfo's of modules imported by this one 771 */ 772 @property immutable(ModuleInfo*)[] importedModules() return nothrow pure @nogc 773 { 774 if (flags & MIimportedModules) 775 { 776 auto p = cast(size_t*)addrOf(MIimportedModules); 777 return (cast(immutable(ModuleInfo*)*)(p + 1))[0 .. *p]; 778 } 779 return null; 780 } 781 782 /**************** 783 * Returns: 784 * array of TypeInfo_Class references for classes defined in this module 785 */ 786 @property TypeInfo_Class[] localClasses() return nothrow pure @nogc 787 { 788 if (flags & MIlocalClasses) 789 { 790 auto p = cast(size_t*)addrOf(MIlocalClasses); 791 return (cast(TypeInfo_Class*)(p + 1))[0 .. *p]; 792 } 793 return null; 794 } 795 796 /******************** 797 * Returns: 798 * name of module, `null` if no name 799 */ 800 @property string name() return nothrow pure @nogc 801 { 802 import core.stdc.string : strlen; 803 804 auto p = cast(immutable char*) addrOf(MIname); 805 return p[0 .. strlen(p)]; 806 } 807 }