1 module bc.core.system.linux.dwarf; 2 3 version (D_BetterC) {} 4 else version (linux): 5 6 import bc.core.system.linux.elf : Image; 7 import core.exception : onOutOfMemoryErrorNoGC; 8 import core.internal.traits : dtorIsNothrow; 9 import core.stdc.stdio : snprintf; 10 import core.stdc.string : strlen; 11 12 // Selective copy from normally unavailable: https://github.com/dlang/druntime/blob/master/src/rt/backtrace/dwarf.d 13 // Also combined (and noted) with some only here used module parts 14 15 size_t getFirstFrame(const(void*)[] callstack, const char** frameList) nothrow @nogc 16 { 17 import core.internal.execinfo : getMangledSymbolName; 18 19 version (LDC) enum BaseExceptionFunctionName = "_d_throw_exception"; 20 else enum BaseExceptionFunctionName = "_d_throwdwarf"; 21 22 foreach (i; 0..callstack.length) 23 { 24 auto proc = getMangledSymbolName(frameList[i][0 .. strlen(frameList[i])]); 25 if (proc == BaseExceptionFunctionName) return i+1; 26 } 27 return 0; 28 } 29 30 /// Our customized @nogc variant of https://github.com/dlang/druntime/blob/master/src/rt/backtrace/dwarf.d#L94 31 size_t dumpCallstack(S)(ref S sink, ref Image image, const(void*)[] callstack, const char** frameList, 32 const(ubyte)[] debugLineSectionData) nothrow @nogc 33 { 34 // find address -> file, line mapping using dwarf debug_line 35 Array!Location locations; 36 if (debugLineSectionData) 37 { 38 locations.length = callstack.length; 39 foreach (size_t i; 0 .. callstack.length) 40 locations[i].address = cast(size_t) callstack[i]; 41 42 resolveAddresses(debugLineSectionData, locations[], image.baseAddress); 43 } 44 45 size_t ret = 0; 46 foreach (size_t i; 0 .. callstack.length) 47 { 48 char[1536] buffer = void; 49 size_t bufferLength = 0; 50 51 void appendToBuffer(Args...)(const(char)* format, Args args) 52 { 53 const count = snprintf(buffer.ptr + bufferLength, buffer.length - bufferLength, format, args); 54 assert(count >= 0); 55 bufferLength += count; 56 if (bufferLength >= buffer.length) 57 bufferLength = buffer.length - 1; 58 } 59 60 if (i) { sink.put('\n'); ret++; } 61 62 if (locations.length > 0 && locations[i].line != -1) 63 { 64 bool includeSlash = locations[i].directory.length > 0 && locations[i].directory[$ - 1] != '/'; 65 if (locations[i].line) 66 { 67 string printFormat = includeSlash ? "%.*s/%.*s:%d " : "%.*s%.*s:%d "; 68 appendToBuffer( 69 printFormat.ptr, 70 cast(int) locations[i].directory.length, locations[i].directory.ptr, 71 cast(int) locations[i].file.length, locations[i].file.ptr, 72 locations[i].line, 73 ); 74 } 75 else 76 { 77 string printFormat = includeSlash ? "%.*s/%.*s " : "%.*s%.*s "; 78 appendToBuffer( 79 printFormat.ptr, 80 cast(int) locations[i].directory.length, locations[i].directory.ptr, 81 cast(int) locations[i].file.length, locations[i].file.ptr, 82 ); 83 } 84 } 85 else 86 { 87 buffer[0 .. 5] = "??:? "; 88 bufferLength = 5; 89 } 90 91 char[1024] symbolBuffer = void; 92 auto symbol = getDemangledSymbol(frameList[i][0 .. strlen(frameList[i])], symbolBuffer); 93 if (symbol.length > 0) 94 appendToBuffer("%.*s ", cast(int) symbol.length, symbol.ptr); 95 96 const addressLength = 20; 97 const maxBufferLength = buffer.length - addressLength; 98 if (bufferLength > maxBufferLength) 99 { 100 buffer[maxBufferLength-4 .. maxBufferLength] = "... "; 101 bufferLength = maxBufferLength; 102 } 103 appendToBuffer("[0x%zx]", callstack[i]); 104 105 auto output = buffer[0 .. bufferLength]; 106 sink.put(output); 107 ret += bufferLength; 108 if (symbol == "_Dmain") break; 109 } 110 111 return ret; 112 } 113 114 // Copy: https://github.com/dlang/druntime/blob/master/src/rt/backtrace/dwarf.d#L172 115 // the lifetime of the Location data is bound to the lifetime of debugLineSectionData 116 void resolveAddresses(const(ubyte)[] debugLineSectionData, Location[] locations, size_t baseAddress) @nogc nothrow 117 { 118 debug(DwarfDebugMachine) import core.stdc.stdio; 119 120 size_t numberOfLocationsFound = 0; 121 122 const(ubyte)[] dbg = debugLineSectionData; 123 while (dbg.length > 0) 124 { 125 debug(DwarfDebugMachine) printf("new debug program\n"); 126 const lp = readLineNumberProgram(dbg); 127 128 LocationInfo lastLoc = LocationInfo(-1, -1); 129 size_t lastAddress = 0x0; 130 131 debug(DwarfDebugMachine) printf("program:\n"); 132 runStateMachine(lp, 133 (size_t address, LocationInfo locInfo, bool isEndSequence) 134 { 135 // adjust to ASLR offset 136 address += baseAddress; 137 debug (DwarfDebugMachine) 138 printf("-- offsetting 0x%zx to 0x%zx\n", address - baseAddress, address); 139 140 foreach (ref loc; locations) 141 { 142 // If loc.line != -1, then it has been set previously. 143 // Some implementations (eg. dmd) write an address to 144 // the debug data multiple times, but so far I have found 145 // that the first occurrence to be the correct one. 146 if (loc.line != -1) 147 continue; 148 149 // Can be called with either `locInfo` or `lastLoc` 150 void update(const ref LocationInfo match) 151 { 152 const sourceFile = lp.sourceFiles[match.file - 1]; 153 debug (DwarfDebugMachine) 154 { 155 printf("-- found for [0x%zx]:\n", loc.address); 156 printf("-- file: %.*s\n", 157 cast(int) sourceFile.file.length, sourceFile.file.ptr); 158 printf("-- line: %d\n", match.line); 159 } 160 // DMD emits entries with FQN, but other implmentations 161 // (e.g. LDC) make use of directories 162 // See https://github.com/dlang/druntime/pull/2945 163 if (sourceFile.dirIndex != 0) 164 loc.directory = lp.includeDirectories[sourceFile.dirIndex - 1]; 165 166 loc.file = sourceFile.file; 167 loc.line = match.line; 168 numberOfLocationsFound++; 169 } 170 171 // The state machine will not contain an entry for each 172 // address, as consecutive addresses with the same file/line 173 // are merged together to save on space, so we need to 174 // check if our address is within two addresses we get 175 // called with. 176 // 177 // Specs (DWARF v4, Section 6.2, PDF p.109) says: 178 // "We shrink it with two techniques. First, we delete from 179 // the matrix each row whose file, line, source column and 180 // discriminator information is identical with that of its 181 // predecessors. 182 if (loc.address == address) 183 update(locInfo); 184 else if (lastAddress && 185 loc.address > lastAddress && loc.address < address) 186 update(lastLoc); 187 } 188 189 if (isEndSequence) 190 { 191 lastAddress = 0; 192 } 193 else 194 { 195 lastAddress = address; 196 lastLoc = locInfo; 197 } 198 199 return numberOfLocationsFound < locations.length; 200 } 201 ); 202 203 if (numberOfLocationsFound == locations.length) return; 204 } 205 } 206 207 const(char)[] getDemangledSymbol(const(char)[] btSymbol, return ref char[1024] buffer) nothrow @nogc 208 { 209 //import core.demangle; // isn't @nogc :( 210 import bc.core.demangle : demangle; 211 import core.internal.execinfo : getMangledSymbolName; 212 213 const mangledName = getMangledSymbolName(btSymbol); 214 return !mangledName.length ? buffer[0..0] : demangle(mangledName, buffer[]); 215 // return mangledName; 216 } 217 218 struct LineNumberProgram 219 { 220 ulong unitLength; 221 ushort dwarfVersion; 222 ulong headerLength; 223 ubyte minimumInstructionLength; 224 ubyte maximumOperationsPerInstruction; 225 bool defaultIsStatement; 226 byte lineBase; 227 ubyte lineRange; 228 ubyte opcodeBase; 229 const(ubyte)[] standardOpcodeLengths; 230 Array!(const(char)[]) includeDirectories; 231 Array!SourceFile sourceFiles; 232 const(ubyte)[] program; 233 } 234 235 struct SourceFile 236 { 237 const(char)[] file; 238 size_t dirIndex; 239 } 240 241 struct LocationInfo 242 { 243 int file; 244 int line; 245 } 246 247 LineNumberProgram readLineNumberProgram(ref const(ubyte)[] data) @nogc nothrow 248 { 249 // import core.stdc.stdio : printf; 250 // printf("!my readLineNumberProgram: "); 251 // foreach (b; data[0..data.length > 256 ? 256 : $]) printf("%02X", b); 252 // printf("\n"); 253 254 const originalData = data; 255 256 LineNumberProgram lp; 257 258 bool is64bitDwarf = false; 259 lp.unitLength = data.read!uint(); 260 if (lp.unitLength == uint.max) 261 { 262 is64bitDwarf = true; 263 lp.unitLength = data.read!ulong(); 264 } 265 266 const dwarfVersionFieldOffset = cast(size_t) (data.ptr - originalData.ptr); 267 lp.dwarfVersion = data.read!ushort(); 268 debug(DwarfDebugMachine) printf("DWARF version: %d\n", lp.dwarfVersion); 269 assert(lp.dwarfVersion < 5, "DWARF v5+ not supported yet"); 270 271 lp.headerLength = (is64bitDwarf ? data.read!ulong() : data.read!uint()); 272 273 const minimumInstructionLengthFieldOffset = cast(size_t) (data.ptr - originalData.ptr); 274 lp.minimumInstructionLength = data.read!ubyte(); 275 276 lp.maximumOperationsPerInstruction = (lp.dwarfVersion >= 4 ? data.read!ubyte() : 1); 277 lp.defaultIsStatement = (data.read!ubyte() != 0); 278 lp.lineBase = data.read!byte(); 279 lp.lineRange = data.read!ubyte(); 280 lp.opcodeBase = data.read!ubyte(); 281 282 lp.standardOpcodeLengths = data[0 .. lp.opcodeBase - 1]; 283 data = data[lp.opcodeBase - 1 .. $]; 284 285 // A sequence ends with a null-byte. 286 static auto readSequence(alias ReadEntry)(ref const(ubyte)[] data) 287 { 288 alias ResultType = typeof(ReadEntry(data)); 289 290 static size_t count(const(ubyte)[] data) 291 { 292 size_t count = 0; 293 while (data.length && data[0] != 0) 294 { 295 ReadEntry(data); 296 ++count; 297 } 298 return count; 299 } 300 301 const numEntries = count(data); 302 303 Array!ResultType result; 304 result.length = numEntries; 305 306 foreach (i; 0 .. numEntries) 307 result[i] = ReadEntry(data); 308 309 data = data[1 .. $]; // skip over sequence-terminating null 310 311 return result; 312 } 313 314 static const(char)[] readIncludeDirectoryEntry(ref const(ubyte)[] data) 315 { 316 const length = strlen(cast(char*) data.ptr); 317 auto result = cast(const(char)[]) data[0 .. length]; 318 debug(DwarfDebugMachine) printf("dir: %.*s\n", cast(int) length, result.ptr); 319 data = data[length + 1 .. $]; 320 return result; 321 } 322 lp.includeDirectories = readSequence!readIncludeDirectoryEntry(data); 323 324 static SourceFile readFileNameEntry(ref const(ubyte)[] data) 325 { 326 const length = strlen(cast(char*) data.ptr); 327 auto file = cast(const(char)[]) data[0 .. length]; 328 debug(DwarfDebugMachine) printf("file: %.*s\n", cast(int) length, file.ptr); 329 data = data[length + 1 .. $]; 330 331 auto dirIndex = cast(size_t) data.readULEB128(); 332 333 data.readULEB128(); // last mod 334 data.readULEB128(); // file len 335 336 return SourceFile( 337 file, 338 dirIndex, 339 ); 340 } 341 lp.sourceFiles = readSequence!readFileNameEntry(data); 342 343 const programStart = cast(size_t) (minimumInstructionLengthFieldOffset + lp.headerLength); 344 const programEnd = cast(size_t) (dwarfVersionFieldOffset + lp.unitLength); 345 lp.program = originalData[programStart .. programEnd]; 346 347 data = originalData[programEnd .. $]; 348 349 return lp; 350 } 351 352 T read(T)(ref const(ubyte)[] buffer) @nogc nothrow 353 { 354 version (X86) enum hasUnalignedLoads = true; 355 else version (X86_64) enum hasUnalignedLoads = true; 356 else enum hasUnalignedLoads = false; 357 358 static if (hasUnalignedLoads || T.alignof == 1) 359 { 360 T result = *(cast(T*) buffer.ptr); 361 } 362 else 363 { 364 import core.stdc.string : memcpy; 365 T result = void; 366 memcpy(&result, buffer.ptr, T.sizeof); 367 } 368 369 buffer = buffer[T.sizeof .. $]; 370 return result; 371 } 372 373 ulong readULEB128(ref const(ubyte)[] buffer) @nogc nothrow 374 { 375 ulong val = 0; 376 uint shift = 0; 377 378 while (true) 379 { 380 ubyte b = buffer.read!ubyte(); 381 382 val |= (b & 0x7f) << shift; 383 if ((b & 0x80) == 0) break; 384 shift += 7; 385 } 386 387 return val; 388 } 389 390 long readSLEB128(ref const(ubyte)[] buffer) @nogc nothrow 391 { 392 long val = 0; 393 uint shift = 0; 394 int size = 8 << 3; 395 ubyte b; 396 397 while (true) 398 { 399 b = buffer.read!ubyte(); 400 val |= (b & 0x7f) << shift; 401 shift += 7; 402 if ((b & 0x80) == 0) 403 break; 404 } 405 406 if (shift < size && (b & 0x40) != 0) 407 val |= -(1 << shift); 408 409 return val; 410 } 411 412 alias RunStateMachineCallback = 413 bool delegate(size_t address, LocationInfo info, bool isEndSequence) 414 @nogc nothrow; 415 416 enum StandardOpcode : ubyte 417 { 418 extendedOp = 0, 419 copy = 1, 420 advancePC = 2, 421 advanceLine = 3, 422 setFile = 4, 423 setColumn = 5, 424 negateStatement = 6, 425 setBasicBlock = 7, 426 constAddPC = 8, 427 fixedAdvancePC = 9, 428 setPrologueEnd = 10, 429 setEpilogueBegin = 11, 430 setISA = 12, 431 } 432 433 enum ExtendedOpcode : ubyte 434 { 435 endSequence = 1, 436 setAddress = 2, 437 defineFile = 3, 438 setDiscriminator = 4, 439 } 440 441 struct StateMachine 442 { 443 size_t address = 0; 444 uint operationIndex = 0; 445 uint fileIndex = 1; 446 uint line = 1; 447 uint column = 0; 448 uint isa = 0; 449 uint discriminator = 0; 450 bool isStatement; 451 bool isBasicBlock = false; 452 bool isEndSequence = false; 453 bool isPrologueEnd = false; 454 bool isEpilogueBegin = false; 455 } 456 457 bool runStateMachine(ref const(LineNumberProgram) lp, scope RunStateMachineCallback callback) @nogc nothrow 458 { 459 StateMachine machine; 460 machine.isStatement = lp.defaultIsStatement; 461 462 const(ubyte)[] program = lp.program; 463 while (program.length > 0) 464 { 465 size_t advanceAddressAndOpIndex(size_t operationAdvance) 466 { 467 const addressIncrement = lp.minimumInstructionLength * ((machine.operationIndex + operationAdvance) / lp.maximumOperationsPerInstruction); 468 machine.address += addressIncrement; 469 machine.operationIndex = (machine.operationIndex + operationAdvance) % lp.maximumOperationsPerInstruction; 470 return addressIncrement; 471 } 472 473 ubyte opcode = program.read!ubyte(); 474 if (opcode < lp.opcodeBase) 475 { 476 switch (opcode) with (StandardOpcode) 477 { 478 case extendedOp: 479 size_t len = cast(size_t) program.readULEB128(); 480 ubyte eopcode = program.read!ubyte(); 481 482 switch (eopcode) with (ExtendedOpcode) 483 { 484 case endSequence: 485 machine.isEndSequence = true; 486 debug(DwarfDebugMachine) printf("endSequence 0x%zx\n", machine.address); 487 if (!callback(machine.address, LocationInfo(machine.fileIndex, machine.line), true)) return true; 488 machine = StateMachine.init; 489 machine.isStatement = lp.defaultIsStatement; 490 break; 491 492 case setAddress: 493 size_t address = program.read!size_t(); 494 debug(DwarfDebugMachine) printf("setAddress 0x%zx\n", address); 495 machine.address = address; 496 machine.operationIndex = 0; 497 break; 498 499 case defineFile: // TODO: add proper implementation 500 debug(DwarfDebugMachine) printf("defineFile\n"); 501 program = program[len - 1 .. $]; 502 break; 503 504 case setDiscriminator: 505 const discriminator = cast(uint) program.readULEB128(); 506 debug(DwarfDebugMachine) printf("setDiscriminator %d\n", discriminator); 507 machine.discriminator = discriminator; 508 break; 509 510 default: 511 // unknown opcode 512 debug(DwarfDebugMachine) printf("unknown extended opcode %d\n", cast(int) eopcode); 513 program = program[len - 1 .. $]; 514 break; 515 } 516 517 break; 518 519 case copy: 520 debug(DwarfDebugMachine) printf("copy 0x%zx\n", machine.address); 521 if (!callback(machine.address, LocationInfo(machine.fileIndex, machine.line), false)) return true; 522 machine.isBasicBlock = false; 523 machine.isPrologueEnd = false; 524 machine.isEpilogueBegin = false; 525 machine.discriminator = 0; 526 break; 527 528 case advancePC: 529 const operationAdvance = cast(size_t) readULEB128(program); 530 advanceAddressAndOpIndex(operationAdvance); 531 debug(DwarfDebugMachine) printf("advancePC %d to 0x%zx\n", cast(int) operationAdvance, machine.address); 532 break; 533 534 case advanceLine: 535 long ad = readSLEB128(program); 536 machine.line += ad; 537 debug(DwarfDebugMachine) printf("advanceLine %d to %d\n", cast(int) ad, cast(int) machine.line); 538 break; 539 540 case setFile: 541 uint index = cast(uint) readULEB128(program); 542 debug(DwarfDebugMachine) printf("setFile to %d\n", cast(int) index); 543 machine.fileIndex = index; 544 break; 545 546 case setColumn: 547 uint col = cast(uint) readULEB128(program); 548 debug(DwarfDebugMachine) printf("setColumn %d\n", cast(int) col); 549 machine.column = col; 550 break; 551 552 case negateStatement: 553 debug(DwarfDebugMachine) printf("negateStatement\n"); 554 machine.isStatement = !machine.isStatement; 555 break; 556 557 case setBasicBlock: 558 debug(DwarfDebugMachine) printf("setBasicBlock\n"); 559 machine.isBasicBlock = true; 560 break; 561 562 case constAddPC: 563 const operationAdvance = (255 - lp.opcodeBase) / lp.lineRange; 564 advanceAddressAndOpIndex(operationAdvance); 565 debug(DwarfDebugMachine) printf("constAddPC 0x%zx\n", machine.address); 566 break; 567 568 case fixedAdvancePC: 569 const add = program.read!ushort(); 570 machine.address += add; 571 machine.operationIndex = 0; 572 debug(DwarfDebugMachine) printf("fixedAdvancePC %d to 0x%zx\n", cast(int) add, machine.address); 573 break; 574 575 case setPrologueEnd: 576 machine.isPrologueEnd = true; 577 debug(DwarfDebugMachine) printf("setPrologueEnd\n"); 578 break; 579 580 case setEpilogueBegin: 581 machine.isEpilogueBegin = true; 582 debug(DwarfDebugMachine) printf("setEpilogueBegin\n"); 583 break; 584 585 case setISA: 586 machine.isa = cast(uint) readULEB128(program); 587 debug(DwarfDebugMachine) printf("setISA %d\n", cast(int) machine.isa); 588 break; 589 590 default: 591 debug(DwarfDebugMachine) printf("unknown opcode %d\n", cast(int) opcode); 592 return false; 593 } 594 } 595 else 596 { 597 opcode -= lp.opcodeBase; 598 const operationAdvance = opcode / lp.lineRange; 599 const addressIncrement = advanceAddressAndOpIndex(operationAdvance); 600 const lineIncrement = lp.lineBase + (opcode % lp.lineRange); 601 machine.line += lineIncrement; 602 603 debug (DwarfDebugMachine) 604 printf("special %d %d to 0x%zx line %d\n", cast(int) addressIncrement, 605 cast(int) lineIncrement, machine.address, machine.line); 606 607 if (!callback(machine.address, LocationInfo(machine.fileIndex, machine.line), false)) return true; 608 609 machine.isBasicBlock = false; 610 machine.isPrologueEnd = false; 611 machine.isEpilogueBegin = false; 612 machine.discriminator = 0; 613 } 614 } 615 616 return true; 617 } 618 619 struct Location 620 { 621 const(char)[] file = null; 622 const(char)[] directory = null; 623 int line = -1; 624 size_t address; 625 } 626 627 // See: module rt.util.container.array; 628 struct Array(T) 629 { 630 nothrow: 631 @disable this(this); 632 633 ~this() 634 { 635 reset(); 636 } 637 638 void reset() 639 { 640 length = 0; 641 } 642 643 @property size_t length() const 644 { 645 return _length; 646 } 647 648 @property void length(size_t nlength) 649 { 650 import core.checkedint : mulu; 651 652 bool overflow = false; 653 size_t reqsize = mulu(T.sizeof, nlength, overflow); 654 if (!overflow) 655 { 656 if (nlength < _length) 657 foreach (ref val; _ptr[nlength .. _length]) .destroy(val); 658 _ptr = cast(T*).xrealloc(_ptr, reqsize); 659 if (nlength > _length) 660 foreach (ref val; _ptr[_length .. nlength]) .initialize(val); 661 _length = nlength; 662 } 663 else 664 onOutOfMemoryErrorNoGC(); 665 666 } 667 668 @property bool empty() const 669 { 670 return !length; 671 } 672 673 @property ref inout(T) front() inout 674 in { assert(!empty); } 675 do 676 { 677 return _ptr[0]; 678 } 679 680 @property ref inout(T) back() inout 681 in { assert(!empty); } 682 do 683 { 684 return _ptr[_length - 1]; 685 } 686 687 ref inout(T) opIndex(size_t idx) inout 688 in { assert(idx < length); } 689 do 690 { 691 return _ptr[idx]; 692 } 693 694 inout(T)[] opSlice() inout 695 { 696 return _ptr[0 .. _length]; 697 } 698 699 inout(T)[] opSlice(size_t a, size_t b) inout 700 in { assert(a < b && b <= length); } 701 do 702 { 703 return _ptr[a .. b]; 704 } 705 706 alias length opDollar; 707 708 void insertBack()(auto ref T val) 709 { 710 import core.checkedint : addu; 711 712 bool overflow = false; 713 size_t newlength = addu(length, 1, overflow); 714 if (!overflow) 715 { 716 length = newlength; 717 back = val; 718 } 719 else 720 onOutOfMemoryErrorNoGC(); 721 } 722 723 void popBack() 724 { 725 length = length - 1; 726 } 727 728 void remove(size_t idx) 729 in { assert(idx < length); } 730 do 731 { 732 foreach (i; idx .. length - 1) 733 _ptr[i] = _ptr[i+1]; 734 popBack(); 735 } 736 737 void swap(ref Array other) 738 { 739 auto ptr = _ptr; 740 _ptr = other._ptr; 741 other._ptr = ptr; 742 immutable len = _length; 743 _length = other._length; 744 other._length = len; 745 } 746 747 invariant 748 { 749 assert(!_ptr == !_length); 750 } 751 752 private: 753 T* _ptr; 754 size_t _length; 755 } 756 757 import core.stdc.stdlib : malloc, realloc, free; 758 759 // See: rt.util.container.common 760 void* xrealloc(void* ptr, size_t sz) nothrow @nogc 761 { 762 import core.exception; 763 764 if (!sz) { .free(ptr); return null; } 765 if (auto nptr = .realloc(ptr, sz)) return nptr; 766 .free(ptr); onOutOfMemoryErrorNoGC(); 767 assert(0); 768 } 769 770 void destroy(T)(ref T t) if (is(T == struct) && dtorIsNothrow!T) 771 { 772 scope (failure) assert(0); // nothrow hack 773 object.destroy(t); 774 } 775 776 void destroy(T)(ref T t) if (!is(T == struct)) 777 { 778 t = T.init; 779 } 780 781 void initialize(T)(ref T t) if (is(T == struct)) 782 { 783 import core.stdc.string; 784 static if (__traits(isPOD, T)) // implies !hasElaborateAssign!T && !hasElaborateDestructor!T 785 t = T.init; 786 else static if (__traits(isZeroInit, T)) 787 memset(&t, 0, T.sizeof); 788 else 789 memcpy(&t, typeid(T).initializer().ptr, T.sizeof); 790 } 791 792 void initialize(T)(ref T t) if (!is(T == struct)) 793 { 794 t = T.init; 795 }