1 /** 2 * Part of the D programming language runtime library. 3 * Forms the symbols available to all D programs. Includes 4 * Object, which is the root of the class object hierarchy. 5 * 6 * This module is implicitly imported. 7 * Macros: 8 * WIKI = Object 9 */ 10 11 /* 12 * Copyright (C) 2004-2007 by Digital Mars, www.digitalmars.com 13 * Written by Walter Bright 14 * 15 * This software is provided 'as-is', without any express or implied 16 * warranty. In no event will the authors be held liable for any damages 17 * arising from the use of this software. 18 * 19 * Permission is granted to anyone to use this software for any purpose, 20 * including commercial applications, and to alter it and redistribute it 21 * freely, in both source and binary form, subject to the following 22 * restrictions: 23 * 24 * o The origin of this software must not be misrepresented; you must not 25 * claim that you wrote the original software. If you use this software 26 * in a product, an acknowledgment in the product documentation would be 27 * appreciated but is not required. 28 * o Altered source versions must be plainly marked as such, and must not 29 * be misrepresented as being the original software. 30 * o This notice may not be removed or altered from any source 31 * distribution. 32 */ 33 34 /* 35 * Modified by Sean Kelly <sean@f4.ca> for use with Tango. 36 */ 37 38 module object; 39 40 private 41 { 42 import tango.stdc.string : memcmp, memcpy, memmove; 43 import tango.stdc.stdlib : calloc, realloc, free; 44 import tango.stdc.stdio : snprintf; 45 import tango.core.Exception : onOutOfMemoryError; 46 import rt.compiler.util.string; 47 import rt.compiler.util.hash; 48 import rt.compiler.dmd.rt.aaA; 49 debug(PRINTF) import tango.stdc.stdio: printf; 50 extern (C) Object _d_newclass(ClassInfo ci); 51 52 version (darwin) 53 import rt.compiler.dmd.darwin.Image; 54 } 55 56 // NOTE: For some reason, this declaration method doesn't work 57 // in this particular file (and this file only). It must 58 // be a DMD thing. 59 //alias typeof(int.sizeof) size_t; 60 //alias typeof(cast(void*)0 - cast(void*)0) ptrdiff_t; 61 62 version( X86_64 ) 63 { 64 alias ulong size_t; 65 alias long ptrdiff_t; 66 } 67 else 68 { 69 alias uint size_t; 70 alias int ptrdiff_t; 71 } 72 73 alias size_t hash_t; 74 alias int equals_t; 75 76 version (PhobosCompatibility) 77 { 78 alias char[] string; 79 alias wchar[] wstring; 80 alias dchar[] dstring; 81 } 82 83 /** 84 * All D class objects inherit from Object. 85 */ 86 class Object 87 { 88 /** 89 * Override this to capture an explicit delete or an implicit 90 * delete via a scoped-instance. Unlike a dtor(), GC references 91 * are still intact when this method is invoked 92 */ 93 void dispose() 94 { 95 } 96 97 /** 98 * Convert Object to a human readable string. 99 */ 100 char[] toString() 101 { 102 return this.classinfo.name; 103 } 104 105 /** 106 * Compute hash function for Object. 107 */ 108 hash_t toHash() 109 { 110 // BUG: this prevents a compacting GC from working, needs to be fixed 111 return cast(hash_t)cast(void*)this; 112 } 113 114 /** 115 * Compare with another Object obj. 116 * Returns: 117 * $(TABLE 118 * $(TR $(TD this < obj) $(TD < 0)) 119 * $(TR $(TD this == obj) $(TD 0)) 120 * $(TR $(TD this > obj) $(TD > 0)) 121 * ) 122 */ 123 int opCmp(Object o) 124 { 125 // BUG: this prevents a compacting GC from working, needs to be fixed 126 //return cast(int)cast(void*)this - cast(int)cast(void*)o; 127 128 throw new Exception("need opCmp for class " ~ this.classinfo.name); 129 //return ((cast(void*)this<cast(void*)o)?-1:((cast(void*)this==cast(void*)o)?0:1)); 130 } 131 132 /** 133 * Returns !=0 if this object does have the same contents as obj. 134 */ 135 equals_t opEquals(Object o) 136 { 137 return cast(equals_t)(this is o); 138 } 139 140 interface Monitor 141 { 142 void lock(); 143 void unlock(); 144 } 145 } 146 147 /** 148 * Information about an interface. 149 * When an object is accessed via an interface, an Interface* appears as the 150 * first entry in its vtbl. 151 */ 152 struct Interface 153 { 154 ClassInfo classinfo; /// .classinfo for this interface (not for containing class) 155 void*[] vtbl; 156 ptrdiff_t offset; /// offset to Interface 'this' from Object 'this' 157 } 158 159 /** 160 * Pointer map for precise heap scanning. 161 * Format: 162 * PointerMap pm = typeid(T).pointermap; 163 * pm.bits = [header] ~ scan_bits ~ pointer_bits 164 * size_t header is the number of pointer sized units in T (T.sizeof/size_t.sizeof) 165 * size_t[] scan_bits is the bitmap; each bit covers size_t bytes of T, meaning: 166 * 0: guaranteed not to be a pointer, don't scan 167 * 1: possibly a pointer, must scan 168 * size_t[] pointer_bits is a second bitmap similar to scan_bits. If the 169 * corrsponding bit in scan_bits is 0, the bit is 0; otherwise its meaning is: 170 * 0: pointer can not be moved, because it's possibly an integer 171 * 1: pointer can be moved, the corresponding word is always a pointer 172 * Note that not the bit-arrays are concatenated, but the size_t arrays. 173 * This implies all GC-aware pointers must be aligned on size_t boundaries. 174 * The compiler won't set any bits for unaligned pointer fields. 175 * The least significant bit of a size_t item is considered the first bit. 176 * PointerMap.init is a conservative scanning mask equivelant to void*[] 177 */ 178 struct PointerMap 179 { 180 size_t[] bits = [1, 1, 0]; 181 182 private const size_t BITS = size_t.sizeof * 8; 183 184 /// return size in bytes (aligned) 185 size_t size() 186 { 187 return bits[0] * size_t.sizeof; 188 } 189 190 private bool getbit(size_t offset, bool pointer_bit) 191 { 192 assert(offset < size); 193 194 if ((offset & (size_t.sizeof - 1)) != 0) 195 return false; 196 197 size_t elem = offset / size_t.sizeof; 198 size_t start = 1; //scan_bits offset 199 if (pointer_bit) 200 start += (bits[0] + BITS - 1) / BITS; //pointer_bits offset 201 return !!(bits[start + elem / BITS] & (1 << (elem % BITS))); 202 } 203 204 /// return if the (aligned) field starting at byte offset is a pointer 205 /// Warning: the GC may access the internal data structure directly instead 206 /// of using this method to make scanning faster 207 bool mustScanWordAt(size_t offset) 208 { 209 return getbit(offset, false); 210 } 211 212 /// return if the (aligned) field starting at byte offset is a moveable pointer 213 /// "moveable pointer" means that the memory block referenced by the pointer can 214 /// be moved by the GC (the pointer field will be updated with the new address) 215 bool isPointerAt(size_t offset) 216 { 217 return getbit(offset, true); 218 } 219 220 /// return true if and only if there are integer fields overlapping with pointer 221 /// fields in this type 222 bool canUpdatePointers() 223 { 224 auto len = (bits.length - 1) / 2; 225 return bits[1 .. 1 + len] == bits[1 + len .. $]; 226 } 227 228 } 229 230 /// code for manually building PointerMaps 231 /// separate struct from PointerMap because for some representations, it may be 232 /// hard to handle arbitrary pointerAt() calls to update the internal data structure 233 /// (think of pointer maps encoded as lists of runs etc.) 234 /// xxx untested 235 struct PointerMapBuilder 236 { 237 private size_t[] m_bits = null; 238 private size_t m_size = 0; 239 240 private const size_t BITS = size_t.sizeof * 8; 241 242 /// set the underlying type's size in bytes 243 void size(size_t bytes) 244 { 245 size_t nelem = bytes / size_t.sizeof; 246 m_bits.length = 1 + ((nelem + BITS - 1) / BITS) * 2; 247 m_bits[] = 0; 248 m_bits[0] = nelem; 249 m_size = bytes; 250 } 251 252 /// mark the pointer sized field at byte offset as pointer 253 /// if the offset is unaligned, it does nothing 254 void mustScanWordAt(size_t offset) 255 { 256 assert(offset < m_size); 257 258 if ((offset & (size_t.sizeof - 1)) != 0) 259 return; 260 261 size_t elem = offset / size_t.sizeof; 262 m_bits[1 + elem / BITS] |= 1 << (elem % BITS); 263 } 264 265 /// starting at the given byte offset, call pointerAt() for each pointer in pm 266 void inlineAt(size_t offset, PointerMap pm) 267 { 268 assert(offset + pm.size <= m_size); 269 270 for (size_t n = 0; n < pm.size; n += size_t.sizeof) 271 { 272 if (pm.mustScanWordAt(n)) 273 mustScanWordAt(offset + n); 274 } 275 } 276 277 /// create a PointerMap instance 278 /// accessing this PointerMapBuilder after calling this method is not allowed 279 PointerMap convertToPointerMap() { 280 //no un-moveable pointer stuff supported => imply all pointers are moveable 281 size_t len = (m_bits[0] + BITS - 1) / BITS; 282 assert(len == (m_bits.length - 1) / 2); 283 m_bits[1 + len .. $] = m_bits[1 .. 1 + len]; 284 285 auto res = PointerMap(m_bits); 286 *this = PointerMapBuilder.init; //invalidate this instance 287 return res; 288 } 289 } 290 291 //static const PointerMap cPointerMapNoScan = PointerMap([1, 0, 0]); 292 293 /** 294 * Runtime type information about a class. Can be retrieved for any class type 295 * or instance by using the .classinfo property. 296 * A pointer to this appears as the first entry in the class's vtbl[]. 297 */ 298 class ClassInfo : Object 299 { 300 byte[] init; /** class static initializer 301 * (init.length gives size in bytes of class) 302 */ 303 char[] name; /// class name 304 void*[] vtbl; /// virtual function pointer table 305 Interface[] interfaces; /// interfaces this class implements 306 ClassInfo base; /// base class 307 void* destructor; // Only use as delegate.funcptr! 308 void* classInvariant; // Only use as delegate.funcptr! 309 uint flags; 310 // 1: // is IUnknown or is derived from IUnknown 311 // 2: // has no possible pointers into GC memory 312 // 4: // has offTi[] member 313 // 8: // has constructors 314 // 32: // has typeinfo 315 void* deallocator; 316 OffsetTypeInfo[] offTi; 317 Object function() defaultConstructor; // default Constructor. Only use as delegate.funcptr! 318 static if (__VERSION__ >= 1045) { 319 TypeInfo typeinfo; 320 } 321 322 version (D_HavePointerMap) { 323 PointerMap pointermap; 324 } 325 326 /** 327 * Search all modules for ClassInfo corresponding to classname. 328 * Returns: null if not found 329 */ 330 static ClassInfo find(char[] classname) 331 { 332 foreach (m; ModuleInfo) 333 { 334 if (!m) 335 continue; 336 337 //writefln("module %s, %d", m.name, m.localClasses.length); 338 foreach (c; m.localClasses) 339 { 340 //writefln("\tclass %s", c.name); 341 if (c.name == classname) 342 return c; 343 } 344 } 345 return null; 346 } 347 348 /** 349 * Create instance of Object represented by 'this'. 350 */ 351 Object create() 352 { 353 if (flags & 8 && defaultConstructor is null) 354 return null; 355 Object o = _d_newclass(this); 356 if (flags & 8 && defaultConstructor !is null) 357 { 358 Object delegate() ctor; 359 ctor.ptr = cast(void*)o; 360 ctor.funcptr = cast(Object function())defaultConstructor; 361 return ctor(); 362 } 363 return o; 364 } 365 } 366 367 /** 368 * Array of pairs giving the offset and type information for each 369 * member in an aggregate. 370 */ 371 struct OffsetTypeInfo 372 { 373 size_t offset; /// Offset of member from start of object 374 TypeInfo ti; /// TypeInfo for this member 375 } 376 377 /** 378 * Runtime type information about a type. 379 * Can be retrieved for any type using a 380 * <a href="../expression.html#typeidexpression">TypeidExpression</a>. 381 */ 382 class TypeInfo 383 { 384 hash_t toHash() 385 { hash_t hash; 386 387 foreach (char c; this.toString()) 388 hash = hash * 9 + c; 389 return hash; 390 } 391 392 int opCmp(Object o) 393 { 394 if (this is o) 395 return 0; 396 TypeInfo ti = cast(TypeInfo)o; 397 if (ti is null) 398 return 1; 399 return stringCompare(this.toString(), ti.toString()); 400 } 401 402 override equals_t opEquals(Object o) 403 { 404 /* TypeInfo instances are singletons, but duplicates can exist 405 * across DLL's. Therefore, comparing for a name match is 406 * sufficient. 407 */ 408 if (this is o) 409 return 1; 410 TypeInfo ti = cast(TypeInfo)o; 411 return cast(equals_t)(ti && this.toString() == ti.toString()); 412 } 413 414 /// Returns a hash of the instance of a type. 415 hash_t getHash(in void* p) { return cast(hash_t)p; } 416 417 /// Compares two instances for equality. 418 equals_t equals(in void* p1, in void* p2) { return p1 == p2; } 419 420 /// Compares two instances for <, ==, or >. 421 int compare(in void* p1, in void* p2) { return 0; } // throw new Exception("non comparable",__FILE__,__LINE__); 422 /// Return alignment of type 423 size_t talign() { return tsize(); } 424 /// Returns size of the type. 425 size_t tsize() { return 0; } 426 427 /// Swaps two instances of the type. 428 void swap(void* p1, void* p2) 429 { 430 size_t n = tsize(); 431 for (size_t i = 0; i < n; i++) 432 { 433 byte t = (cast(byte *)p1)[i]; 434 (cast(byte*)p1)[i] = (cast(byte*)p2)[i]; 435 (cast(byte*)p2)[i] = t; 436 } 437 } 438 439 /// Get TypeInfo for 'next' type, as defined by what kind of type this is, 440 /// null if none. 441 TypeInfo next() { return null; } 442 443 /// Return default initializer, null if default initialize to 0 444 void[] init() { return null; } 445 446 /// Get flags for type: 1 means GC should scan for pointers 447 uint flags() { return 0; } 448 449 /// Get a pointer to PointerMap; used for GC scanning 450 PointerMap pointermap() { 451 if (flags() & 1) { 452 return PointerMap.init; 453 } else { 454 //return cPointerMapNoScan; 455 //work around for dmd bug #4397 (triggers infinite recursion) 456 static size_t[3] g_arr; 457 static PointerMap pm; 458 pm.bits = g_arr; 459 pm.bits[0] = 1; 460 pm.bits[1] = 0; 461 pm.bits[2] = 0; 462 return pm; 463 } 464 } 465 466 //return PointerMap for a single, moveable pointer 467 //also just a workaround for dmd bug #4397; should be a const variable 468 private PointerMap exactpointer() { 469 static size_t[3] g_arr; 470 static PointerMap pm; 471 pm.bits = g_arr; 472 pm.bits[0] = 1; 473 pm.bits[1] = 1; 474 pm.bits[2] = 1; 475 return pm; 476 } 477 478 /// Get type information on the contents of the type; null if not available 479 OffsetTypeInfo[] offTi() { return null; } 480 481 482 /** Return internal info on arguments fitting into 8byte. 483 * See X86-64 ABI 3.2.3 484 */ 485 version (X86_64) int argTypes(out TypeInfo arg1, out TypeInfo arg2) 486 { 487 arg1 = this; 488 return 0; 489 } 490 } 491 492 class TypeInfo_Typedef : TypeInfo 493 { 494 override char[] toString() { return name; } 495 496 override equals_t opEquals(Object o) 497 { 498 TypeInfo_Typedef c; 499 return this is o || 500 ((c = cast(TypeInfo_Typedef)o) !is null && 501 this.name == c.name && 502 this.base == c.base); 503 } 504 505 override hash_t getHash(in void* p) { return base.getHash(p); } 506 override equals_t equals(in void* p1, in void* p2) { return base.equals(p1, p2); } 507 override int compare(in void* p1, in void* p2) { return base.compare(p1, p2); } 508 override size_t tsize() { return base.tsize(); } 509 override void swap(void* p1, void* p2) { return base.swap(p1, p2); } 510 511 override TypeInfo next() { return base; } 512 override uint flags() { return base.flags(); } 513 override PointerMap pointermap() { return base.pointermap(); } 514 override void[] init() { return m_init.length ? m_init : base.init(); } 515 516 size_t talign() { return base.talign(); } 517 518 version (X86_64) int argTypes(out TypeInfo arg1, out TypeInfo arg2) 519 { 520 return base.argTypes(arg1, arg2); 521 } 522 523 TypeInfo base; 524 char[] name; 525 void[] m_init; 526 } 527 528 class TypeInfo_Enum : TypeInfo_Typedef 529 { 530 531 } 532 533 class TypeInfo_Pointer : TypeInfo 534 { 535 override char[] toString() { return m_next.toString() ~ "*"; } 536 537 override equals_t opEquals(Object o) 538 { 539 TypeInfo_Pointer c; 540 return this is o || 541 ((c = cast(TypeInfo_Pointer)o) !is null && 542 this.m_next == c.m_next); 543 } 544 545 override hash_t getHash(in void* p) 546 { 547 return cast(hash_t)*cast(void**)p; 548 } 549 550 override equals_t equals(in void* p1, in void* p2) 551 { 552 return cast(equals_t)(*cast(void**)p1 == *cast(void**)p2); 553 } 554 555 override int compare(in void* p1, in void* p2) 556 { 557 if (*cast(void**)p1 < *cast(void**)p2) 558 return -1; 559 else if (*cast(void**)p1 > *cast(void**)p2) 560 return 1; 561 else 562 return 0; 563 } 564 565 override size_t tsize() 566 { 567 return (void*).sizeof; 568 } 569 570 override void swap(void* p1, void* p2) 571 { 572 void* tmp = *cast(void**)p1; 573 *cast(void**)p1 = *cast(void**)p2; 574 *cast(void**)p2 = tmp; 575 } 576 577 override TypeInfo next() { return m_next; } 578 override uint flags() { return 1; } 579 override PointerMap pointermap() { return exactpointer(); } 580 581 TypeInfo m_next; 582 } 583 584 class TypeInfo_Array : TypeInfo 585 { 586 override char[] toString() { return value.toString() ~ "[]"; } 587 588 override equals_t opEquals(Object o) 589 { 590 TypeInfo_Array c; 591 return this is o || 592 ((c = cast(TypeInfo_Array)o) !is null && 593 this.value == c.value); 594 } 595 596 override hash_t getHash(in void* p) 597 { 598 size_t sz = value.tsize(); 599 void[] a = *cast(void[]*)p; 600 hash_t hash = a.length; 601 for (size_t i = 0; i < a.length; i++) 602 hash = rt_hash_combine(value.getHash(a.ptr + i * sz),hash); 603 return hash; 604 } 605 606 override equals_t equals(in void* p1, in void* p2) 607 { 608 void[] a1 = *cast(void[]*)p1; 609 void[] a2 = *cast(void[]*)p2; 610 if (a1.length != a2.length) 611 return false; 612 size_t sz = value.tsize(); 613 for (size_t i = 0; i < a1.length; i++) 614 { 615 if (!value.equals(a1.ptr + i * sz, a2.ptr + i * sz)) 616 return false; 617 } 618 return true; 619 } 620 621 override int compare(in void* p1, in void* p2) 622 { 623 void[] a1 = *cast(void[]*)p1; 624 void[] a2 = *cast(void[]*)p2; 625 size_t sz = value.tsize(); 626 size_t len = a1.length; 627 628 if (a2.length < len) 629 len = a2.length; 630 for (size_t u = 0; u < len; u++) 631 { 632 int result = value.compare(a1.ptr + u * sz, a2.ptr + u * sz); 633 if (result) 634 return result; 635 } 636 return cast(int)a1.length - cast(int)a2.length; 637 } 638 639 override size_t tsize() 640 { 641 return (void[]).sizeof; 642 } 643 644 override void swap(void* p1, void* p2) 645 { 646 void[] tmp = *cast(void[]*)p1; 647 *cast(void[]*)p1 = *cast(void[]*)p2; 648 *cast(void[]*)p2 = tmp; 649 } 650 651 TypeInfo value; 652 653 override TypeInfo next() 654 { 655 return value; 656 } 657 658 override uint flags() { return 1; } 659 660 size_t talign() 661 { 662 return (void[]).alignof; 663 } 664 665 version (X86_64) override int argTypes(out TypeInfo arg1, out TypeInfo arg2) 666 { //arg1 = typeid(size_t); 667 //arg2 = typeid(void*); 668 return 0; 669 } 670 671 override PointerMap pointermap() 672 { 673 //return static mask for arrays 674 // word 0: length 675 // word 1: pointer 676 //work around for dmd bug #4397 (triggers infinite recursion) 677 static size_t[3] g_arr; 678 static PointerMap pm; 679 pm.bits = g_arr; 680 pm.bits[0] = 2; 681 pm.bits[1] = 0b10; 682 pm.bits[2] = 0b10; //moveable 683 return pm; 684 } 685 } 686 687 class TypeInfo_StaticArray : TypeInfo 688 { 689 override char[] toString() 690 { 691 char [10] tmp = void; 692 return value.toString() ~ "[" ~ intToUtf8(tmp, len) ~ "]"; 693 } 694 695 override equals_t opEquals(Object o) 696 { 697 TypeInfo_StaticArray c; 698 return this is o || 699 ((c = cast(TypeInfo_StaticArray)o) !is null && 700 this.len == c.len && 701 this.value == c.value); 702 } 703 704 override hash_t getHash(in void* p) 705 { 706 size_t sz = value.tsize(); 707 hash_t hash = len; 708 for (size_t i = 0; i < len; i++) 709 hash = rt_hash_combine(value.getHash(p + i * sz),hash); 710 return hash; 711 } 712 713 override equals_t equals(in void* p1, in void* p2) 714 { 715 size_t sz = value.tsize(); 716 717 for (size_t u = 0; u < len; u++) 718 { 719 if (!value.equals(p1 + u * sz, p2 + u * sz)) 720 return false; 721 } 722 return true; 723 } 724 725 override int compare(in void* p1, in void* p2) 726 { 727 size_t sz = value.tsize(); 728 729 for (size_t u = 0; u < len; u++) 730 { 731 int result = value.compare(p1 + u * sz, p2 + u * sz); 732 if (result) 733 return result; 734 } 735 return 0; 736 } 737 738 override size_t tsize() 739 { 740 return len * value.tsize(); 741 } 742 743 override void swap(void* p1, void* p2) 744 { 745 void* tmp; 746 size_t sz = value.tsize(); 747 ubyte[16] buffer; 748 void* pbuffer; 749 750 if (sz < buffer.sizeof) 751 tmp = buffer.ptr; 752 else 753 tmp = pbuffer = (new void[sz]).ptr; 754 755 for (size_t u = 0; u < len; u += sz) 756 { size_t o = u * sz; 757 memcpy(tmp, p1 + o, sz); 758 memcpy(p1 + o, p2 + o, sz); 759 memcpy(p2 + o, tmp, sz); 760 } 761 if (pbuffer) 762 delete pbuffer; 763 } 764 765 override void[] init() { return value.init(); } 766 override TypeInfo next() { return value; } 767 override uint flags() { return value.flags(); } 768 769 override PointerMap pointermap() 770 { 771 //assert(0); 772 //this is kind of a hack to make arrays of static arrays work 773 //e.g. T[2][] (typeid(T[2]) would be this instance) 774 //because the GC repeats GC bitmasks shorter than the allocation size, 775 // this should work well 776 //it's a hack because pointermap() is supposed to return a map that 777 // covers the whole type (i.e. doesn't rely on repeat) 778 //this also might prevent subtle bugs, when a static array is resized 779 // as dynamic array, and the bitmask is reused (can that happen at all?) 780 return value.pointermap(); 781 } 782 783 TypeInfo value; 784 size_t len; 785 786 size_t talign() 787 { 788 return value.talign(); 789 } 790 791 version (X86_64) override int argTypes(out TypeInfo arg1, out TypeInfo arg2) 792 { 793 arg1 = typeid(void*); 794 return 0; 795 } 796 797 } 798 799 class TypeInfo_AssociativeArray : TypeInfo 800 { 801 override char[] toString() 802 { 803 return next.toString() ~ "[" ~ key.toString() ~ "]"; 804 } 805 806 override equals_t opEquals(Object o) 807 { 808 TypeInfo_AssociativeArray c; 809 return this is o || 810 ((c = cast(TypeInfo_AssociativeArray)o) !is null && 811 this.key == c.key && 812 this.next == c.next); 813 } 814 815 override hash_t getHash(in void* p) 816 { 817 size_t sz = value.tsize(); 818 hash_t hash = sz; 819 AA aa=*cast(AA*)p; 820 size_t keysize=key.tsize(); 821 int res=_aaApply2(aa, keysize, cast(dg2_t) delegate int(void *k, void *v){ 822 hash+=rt_hash_combine(key.getHash(k),value.getHash(v)); 823 return 0; 824 }); 825 return hash; 826 } 827 828 override size_t tsize() 829 { 830 return (char[int]).sizeof; 831 } 832 override equals_t equals(in void* p1, in void* p2) 833 { 834 AA a=*cast(AA*)p1; 835 AA b=*cast(AA*)p2; 836 if (cast(void*)a.a==cast(void*)b.a) return true; 837 size_t l1=_aaLen(a); 838 size_t l2=_aaLen(b); 839 if (l1!=l2) return false; 840 size_t keysize=key.tsize(); 841 equals_t same=true; 842 int res=_aaApply2(a, keysize, cast(dg2_t) delegate int(void *k, void *v){ 843 void* v2=_aaGetRvalue(b, key, value.tsize(), k); 844 if (v2 is null || !value.equals(v,v2)) { 845 same=false; 846 return 1; 847 } 848 ++l1; 849 return 0; 850 }); 851 return same; 852 } 853 854 override int compare(in void* p1, in void* p2) 855 { 856 throw new Exception("non comparable",__FILE__,__LINE__); 857 } 858 859 override TypeInfo next() { return value; } 860 override uint flags() { return 1; } 861 override PointerMap pointermap() { return exactpointer(); } 862 863 TypeInfo value; 864 TypeInfo key; 865 866 size_t talign() 867 { 868 return (char[int]).alignof; 869 } 870 871 version (X86_64) override int argTypes(out TypeInfo arg1, out TypeInfo arg2) 872 { 873 arg1 = typeid(void*); 874 return 0; 875 } 876 } 877 878 class TypeInfo_Function : TypeInfo 879 { 880 override char[] toString() 881 { 882 return next.toString() ~ "()"; 883 } 884 885 override equals_t opEquals(Object o) 886 { 887 TypeInfo_Function c; 888 return this is o || 889 ((c = cast(TypeInfo_Function)o) !is null && 890 this.next == c.next); 891 } 892 893 // BUG: need to add the rest of the functions 894 895 override size_t tsize() 896 { 897 return 0; // no size for functions 898 } 899 900 TypeInfo next; 901 } 902 903 class TypeInfo_Delegate : TypeInfo 904 { 905 override char[] toString() 906 { 907 return (next.toString() ~ " delegate()"); 908 } 909 910 override equals_t opEquals(Object o) 911 { 912 TypeInfo_Delegate c; 913 return this is o || 914 ((c = cast(TypeInfo_Delegate)o) !is null && 915 this.next == c.next); 916 } 917 918 override hash_t getHash(in void* p) 919 { 920 alias int delegate() dg; 921 return rt_hash_str(p,dg.sizeof,0); 922 } 923 924 override equals_t equals(in void* p1, in void* p2) 925 { 926 alias int delegate() dg; 927 return memcmp(p1,p2,dg.sizeof); 928 } 929 930 override size_t tsize() 931 { 932 alias int delegate() dg; 933 return dg.sizeof; 934 } 935 936 override int compare(in void* p1, in void* p2) 937 { 938 alias int delegate() dg; 939 return memcmp(p1,p2,dg.sizeof); 940 } 941 942 override uint flags() { return 1; } 943 944 override PointerMap pointermap() 945 { 946 //return static mask for delegates 947 // word 0: context pointer 948 // word 1: function pointer (not scanned) 949 //work around for dmd bug #4397 (triggers infinite recursion) 950 static size_t[3] g_arr; 951 static PointerMap pm; 952 pm.bits = g_arr; 953 pm.bits[0] = 2; 954 pm.bits[1] = 0b01; 955 pm.bits[2] = 0b01; //moveable 956 return pm; 957 } 958 959 TypeInfo next; 960 961 size_t talign() 962 { 963 alias int delegate() dg; 964 return dg.alignof; 965 } 966 967 version (X86_64) override int argTypes(out TypeInfo arg1, out TypeInfo arg2) 968 { //arg1 = typeid(void*); 969 //arg2 = typeid(void*); 970 return 0; 971 } 972 973 } 974 975 class TypeInfo_Class : TypeInfo 976 { 977 override char[] toString() { return info.name; } 978 979 override equals_t opEquals(Object o) 980 { 981 TypeInfo_Class c; 982 return this is o || 983 ((c = cast(TypeInfo_Class)o) !is null && 984 this.info.name == c.classinfo.name); 985 } 986 987 override hash_t getHash(in void* p) 988 { 989 Object o = *cast(Object*)p; 990 return o ? o.toHash() : 0; 991 } 992 993 override equals_t equals(in void* p1, in void* p2) 994 { 995 Object o1 = *cast(Object*)p1; 996 Object o2 = *cast(Object*)p2; 997 998 return (o1 is o2) || (o1 && o1.opEquals(o2)); 999 } 1000 1001 override int compare(in void* p1, in void* p2) 1002 { 1003 Object o1 = *cast(Object*)p1; 1004 Object o2 = *cast(Object*)p2; 1005 int c = 0; 1006 1007 // Regard null references as always being "less than" 1008 if (o1 !is o2) 1009 { 1010 if (o1) 1011 { 1012 if (!o2) 1013 c = 1; 1014 else 1015 c = o1.opCmp(o2); 1016 } 1017 else 1018 c = -1; 1019 } 1020 return c; 1021 } 1022 1023 override size_t tsize() 1024 { 1025 return Object.sizeof; 1026 } 1027 1028 override uint flags() { return 1; } 1029 override PointerMap pointermap() { return exactpointer(); } 1030 1031 override OffsetTypeInfo[] offTi() 1032 { 1033 return (info.flags & 4) ? info.offTi : null; 1034 } 1035 1036 ClassInfo info; 1037 } 1038 1039 class TypeInfo_Interface : TypeInfo 1040 { 1041 override char[] toString() { return info.name; } 1042 1043 override equals_t opEquals(Object o) 1044 { 1045 TypeInfo_Interface c; 1046 return this is o || 1047 ((c = cast(TypeInfo_Interface)o) !is null && 1048 this.info.name == c.classinfo.name); 1049 } 1050 1051 override hash_t getHash(in void* p) 1052 { 1053 Interface* pi = **cast(Interface ***)*cast(void**)p; 1054 Object o = cast(Object)(*cast(void**)p - pi.offset); 1055 assert(o); 1056 return o.toHash(); 1057 } 1058 1059 override equals_t equals(in void* p1, in void* p2) 1060 { 1061 Interface* pi = **cast(Interface ***)*cast(void**)p1; 1062 Object o1 = cast(Object)(*cast(void**)p1 - pi.offset); 1063 pi = **cast(Interface ***)*cast(void**)p2; 1064 Object o2 = cast(Object)(*cast(void**)p2 - pi.offset); 1065 1066 return o1 == o2 || (o1 && o1.opCmp(o2) == 0); 1067 } 1068 1069 override int compare(in void* p1, in void* p2) 1070 { 1071 Interface* pi = **cast(Interface ***)*cast(void**)p1; 1072 Object o1 = cast(Object)(*cast(void**)p1 - pi.offset); 1073 pi = **cast(Interface ***)*cast(void**)p2; 1074 Object o2 = cast(Object)(*cast(void**)p2 - pi.offset); 1075 int c = 0; 1076 1077 // Regard null references as always being "less than" 1078 if (o1 != o2) 1079 { 1080 if (o1) 1081 { 1082 if (!o2) 1083 c = 1; 1084 else 1085 c = o1.opCmp(o2); 1086 } 1087 else 1088 c = -1; 1089 } 1090 return c; 1091 } 1092 1093 override size_t tsize() 1094 { 1095 return Object.sizeof; 1096 } 1097 1098 override uint flags() { return 1; } 1099 override PointerMap pointermap() { return exactpointer(); } 1100 1101 ClassInfo info; 1102 } 1103 1104 class TypeInfo_Struct : TypeInfo 1105 { 1106 override char[] toString() { return name; } 1107 1108 override equals_t opEquals(Object o) 1109 { 1110 TypeInfo_Struct s; 1111 return this is o || 1112 ((s = cast(TypeInfo_Struct)o) !is null && 1113 this.name == s.name && 1114 this.init.length == s.init.length); 1115 } 1116 1117 override hash_t getHash(in void* p) 1118 { 1119 assert(p); 1120 if (xtoHash !is null) 1121 { 1122 debug(PRINTF) printf("getHash() using xtoHash\n"); 1123 hash_t delegate() toHash; 1124 toHash.ptr = p; 1125 toHash.funcptr = cast(hash_t function())xtoHash; 1126 return toHash(); 1127 } 1128 else 1129 { 1130 debug(PRINTF) printf("getHash() using default hash\n"); 1131 // BUG: relies on the GC not moving objects 1132 return rt_hash_str(p,init.length,0); 1133 } 1134 } 1135 1136 override equals_t equals(in void* p1, in void* p2) 1137 { 1138 if (p1 == p2) 1139 return true; 1140 else if (!p1 || !p2) 1141 return false; 1142 else if (xopEquals !is null) { 1143 int delegate(void*) opEquals; 1144 opEquals.ptr = p1; 1145 opEquals.funcptr = xopEquals; 1146 return opEquals(p2); 1147 } else 1148 // BUG: relies on the GC not moving objects 1149 return memcmp(p1, p2, init.length) == 0; 1150 } 1151 1152 override int compare(in void* p1, in void* p2) 1153 { 1154 // Regard null references as always being "less than" 1155 if (p1 != p2) 1156 { 1157 if (p1) 1158 { 1159 if (!p2) 1160 return true; 1161 else if (xopCmp !is null) { 1162 int delegate(void*) opCmp; 1163 opCmp.ptr = p1; 1164 opCmp.funcptr = xopCmp; 1165 return opCmp(p2); 1166 } else 1167 // BUG: relies on the GC not moving objects 1168 return memcmp(p1, p2, init.length); 1169 } 1170 else 1171 return -1; 1172 } 1173 return 0; 1174 } 1175 1176 override size_t tsize() 1177 { 1178 return init.length; 1179 } 1180 1181 override void[] init() { return m_init; } 1182 1183 override uint flags() { return m_flags; } 1184 1185 size_t talign() { return m_align; } 1186 1187 1188 char[] name; 1189 void[] m_init; // initializer; init.ptr == null if 0 initialize 1190 1191 // These are ONLY for use as a delegate.funcptr! 1192 hash_t function() xtoHash; 1193 int function(void*) xopEquals; 1194 int function(void*) xopCmp; 1195 char[] function() xtoString; 1196 1197 uint m_flags; 1198 uint m_align; 1199 1200 version (D_HavePointerMap) { 1201 PointerMap m_pointermap; 1202 1203 override PointerMap pointermap() { return m_pointermap; } 1204 } 1205 1206 version (X86_64) 1207 { 1208 int argTypes(out TypeInfo arg1, out TypeInfo arg2) 1209 { 1210 arg1 = m_arg1; 1211 arg2 = m_arg2; 1212 return 0; 1213 } 1214 TypeInfo m_arg1; 1215 TypeInfo m_arg2; 1216 } 1217 } 1218 1219 class TypeInfo_Tuple : TypeInfo 1220 { 1221 TypeInfo[] elements; 1222 1223 override char[] toString() 1224 { 1225 char[] s; 1226 s = "("; 1227 foreach (i, element; elements) 1228 { 1229 if (i) 1230 s ~= ','; 1231 s ~= element.toString(); 1232 } 1233 s ~= ")"; 1234 return s; 1235 } 1236 1237 override equals_t opEquals(Object o) 1238 { 1239 if (this is o) 1240 return true; 1241 1242 auto t = cast(TypeInfo_Tuple)o; 1243 if (t && elements.length == t.elements.length) 1244 { 1245 for (size_t i = 0; i < elements.length; i++) 1246 { 1247 if (elements[i] != t.elements[i]) 1248 return false; 1249 } 1250 return true; 1251 } 1252 return false; 1253 } 1254 1255 override hash_t getHash(in void* p) 1256 { 1257 assert(0); 1258 } 1259 1260 override equals_t equals(in void* p1, in void* p2) 1261 { 1262 assert(0); 1263 } 1264 1265 override int compare(in void* p1, in void* p2) 1266 { 1267 assert(0); 1268 } 1269 1270 override size_t tsize() 1271 { 1272 assert(0); 1273 } 1274 1275 override void swap(void* p1, void* p2) 1276 { 1277 assert(0); 1278 } 1279 1280 override PointerMap pointermap() 1281 { 1282 assert(0); 1283 } 1284 1285 version (X86_64) int argTypes(out TypeInfo arg1, out TypeInfo arg2) 1286 { 1287 assert(0); 1288 } 1289 } 1290 1291 1292 //////////////////////////////////////////////////////////////////////////////// 1293 // Exception 1294 //////////////////////////////////////////////////////////////////////////////// 1295 class Exception : Object 1296 { 1297 struct FrameInfo{ 1298 long line; 1299 size_t iframe; 1300 ptrdiff_t offsetSymb; 1301 size_t baseSymb; 1302 ptrdiff_t offsetImg; 1303 size_t baseImg; 1304 size_t address; 1305 char[] file; 1306 char[] func; 1307 char[] extra; 1308 bool exactAddress; 1309 bool internalFunction; 1310 alias void function(FrameInfo*,void delegate(char[])) FramePrintHandler; 1311 static FramePrintHandler defaultFramePrintingFunction; 1312 void writeOut(void delegate(char[])sink){ 1313 1314 if (defaultFramePrintingFunction){ 1315 defaultFramePrintingFunction(this,sink); 1316 } else { 1317 // Imitate GDB backtrace format, something like: 1318 // printf("#%-4td %p in %s (%s) at %s:%lld\n", 1319 // iframe, address, func, extra, file, line); 1320 const M = 26; 1321 char[M] buf; 1322 auto len = snprintf(buf.ptr, M, "#%-4td ", this.iframe); 1323 sink(buf[0..len]); 1324 1325 len = snprintf(buf.ptr, M, "%p", this.address); 1326 sink(buf[0..len]); 1327 1328 sink(" in "); 1329 sink(this.func.length ? this.func : "???"); 1330 sink(" ("); 1331 sink(this.extra); 1332 sink(") at "); 1333 1334 sink(this.file); 1335 sink(":"); 1336 1337 len = snprintf(buf.ptr, M, "%zu", cast(size_t) this.line); 1338 sink(buf[0..len]); 1339 } 1340 } 1341 1342 void clear(){ 1343 line=0; 1344 iframe=-1; 1345 offsetImg=0; 1346 baseImg=0; 1347 offsetSymb=0; 1348 baseSymb=0; 1349 address=0; 1350 exactAddress=true; 1351 internalFunction=false; 1352 file=null; 1353 func=null; 1354 extra=null; 1355 } 1356 } 1357 interface TraceInfo 1358 { 1359 int opApply( int delegate( ref FrameInfo fInfo ) ); 1360 void writeOut(void delegate(char[])sink); 1361 } 1362 1363 char[] msg; 1364 char[] file; 1365 size_t line; // long would be better 1366 TraceInfo info; 1367 Exception next; 1368 1369 this( char[] msg, char[] file, long line, Exception next, TraceInfo info ) 1370 { 1371 // main constructor, breakpoint this if you want... 1372 this.msg = msg; 1373 this.next = next; 1374 this.file = file; 1375 this.line = cast(size_t)line; 1376 this.info = info; 1377 } 1378 1379 this( char[] msg, Exception next=null ) 1380 { 1381 this(msg,"",0,next,rt_createTraceContext(null)); 1382 } 1383 1384 this( char[] msg, char[] file, long line, Exception next=null ) 1385 { 1386 this(msg,file,line,next,rt_createTraceContext(null)); 1387 } 1388 1389 override char[] toString() 1390 { 1391 return msg; 1392 } 1393 void writeOutMsg(void delegate(char[])sink){ 1394 sink(toString()); 1395 } 1396 void writeOut(void delegate(char[])sink){ 1397 if (file.length>0 || line!=0) 1398 { 1399 char[25]buf; 1400 sink(this.classinfo.name); 1401 sink("@"); 1402 sink(file); 1403 sink("("); 1404 sink(ulongToUtf8(buf, line)); 1405 sink("): "); 1406 writeOutMsg(sink); 1407 sink("\n"); 1408 } 1409 else 1410 { 1411 sink(this.classinfo.name); 1412 sink(": "); 1413 writeOutMsg(sink); 1414 sink("\n"); 1415 } 1416 if (info) 1417 { 1418 sink("----------------\n"); 1419 info.writeOut(sink); 1420 } 1421 if (next){ 1422 sink("\n++++++++++++++++\n"); 1423 next.writeOut(sink); 1424 } 1425 } 1426 } 1427 1428 1429 alias Exception.TraceInfo function( void* ptr = null ) TraceHandler; 1430 private TraceHandler traceHandler = null; 1431 1432 1433 /** 1434 * Overrides the default trace hander with a user-supplied version. 1435 * 1436 * Params: 1437 * h = The new trace handler. Set to null to use the default handler. 1438 */ 1439 extern (C) void rt_setTraceHandler( TraceHandler h ) 1440 { 1441 traceHandler = h; 1442 } 1443 1444 /** 1445 * This function will be called when an Exception is constructed. The 1446 * user-supplied trace handler will be called if one has been supplied, 1447 * otherwise no trace will be generated. 1448 * 1449 * Params: 1450 * ptr = A pointer to the location from which to generate the trace, or null 1451 * if the trace should be generated from within the trace handler 1452 * itself. 1453 * 1454 * Returns: 1455 * An object describing the current calling context or null if no handler is 1456 * supplied. 1457 */ 1458 extern(C) Exception.TraceInfo rt_createTraceContext( void* ptr ){ 1459 if( traceHandler is null ) 1460 return null; 1461 return traceHandler( ptr ); 1462 } 1463 1464 //////////////////////////////////////////////////////////////////////////////// 1465 // ModuleInfo 1466 //////////////////////////////////////////////////////////////////////////////// 1467 1468 1469 enum 1470 { 1471 MIctorstart = 1, // we've started constructing it 1472 MIctordone = 2, // finished construction 1473 MIstandalone = 4, // module ctor does not depend on other module 1474 // ctors being done first 1475 MIhasictor = 8, // has ictor member 1476 } 1477 1478 1479 class ModuleInfo 1480 { 1481 char[] name; 1482 ModuleInfo[] importedModules; 1483 ClassInfo[] localClasses; 1484 uint flags; 1485 1486 void function() ctor; // module static constructor (order dependent) 1487 void function() dtor; // module static destructor 1488 void function() unitTest; // module unit tests 1489 1490 void* xgetMembers; // module getMembers() function 1491 1492 void function() ictor; // module static constructor (order independent) 1493 1494 static int opApply( int delegate( ref ModuleInfo ) dg ) 1495 { 1496 int ret = 0; 1497 1498 foreach( m; _moduleinfo_array ) 1499 { 1500 ret = dg( m ); 1501 if( ret ) 1502 break; 1503 } 1504 return ret; 1505 } 1506 } 1507 1508 1509 // Win32: this gets initialized by minit.asm 1510 // linux: this gets initialized in _moduleCtor() 1511 extern (C) ModuleInfo[] _moduleinfo_array; 1512 1513 1514 version (linux) 1515 { 1516 // This linked list is created by a compiler generated function inserted 1517 // into the .ctor list by the compiler. 1518 struct ModuleReference 1519 { 1520 ModuleReference* next; 1521 ModuleInfo mod; 1522 } 1523 1524 extern (C) ModuleReference* _Dmodule_ref; // start of linked list 1525 } 1526 1527 version( freebsd ) 1528 { 1529 // This linked list is created by a compiler generated function inserted 1530 // into the .ctor list by the compiler. 1531 struct ModuleReference 1532 { 1533 ModuleReference* next; 1534 ModuleInfo mod; 1535 } 1536 extern (C) ModuleReference *_Dmodule_ref; // start of linked list 1537 } 1538 1539 ModuleInfo[] _moduleinfo_dtors; 1540 uint _moduleinfo_dtors_i; 1541 1542 // Register termination function pointers 1543 extern (C) int _fatexit(void *); 1544 1545 /** 1546 * Initialize the modules. 1547 */ 1548 1549 extern (C) void _moduleCtor() 1550 { 1551 debug(PRINTF) printf("_moduleCtor()\n"); 1552 version (linux) 1553 { 1554 int len = 0; 1555 ModuleReference *mr; 1556 1557 for (mr = _Dmodule_ref; mr; mr = mr.next) 1558 len++; 1559 _moduleinfo_array = new ModuleInfo[len]; 1560 len = 0; 1561 for (mr = _Dmodule_ref; mr; mr = mr.next) 1562 { _moduleinfo_array[len] = mr.mod; 1563 len++; 1564 } 1565 1566 debug(PRINTF) foreach (m; _moduleinfo_array) 1567 { 1568 //printf("\t%p\n", m); 1569 printf("\t%.*s\n", m.name.length,m.name.ptr); 1570 } 1571 1572 } 1573 1574 version( freebsd ) 1575 { 1576 int len = 0; 1577 ModuleReference *mr; 1578 1579 for (mr = _Dmodule_ref; mr; mr = mr.next) 1580 len++; 1581 _moduleinfo_array = new ModuleInfo[len]; 1582 len = 0; 1583 for (mr = _Dmodule_ref; mr; mr = mr.next) 1584 { 1585 _moduleinfo_array[len] = mr.mod; 1586 len++; 1587 } 1588 } 1589 1590 version( OSX ) 1591 { 1592 /* The ModuleInfo references are stored in the special segment 1593 * __minfodata, which is bracketed by the segments __minfo_beg 1594 * and __minfo_end. The variables _minfo_beg and _minfo_end 1595 * are of zero size and are in the two bracketing segments, 1596 * respectively. 1597 * 1598 * The __minfo_beg and __minfo_end sections are not put into 1599 * dynamic libraries therefore we cannot use them or the 1600 * _minfo_beg and _minfo_end variables. Instead we loop through 1601 * all the loaded images (executables and dynamic libraries) and 1602 * collect all the ModuleInfo references. 1603 */ 1604 _moduleinfo_array = getSectionData!(ModuleInfo, "__DATA", "__minfodata"); 1605 debug(PRINTF) printf("moduleinfo: ptr = %p, length = %d\n", _moduleinfo_array.ptr, _moduleinfo_array.length); 1606 1607 debug(PRINTF) foreach (m; _moduleinfo_array) 1608 { 1609 //printf("\t%p\n", m); 1610 printf("\t%.*s\n", m.name.length,m.name.ptr); 1611 } 1612 } 1613 1614 version (Win32) 1615 { 1616 // Ensure module destructors also get called on program termination 1617 //_fatexit(&_STD_moduleDtor); 1618 } 1619 1620 _moduleinfo_dtors = new ModuleInfo[_moduleinfo_array.length]; 1621 debug(PRINTF) printf("_moduleinfo_dtors = x%x\n", cast(void*)_moduleinfo_dtors); 1622 _moduleIndependentCtors(); 1623 _moduleCtor2(null,_moduleinfo_array, 0); 1624 } 1625 1626 extern (C) void _moduleIndependentCtors() 1627 { 1628 debug(PRINTF) printf("_moduleIndependentCtors()\n"); 1629 foreach (m; _moduleinfo_array) 1630 { 1631 if (m && m.flags & MIhasictor && m.ictor) 1632 { 1633 (*m.ictor)(); 1634 } 1635 } 1636 } 1637 1638 void _moduleCtor2(ModuleInfo from, ModuleInfo[] mi, int skip) 1639 { 1640 debug(PRINTF) printf("_moduleCtor2(): %d modules\n", mi.length); 1641 for (uint i = 0; i < mi.length; i++) 1642 { 1643 ModuleInfo m = mi[i]; 1644 1645 debug(PRINTF) printf("\tmodule[%d] = '%p'\n", i, m); 1646 if (!m) 1647 continue; 1648 debug(PRINTF) printf("\tmodule[%d].name = '%s'\n", i, m.name); 1649 if (m.flags & MIctordone) 1650 continue; 1651 debug(PRINTF) printf("\tmodule[%d] = '%.*s', m = x%x\n", i, m.name, m); 1652 1653 if (m.ctor || m.dtor) 1654 { 1655 if (m.flags & MIctorstart) 1656 { if (skip || m.flags & MIstandalone) 1657 continue; 1658 throw new Exception( "Cyclic dependency in module " ~ (from is null ? "*null*" : from.name) ~ " for import " ~ m.name); 1659 } 1660 1661 m.flags |= MIctorstart; 1662 _moduleCtor2(m,m.importedModules, 0); 1663 if (m.ctor) 1664 (*m.ctor)(); 1665 m.flags &= ~MIctorstart; 1666 m.flags |= MIctordone; 1667 1668 // Now that construction is done, register the destructor 1669 //printf("\tadding module dtor x%x\n", m); 1670 assert(_moduleinfo_dtors_i < _moduleinfo_dtors.length); 1671 _moduleinfo_dtors[_moduleinfo_dtors_i++] = m; 1672 } 1673 else 1674 { 1675 m.flags |= MIctordone; 1676 _moduleCtor2(m,m.importedModules, 1); 1677 } 1678 } 1679 } 1680 1681 /** 1682 * Destruct the modules. 1683 */ 1684 1685 // Starting the name with "_STD" means under linux a pointer to the 1686 // function gets put in the .dtors segment. 1687 1688 extern (C) void _moduleDtor() 1689 { 1690 debug(PRINTF) printf("_moduleDtor(): %d modules\n", _moduleinfo_dtors_i); 1691 1692 for (uint i = _moduleinfo_dtors_i; i-- != 0;) 1693 { 1694 ModuleInfo m = _moduleinfo_dtors[i]; 1695 1696 debug(PRINTF) printf("\tmodule[%d] = '%.*s', x%x\n", i, m.name, m); 1697 if (m.dtor) 1698 { 1699 (*m.dtor)(); 1700 } 1701 } 1702 debug(PRINTF) printf("_moduleDtor() done\n"); 1703 } 1704 1705 //////////////////////////////////////////////////////////////////////////////// 1706 // Monitor 1707 //////////////////////////////////////////////////////////////////////////////// 1708 1709 alias Object.Monitor IMonitor; 1710 alias void delegate(Object) DEvent; 1711 1712 // NOTE: The dtor callback feature is only supported for monitors that are not 1713 // supplied by the user. The assumption is that any object with a user- 1714 // supplied monitor may have special storage or lifetime requirements and 1715 // that as a result, storing references to local objects within Monitor 1716 // may not be safe or desirable. Thus, devt is only valid if impl is 1717 // null. 1718 struct Monitor 1719 { 1720 IMonitor impl; 1721 /* internal */ 1722 DEvent[] devt; 1723 /* stuff */ 1724 } 1725 1726 Monitor* getMonitor(Object h) 1727 { 1728 return cast(Monitor*) (cast(void**) h)[1]; 1729 } 1730 1731 void setMonitor(Object h, Monitor* m) 1732 { 1733 (cast(void**) h)[1] = m; 1734 } 1735 1736 extern (C) void _d_monitor_create(Object); 1737 extern (C) void _d_monitor_destroy(Object); 1738 extern (C) void _d_monitor_lock(Object); 1739 extern (C) int _d_monitor_unlock(Object); 1740 1741 extern (C) void _d_monitordelete(Object h, bool det) 1742 { 1743 Monitor* m = getMonitor(h); 1744 1745 if (m !is null) 1746 { 1747 IMonitor i = m.impl; 1748 if (i is null) 1749 { 1750 _d_monitor_devt(m, h); 1751 _d_monitor_destroy(h); 1752 setMonitor(h, null); 1753 return; 1754 } 1755 if (det && (cast(void*) i) !is (cast(void*) h)) 1756 delete i; 1757 setMonitor(h, null); 1758 } 1759 } 1760 1761 extern (C) void _d_monitorenter(Object h) 1762 { 1763 Monitor* m = getMonitor(h); 1764 1765 if (m is null) 1766 { 1767 _d_monitor_create(h); 1768 m = getMonitor(h); 1769 } 1770 1771 IMonitor i = m.impl; 1772 1773 if (i is null) 1774 { 1775 _d_monitor_lock(h); 1776 return; 1777 } 1778 i.lock(); 1779 } 1780 1781 extern (C) void _d_monitorexit(Object h) 1782 { 1783 Monitor* m = getMonitor(h); 1784 IMonitor i = m.impl; 1785 1786 if (i is null) 1787 { 1788 _d_monitor_unlock(h); 1789 return; 1790 } 1791 i.unlock(); 1792 } 1793 1794 extern (C) void _d_monitor_devt(Monitor* m, Object h) 1795 { 1796 if (m.devt.length) 1797 { 1798 DEvent[] devt; 1799 1800 synchronized (h) 1801 { 1802 devt = m.devt; 1803 m.devt = null; 1804 } 1805 foreach (v; devt) 1806 { 1807 if (v) 1808 v(h); 1809 } 1810 free(devt.ptr); 1811 } 1812 } 1813 1814 extern (C) void rt_attachDisposeEvent(Object h, DEvent e) 1815 { 1816 synchronized (h) 1817 { 1818 Monitor* m = getMonitor(h); 1819 assert(m.impl is null); 1820 1821 foreach (ref v; m.devt) 1822 { 1823 if (v is null || v == e) 1824 { 1825 v = e; 1826 return; 1827 } 1828 } 1829 1830 auto len = m.devt.length + 4; // grow by 4 elements 1831 auto pos = m.devt.length; // insert position 1832 auto p = realloc(m.devt.ptr, DEvent.sizeof * len); 1833 if (!p) 1834 onOutOfMemoryError(); 1835 m.devt = (cast(DEvent*)p)[0 .. len]; 1836 m.devt[pos+1 .. len] = null; 1837 m.devt[pos] = e; 1838 } 1839 } 1840 1841 extern (C) bool rt_detachDisposeEvent(Object h, DEvent e) 1842 { 1843 synchronized (h) 1844 { 1845 return rt_detachDisposeEventNoLock(h, e); 1846 } 1847 } 1848 1849 extern (C) bool rt_detachDisposeEventNoLock(Object h, DEvent e) 1850 { 1851 Monitor* m = getMonitor(h); 1852 assert(m.impl is null); 1853 1854 foreach (p, v; m.devt) 1855 { 1856 if (v == e) 1857 { 1858 memmove(&m.devt[p], 1859 &m.devt[p+1], 1860 (m.devt.length - p - 1) * DEvent.sizeof); 1861 m.devt[$ - 1] = null; 1862 return true; 1863 } 1864 } 1865 return false; 1866 }