1 /** 2 * Convert an AST that went through all semantic phases into an object file. 3 * 4 * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved 5 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) 6 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 7 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/tocsym.d, _toobj.d) 8 * Documentation: https://dlang.org/phobos/dmd_toobj.html 9 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/toobj.d 10 */ 11 12 module dmd.toobj; 13 14 import core.stdc.stdio; 15 import core.stdc.stddef; 16 import core.stdc.string; 17 import core.stdc.time; 18 19 import dmd.root.array; 20 import dmd.common.outbuffer; 21 import dmd.root.rmem; 22 import dmd.rootobject; 23 24 import dmd.aggregate; 25 import dmd.arraytypes; 26 import dmd.astenums; 27 import dmd.attrib; 28 import dmd.dcast; 29 import dmd.dclass; 30 import dmd.declaration; 31 import dmd.denum; 32 import dmd.dmdparams; 33 import dmd.dmodule; 34 import dmd.dscope; 35 import dmd.dstruct; 36 import dmd.dsymbol; 37 import dmd.dtemplate; 38 import dmd.errors; 39 import dmd.expression; 40 import dmd.func; 41 import dmd.globals; 42 import dmd.glue; 43 import dmd.hdrgen; 44 import dmd.id; 45 import dmd.init; 46 import dmd.location; 47 import dmd.mtype; 48 import dmd.nspace; 49 import dmd.objc_glue; 50 import dmd.statement; 51 import dmd.staticassert; 52 import dmd.target; 53 import dmd.tocsym; 54 import dmd.toctype; 55 import dmd.tocvdebug; 56 import dmd.todt; 57 import dmd.tokens; 58 import dmd.traits; 59 import dmd.typinf; 60 import dmd.visitor; 61 62 import dmd.backend.cc; 63 import dmd.backend.cdef; 64 import dmd.backend.cgcv; 65 import dmd.backend.code; 66 import dmd.backend.code_x86; 67 import dmd.backend.cv4; 68 import dmd.backend.dt; 69 import dmd.backend.el; 70 import dmd.backend.global; 71 import dmd.backend.obj; 72 import dmd.backend.oper; 73 import dmd.backend.ty; 74 import dmd.backend.type; 75 76 extern (C++): 77 78 /* ================================================================== */ 79 80 // Put out instance of ModuleInfo for this Module 81 82 void genModuleInfo(Module m) 83 { 84 //printf("Module.genmoduleinfo() %s\n", m.toChars()); 85 86 if (!Module.moduleinfo) 87 { 88 ObjectNotFound(Id.ModuleInfo); 89 } 90 91 Symbol *msym = toSymbol(m); 92 93 ////////////////////////////////////////////// 94 95 m.csym.Sclass = SC.global; 96 m.csym.Sfl = FLdata; 97 98 auto dtb = DtBuilder(0); 99 100 ClassDeclarations aclasses; 101 getLocalClasses(m, aclasses); 102 103 // importedModules[] 104 size_t aimports_dim = m.aimports.length; 105 for (size_t i = 0; i < m.aimports.length; i++) 106 { 107 Module mod = m.aimports[i]; 108 if (!mod.needmoduleinfo) 109 aimports_dim--; 110 } 111 112 FuncDeclaration sgetmembers = m.findGetMembers(); 113 114 // These must match the values in druntime/src/object_.d 115 enum 116 { 117 MIstandalone = 0x4, 118 MItlsctor = 0x8, 119 MItlsdtor = 0x10, 120 MIctor = 0x20, 121 MIdtor = 0x40, 122 MIxgetMembers = 0x80, 123 MIictor = 0x100, 124 MIunitTest = 0x200, 125 MIimportedModules = 0x400, 126 MIlocalClasses = 0x800, 127 MIname = 0x1000, 128 } 129 130 uint flags = 0; 131 if (!m.needmoduleinfo) 132 flags |= MIstandalone; 133 if (m.sctor) 134 flags |= MItlsctor; 135 if (m.sdtor) 136 flags |= MItlsdtor; 137 if (m.ssharedctor) 138 flags |= MIctor; 139 if (m.sshareddtor) 140 flags |= MIdtor; 141 if (sgetmembers) 142 flags |= MIxgetMembers; 143 if (m.sictor) 144 flags |= MIictor; 145 if (m.stest) 146 flags |= MIunitTest; 147 if (aimports_dim) 148 flags |= MIimportedModules; 149 if (aclasses.length) 150 flags |= MIlocalClasses; 151 flags |= MIname; 152 153 dtb.dword(flags); // _flags 154 dtb.dword(0); // _index 155 156 if (flags & MItlsctor) 157 dtb.xoff(m.sctor, 0, TYnptr); 158 if (flags & MItlsdtor) 159 dtb.xoff(m.sdtor, 0, TYnptr); 160 if (flags & MIctor) 161 dtb.xoff(m.ssharedctor, 0, TYnptr); 162 if (flags & MIdtor) 163 dtb.xoff(m.sshareddtor, 0, TYnptr); 164 if (flags & MIxgetMembers) 165 dtb.xoff(toSymbol(sgetmembers), 0, TYnptr); 166 if (flags & MIictor) 167 dtb.xoff(m.sictor, 0, TYnptr); 168 if (flags & MIunitTest) 169 dtb.xoff(m.stest, 0, TYnptr); 170 if (flags & MIimportedModules) 171 { 172 dtb.size(aimports_dim); 173 foreach (i; 0 .. m.aimports.length) 174 { 175 Module mod = m.aimports[i]; 176 177 if (!mod.needmoduleinfo) 178 continue; 179 180 Symbol *s = toSymbol(mod); 181 182 /* Weak references don't pull objects in from the library, 183 * they resolve to 0 if not pulled in by something else. 184 * Don't pull in a module just because it was imported. 185 */ 186 s.Sflags |= SFLweak; 187 dtb.xoff(s, 0, TYnptr); 188 } 189 } 190 if (flags & MIlocalClasses) 191 { 192 dtb.size(aclasses.length); 193 foreach (i; 0 .. aclasses.length) 194 { 195 ClassDeclaration cd = aclasses[i]; 196 dtb.xoff(toSymbol(cd), 0, TYnptr); 197 } 198 } 199 if (flags & MIname) 200 { 201 // Put out module name as a 0-terminated string, to save bytes 202 m.nameoffset = dtb.length(); 203 const(char) *name = m.toPrettyChars(); 204 m.namelen = strlen(name); 205 dtb.nbytes(cast(uint)m.namelen + 1, name); 206 //printf("nameoffset = x%x\n", nameoffset); 207 } 208 209 objc.generateModuleInfo(m); 210 m.csym.Sdt = dtb.finish(); 211 out_readonly(m.csym); 212 outdata(m.csym); 213 214 ////////////////////////////////////////////// 215 216 objmod.moduleinfo(msym); 217 } 218 219 /***************************************** 220 * write pointer references for typed data to the object file 221 * a class type is considered to mean a reference to a class instance 222 * Params: 223 * type = type of the data to check for pointers 224 * s = symbol that contains the data 225 * offset = offset of the data inside the Symbol's memory 226 */ 227 void write_pointers(Type type, Symbol *s, uint offset) 228 { 229 uint ty = type.toBasetype().ty; 230 if (ty == Tclass) 231 return objmod.write_pointerRef(s, offset); 232 233 write_instance_pointers(type, s, offset); 234 } 235 236 /***************************************** 237 * write pointer references for typed data to the object file 238 * a class type is considered to mean the instance, not a reference 239 * Params: 240 * type = type of the data to check for pointers 241 * s = symbol that contains the data 242 * offset = offset of the data inside the Symbol's memory 243 */ 244 void write_instance_pointers(Type type, Symbol *s, uint offset) 245 { 246 if (!type.hasPointers()) 247 return; 248 249 Array!(ulong) data; 250 ulong sz = getTypePointerBitmap(Loc.initial, type, &data); 251 if (sz == ulong.max) 252 return; 253 254 const bytes_size_t = cast(size_t)Type.tsize_t.size(Loc.initial); 255 const bits_size_t = bytes_size_t * 8; 256 auto words = cast(size_t)(sz / bytes_size_t); 257 for (size_t i = 0; i < data.length; i++) 258 { 259 size_t bits = words < bits_size_t ? words : bits_size_t; 260 for (size_t b = 0; b < bits; b++) 261 if (data[i] & (1L << b)) 262 { 263 auto off = cast(uint) ((i * bits_size_t + b) * bytes_size_t); 264 objmod.write_pointerRef(s, off + offset); 265 } 266 words -= bits; 267 } 268 } 269 270 /**************************************************** 271 * Put out instance of the `TypeInfo` object associated with `t` if it 272 * hasn't already been generated 273 * Params: 274 * e = if not null, then expression for pretty-printing errors 275 * loc = the location for reporting line numbers in errors 276 * t = the type to generate the `TypeInfo` object for 277 */ 278 void TypeInfo_toObjFile(Expression e, const ref Loc loc, Type t) 279 { 280 // printf("TypeInfo_toObjFIle() %s\n", torig.toChars()); 281 if (genTypeInfo(e, loc, t, null)) 282 { 283 // generate a COMDAT for other TypeInfos not available as builtins in druntime 284 toObjFile(t.vtinfo, global.params.multiobj); 285 } 286 } 287 288 /* ================================================================== */ 289 290 void toObjFile(Dsymbol ds, bool multiobj) 291 { 292 //printf("toObjFile(%s %s)\n", ds.kind(), ds.toChars()); 293 294 bool isCfile = ds.isCsymbol(); 295 296 extern (C++) final class ToObjFile : Visitor 297 { 298 alias visit = Visitor.visit; 299 public: 300 bool multiobj; 301 302 this(bool multiobj) scope @safe 303 { 304 this.multiobj = multiobj; 305 } 306 307 void visitNoMultiObj(Dsymbol ds) 308 { 309 bool multiobjsave = multiobj; 310 multiobj = false; 311 ds.accept(this); 312 multiobj = multiobjsave; 313 } 314 315 override void visit(Dsymbol ds) 316 { 317 //printf("Dsymbol.toObjFile('%s')\n", ds.toChars()); 318 // ignore 319 } 320 321 override void visit(FuncDeclaration fd) 322 { 323 // in glue.c 324 FuncDeclaration_toObjFile(fd, multiobj); 325 } 326 327 override void visit(ClassDeclaration cd) 328 { 329 //printf("ClassDeclaration.toObjFile('%s')\n", cd.toChars()); 330 331 if (cd.type.ty == Terror) 332 { 333 .error(cd.loc, "%s `%s` had semantic errors when compiling", cd.kind, cd.toPrettyChars); 334 return; 335 } 336 337 if (!cd.members) 338 return; 339 340 if (multiobj && !cd.hasStaticCtorOrDtor()) 341 { 342 obj_append(cd); 343 return; 344 } 345 346 if (driverParams.symdebugref) 347 Type_toCtype(cd.type); // calls toDebug() only once 348 else if (driverParams.symdebug) 349 toDebug(cd); 350 351 assert(cd.semanticRun >= PASS.semantic3done); // semantic() should have been run to completion 352 353 SC scclass = SC.comdat; 354 355 // Put out the members 356 /* There might be static ctors in the members, and they cannot 357 * be put in separate obj files. 358 */ 359 cd.members.foreachDsymbol( (s) { s.accept(this); } ); 360 361 if (cd.classKind == ClassKind.objc) 362 { 363 objc.toObjFile(cd); 364 return; 365 } 366 367 // If something goes wrong during this pass don't bother with the 368 // rest as we may have incomplete info 369 // https://issues.dlang.org/show_bug.cgi?id=17918 370 if (!finishVtbl(cd)) 371 { 372 return; 373 } 374 375 const bool gentypeinfo = global.params.useTypeInfo && Type.dtypeinfo; 376 const bool genclassinfo = gentypeinfo || !(cd.isCPPclass || cd.isCOMclass); 377 378 // Generate C symbols 379 if (genclassinfo) 380 toSymbol(cd); // __ClassZ symbol 381 toVtblSymbol(cd, genclassinfo); // __vtblZ symbol 382 Symbol *sinit = toInitializer(cd); // __initZ symbol 383 384 ////////////////////////////////////////////// 385 386 // Generate static initializer 387 { 388 sinit.Sclass = scclass; 389 sinit.Sfl = FLdata; 390 auto dtb = DtBuilder(0); 391 ClassDeclaration_toDt(cd, dtb); 392 sinit.Sdt = dtb.finish(); 393 out_readonly(sinit); 394 outdata(sinit); 395 } 396 397 ////////////////////////////////////////////// 398 399 // Put out the TypeInfo 400 if (gentypeinfo) 401 TypeInfo_toObjFile(null, cd.loc, cd.type); 402 //toObjFile(cd.type.vtinfo, multiobj); 403 404 if (genclassinfo) 405 { 406 genClassInfoForClass(cd, sinit); 407 } 408 409 ////////////////////////////////////////////// 410 411 // Put out the vtbl[] 412 //printf("putting out %s.vtbl[]\n", toChars()); 413 auto dtbv = DtBuilder(0); 414 if (cd.vtblOffset()) 415 dtbv.xoff(cd.csym, 0, TYnptr); // first entry is ClassInfo reference 416 foreach (i; cd.vtblOffset() .. cd.vtbl.length) 417 { 418 FuncDeclaration fd = cd.vtbl[i].isFuncDeclaration(); 419 420 //printf("\tvtbl[%d] = %p\n", i, fd); 421 if (fd && (fd.fbody || !cd.isAbstract())) 422 { 423 dtbv.xoff(toSymbol(fd), 0, TYnptr); 424 } 425 else 426 dtbv.size(0); 427 } 428 if (dtbv.isZeroLength()) 429 { 430 /* Someone made an 'extern (C++) class C { }' with no virtual functions. 431 * But making an empty vtbl[] causes linking problems, so make a dummy 432 * entry. 433 */ 434 dtbv.size(0); 435 } 436 cd.vtblsym.csym.Sdt = dtbv.finish(); 437 cd.vtblsym.csym.Sclass = scclass; 438 cd.vtblsym.csym.Sfl = FLdata; 439 out_readonly(cd.vtblsym.csym); 440 outdata(cd.vtblsym.csym); 441 if (cd.isExport()) 442 objmod.export_symbol(cd.vtblsym.csym,0); 443 } 444 445 override void visit(InterfaceDeclaration id) 446 { 447 //printf("InterfaceDeclaration.toObjFile('%s')\n", id.toChars()); 448 449 if (id.type.ty == Terror) 450 { 451 .error(id.loc, "had semantic errors when compiling", id.kind, id.toPrettyChars); 452 return; 453 } 454 455 if (!id.members) 456 return; 457 458 if (driverParams.symdebugref) 459 Type_toCtype(id.type); // calls toDebug() only once 460 else if (driverParams.symdebug) 461 toDebug(id); 462 463 // Put out the members 464 id.members.foreachDsymbol( (s) { visitNoMultiObj(s); } ); 465 466 // Objetive-C protocols are only output if implemented as a class. 467 // If so, they're output via the class declaration. 468 if (id.classKind == ClassKind.objc) 469 return; 470 471 const bool gentypeinfo = global.params.useTypeInfo && Type.dtypeinfo; 472 const bool genclassinfo = gentypeinfo || !(id.isCPPclass || id.isCOMclass); 473 474 475 // Generate C symbols 476 if (genclassinfo) 477 toSymbol(id); 478 479 ////////////////////////////////////////////// 480 481 // Put out the TypeInfo 482 if (gentypeinfo) 483 { 484 TypeInfo_toObjFile(null, id.loc, id.type); 485 id.type.vtinfo.accept(this); 486 } 487 488 ////////////////////////////////////////////// 489 490 if (genclassinfo) 491 genClassInfoForInterface(id); 492 } 493 494 override void visit(StructDeclaration sd) 495 { 496 //printf("StructDeclaration.toObjFile('%s')\n", sd.toChars()); 497 498 if (sd.type.ty == Terror) 499 { 500 .error(sd.loc, "%s `%s` had semantic errors when compiling", sd.kind, sd.toPrettyChars); 501 return; 502 } 503 504 if (multiobj && !sd.hasStaticCtorOrDtor()) 505 { 506 obj_append(sd); 507 return; 508 } 509 510 // Anonymous structs/unions only exist as part of others, 511 // do not output forward referenced structs's 512 if (!sd.isAnonymous() && sd.members) 513 { 514 if (driverParams.symdebugref) 515 Type_toCtype(sd.type); // calls toDebug() only once 516 else if (driverParams.symdebug) 517 toDebug(sd); 518 519 if (global.params.useTypeInfo && Type.dtypeinfo) 520 TypeInfo_toObjFile(null, sd.loc, sd.type); 521 522 // Generate static initializer 523 auto sinit = toInitializer(sd); 524 if (sinit.Sclass == SC.extern_) 525 { 526 if (sinit == bzeroSymbol) assert(0); 527 sinit.Sclass = sd.isInstantiated() ? SC.comdat : SC.global; 528 sinit.Sfl = FLdata; 529 auto dtb = DtBuilder(0); 530 StructDeclaration_toDt(sd, dtb); 531 sinit.Sdt = dtb.finish(); 532 533 /* fails to link on OBJ_MACH 64 with: 534 * ld: in generated/osx/release/64/libphobos2.a(dwarfeh_8dc_56a.o), 535 * in section __TEXT,__textcoal_nt reloc 6: 536 * symbol index out of range for architecture x86_64 537 */ 538 if (config.objfmt != OBJ_MACH && 539 dtallzeros(sinit.Sdt)) 540 { 541 sinit.Sclass = SC.global; 542 dt2common(&sinit.Sdt); 543 } 544 else 545 out_readonly(sinit); // put in read-only segment 546 outdata(sinit); 547 } 548 549 // Put out the members 550 /* There might be static ctors in the members, and they cannot 551 * be put in separate obj files. 552 */ 553 sd.members.foreachDsymbol( (s) { s.accept(this); } ); 554 555 if (sd.xeq && sd.xeq != StructDeclaration.xerreq) 556 sd.xeq.accept(this); 557 if (sd.xcmp && sd.xcmp != StructDeclaration.xerrcmp) 558 sd.xcmp.accept(this); 559 if (sd.xhash) 560 sd.xhash.accept(this); 561 } 562 } 563 564 override void visit(VarDeclaration vd) 565 { 566 567 //printf("VarDeclaration.toObjFile(%p '%s' type=%s) visibility %d\n", vd, vd.toChars(), vd.type.toChars(), vd.visibility); 568 //printf("\talign = %d\n", vd.alignment); 569 570 if (vd.type.ty == Terror) 571 { 572 .error(vd.loc, "%s `%s` had semantic errors when compiling", vd.kind, vd.toPrettyChars); 573 return; 574 } 575 576 if (vd.aliasTuple) 577 { 578 vd.toAlias().accept(this); 579 return; 580 } 581 582 // Do not store variables we cannot take the address of 583 if (!vd.canTakeAddressOf()) 584 { 585 return; 586 } 587 588 if (!vd.isDataseg() || vd.storage_class & STC.extern_) 589 return; 590 591 Symbol *s = toSymbol(vd); 592 const sz64 = vd.type.size(vd.loc); 593 if (sz64 == SIZE_INVALID) 594 { 595 .error(vd.loc, "%s `%s` size overflow", vd.kind, vd.toPrettyChars); 596 return; 597 } 598 if (sz64 > target.maxStaticDataSize) 599 { 600 .error(vd.loc, "%s `%s` size of 0x%llx exceeds max allowed size 0x%llx", vd.kind, vd.toPrettyChars, sz64, target.maxStaticDataSize); 601 } 602 uint sz = cast(uint)sz64; 603 604 Dsymbol parent = vd.toParent(); 605 s.Sclass = SC.global; 606 607 /* Make C static functions SCstatic 608 */ 609 if (vd.storage_class & STC.static_ && vd.isCsymbol()) 610 s.Sclass = SC.static_; 611 612 do 613 { 614 /* Global template data members need to be in comdat's 615 * in case multiple .obj files instantiate the same 616 * template with the same types. 617 */ 618 if (parent.isTemplateInstance() && !parent.isTemplateMixin()) 619 { 620 s.Sclass = SC.comdat; 621 break; 622 } 623 parent = parent.parent; 624 } while (parent); 625 s.Sfl = FLdata; 626 627 // Size 0 should only be possible for T[0] and noreturn 628 if (!sz) 629 { 630 const ty = vd.type.toBasetype().ty; 631 if (ty != Tsarray && ty != Tnoreturn && !vd.isCsymbol()) 632 assert(0); // this shouldn't be possible 633 } 634 635 auto dtb = DtBuilder(0); 636 if (config.objfmt == OBJ_MACH && target.isX86_64 && (s.Stype.Tty & mTYLINK) == mTYthread) 637 { 638 tlsToDt(vd, s, sz, dtb, isCfile); 639 } 640 else if (!sz) 641 { 642 /* Give it a byte of data 643 * so we can take the 'address' of this symbol 644 * and avoid problematic behavior of object file format 645 * Note that gcc will give 0 size C objects a `comm a:byte:00h` 646 */ 647 dtb.nzeros(1); 648 } 649 else if (vd._init) 650 { 651 initializerToDt(vd, dtb, vd.isCsymbol()); 652 } 653 else 654 { 655 Type_toDt(vd.type, dtb, vd.isCsymbol()); 656 } 657 s.Sdt = dtb.finish(); 658 659 // See if we can convert a comdat to a comdef, 660 // which saves on exe file space. 661 if (s.Sclass == SC.comdat && 662 s.Sdt && 663 dtallzeros(s.Sdt) && 664 !vd.isThreadlocal()) 665 { 666 s.Sclass = SC.global; 667 dt2common(&s.Sdt); 668 } 669 670 if (s.Sclass == SC.global && s.Stype.Tty & mTYconst) 671 out_readonly(s); 672 673 outdata(s); 674 if (vd.type.isMutable() || !vd._init) 675 write_pointers(vd.type, s, 0); 676 if (vd.isExport()) 677 objmod.export_symbol(s, 0); 678 } 679 680 override void visit(EnumDeclaration ed) 681 { 682 if (ed.semanticRun >= PASS.obj) // already written 683 return; 684 //printf("EnumDeclaration.toObjFile('%s')\n", ed.toChars()); 685 686 if (ed.errors || ed.type.ty == Terror) 687 { 688 .error(ed.loc, "%s `%s` had semantic errors when compiling", ed.kind, ed.toPrettyChars); 689 return; 690 } 691 692 if (ed.isAnonymous()) 693 return; 694 695 if (driverParams.symdebugref) 696 Type_toCtype(ed.type); // calls toDebug() only once 697 else if (driverParams.symdebug) 698 toDebug(ed); 699 700 if (global.params.useTypeInfo && Type.dtypeinfo) 701 TypeInfo_toObjFile(null, ed.loc, ed.type); 702 703 TypeEnum tc = cast(TypeEnum)ed.type; 704 if (!tc.sym.members || ed.type.isZeroInit(Loc.initial)) 705 { 706 } 707 else 708 { 709 SC scclass = SC.global; 710 if (ed.isInstantiated()) 711 scclass = SC.comdat; 712 713 // Generate static initializer 714 toInitializer(ed); 715 ed.sinit.Sclass = scclass; 716 ed.sinit.Sfl = FLdata; 717 auto dtb = DtBuilder(0); 718 Expression_toDt(tc.sym.defaultval, dtb); 719 ed.sinit.Sdt = dtb.finish(); 720 outdata(ed.sinit); 721 } 722 ed.semanticRun = PASS.obj; 723 } 724 725 override void visit(TypeInfoDeclaration tid) 726 { 727 if (isSpeculativeType(tid.tinfo)) 728 { 729 //printf("-speculative '%s'\n", tid.toPrettyChars()); 730 return; 731 } 732 //printf("TypeInfoDeclaration.toObjFile(%p '%s') visibility %d\n", tid, tid.toChars(), tid.visibility); 733 734 if (multiobj) 735 { 736 obj_append(tid); 737 return; 738 } 739 740 Symbol *s = toSymbol(tid); 741 s.Sclass = SC.comdat; 742 s.Sfl = FLdata; 743 744 auto dtb = DtBuilder(0); 745 TypeInfo_toDt(dtb, tid); 746 s.Sdt = dtb.finish(); 747 748 // See if we can convert a comdat to a comdef, 749 // which saves on exe file space. 750 if (s.Sclass == SC.comdat && 751 dtallzeros(s.Sdt)) 752 { 753 s.Sclass = SC.global; 754 dt2common(&s.Sdt); 755 } 756 757 outdata(s); 758 if (tid.isExport()) 759 objmod.export_symbol(s, 0); 760 } 761 762 override void visit(AttribDeclaration ad) 763 { 764 Dsymbols *d = ad.include(null); 765 766 if (d) 767 { 768 for (size_t i = 0; i < d.length; i++) 769 { 770 Dsymbol s = (*d)[i]; 771 s.accept(this); 772 } 773 } 774 } 775 776 override void visit(PragmaDeclaration pd) 777 { 778 if (pd.ident == Id.lib) 779 { 780 assert(pd.args && pd.args.length == 1); 781 782 Expression e = (*pd.args)[0]; 783 784 assert(e.op == EXP.string_); 785 786 StringExp se = cast(StringExp)e; 787 char *name = cast(char *)mem.xmalloc(se.numberOfCodeUnits() + 1); 788 se.writeTo(name, true); 789 790 /* Embed the library names into the object file. 791 * The linker will then automatically 792 * search that library, too. 793 */ 794 if (!obj_includelib(name[0 .. strlen(name)])) 795 { 796 /* The format does not allow embedded library names, 797 * so instead append the library name to the list to be passed 798 * to the linker. 799 */ 800 global.params.libfiles.push(name); 801 } 802 } 803 else if (pd.ident == Id.startaddress) 804 { 805 assert(pd.args && pd.args.length == 1); 806 Expression e = (*pd.args)[0]; 807 Dsymbol sa = getDsymbol(e); 808 FuncDeclaration f = sa.isFuncDeclaration(); 809 assert(f); 810 Symbol *s = toSymbol(f); 811 obj_startaddress(s); 812 } 813 else if (pd.ident == Id.linkerDirective) 814 { 815 assert(pd.args && pd.args.length == 1); 816 817 Expression e = (*pd.args)[0]; 818 819 assert(e.op == EXP.string_); 820 821 StringExp se = cast(StringExp)e; 822 char *directive = cast(char *)mem.xmalloc(se.numberOfCodeUnits() + 1); 823 se.writeTo(directive, true); 824 825 obj_linkerdirective(directive); 826 } 827 828 visit(cast(AttribDeclaration)pd); 829 } 830 831 override void visit(TemplateInstance ti) 832 { 833 //printf("TemplateInstance.toObjFile(%p, '%s')\n", ti, ti.toChars()); 834 if (!isError(ti) && ti.members) 835 { 836 if (!ti.needsCodegen()) 837 { 838 //printf("-speculative (%p, %s)\n", ti, ti.toPrettyChars()); 839 return; 840 } 841 //printf("TemplateInstance.toObjFile(%p, '%s')\n", ti, ti.toPrettyChars()); 842 843 if (multiobj) 844 { 845 // Append to list of object files to be written later 846 obj_append(ti); 847 } 848 else 849 { 850 ti.members.foreachDsymbol( (s) { s.accept(this); } ); 851 } 852 } 853 } 854 855 override void visit(TemplateMixin tm) 856 { 857 //printf("TemplateMixin.toObjFile('%s')\n", tm.toChars()); 858 if (!isError(tm)) 859 { 860 tm.members.foreachDsymbol( (s) { s.accept(this); } ); 861 } 862 } 863 864 override void visit(StaticAssert sa) 865 { 866 } 867 868 override void visit(Nspace ns) 869 { 870 //printf("Nspace.toObjFile('%s', this = %p)\n", ns.toChars(), ns); 871 if (!isError(ns) && ns.members) 872 { 873 if (multiobj) 874 { 875 // Append to list of object files to be written later 876 obj_append(ns); 877 } 878 else 879 { 880 ns.members.foreachDsymbol( (s) { s.accept(this); } ); 881 } 882 } 883 } 884 885 override void visit(TupleDeclaration tup) 886 { 887 tup.foreachVar((s) { s.accept(this); }); 888 } 889 890 private: 891 static void initializerToDt(VarDeclaration vd, ref DtBuilder dtb, bool isCfile) 892 { 893 Initializer_toDt(vd._init, dtb, isCfile); 894 895 // Look for static array that is block initialized 896 ExpInitializer ie = vd._init.isExpInitializer(); 897 898 Type tb = vd.type.toBasetype(); 899 if (tb.ty == Tsarray && ie && 900 !tb.nextOf().equals(ie.exp.type.toBasetype().nextOf()) && 901 ie.exp.implicitConvTo(tb.nextOf()) 902 ) 903 { 904 auto dim = (cast(TypeSArray)tb).dim.toInteger(); 905 906 // Duplicate Sdt 'dim-1' times, as we already have the first one 907 while (--dim > 0) 908 { 909 Expression_toDt(ie.exp, dtb); 910 } 911 } 912 } 913 914 /** 915 * Output a TLS symbol for Mach-O. 916 * 917 * A TLS variable in the Mach-O format consists of two symbols. 918 * One symbol for the data, which contains the initializer, if any. 919 * The name of this symbol is the same as the variable, but with the 920 * "$tlv$init" suffix. If the variable has an initializer it's placed in 921 * the __thread_data section. Otherwise it's placed in the __thread_bss 922 * section. 923 * 924 * The other symbol is for the TLV descriptor. The symbol has the same 925 * name as the variable and is placed in the __thread_vars section. 926 * A TLV descriptor has the following structure, where T is the type of 927 * the variable: 928 * 929 * struct TLVDescriptor(T) 930 * { 931 * extern(C) T* function(TLVDescriptor*) thunk; 932 * size_t key; 933 * size_t offset; 934 * } 935 * 936 * Params: 937 * vd = the variable declaration for the symbol 938 * s = the backend Symbol corresponsing to vd 939 * sz = data size of s 940 * dtb = where to put the data 941 */ 942 static void tlsToDt(VarDeclaration vd, Symbol *s, uint sz, ref DtBuilder dtb, bool isCfile) 943 { 944 assert(config.objfmt == OBJ_MACH && target.isX86_64 && (s.Stype.Tty & mTYLINK) == mTYthread); 945 946 Symbol *tlvInit = createTLVDataSymbol(vd, s); 947 auto tlvInitDtb = DtBuilder(0); 948 949 if (sz == 0) 950 tlvInitDtb.nzeros(1); 951 else if (vd._init) 952 initializerToDt(vd, tlvInitDtb, isCfile); 953 else 954 Type_toDt(vd.type, tlvInitDtb); 955 956 tlvInit.Sdt = tlvInitDtb.finish(); 957 outdata(tlvInit); 958 959 if (target.isX86_64) 960 tlvInit.Sclass = SC.extern_; 961 962 Symbol* tlvBootstrap = objmod.tlv_bootstrap(); 963 dtb.xoff(tlvBootstrap, 0, TYnptr); 964 dtb.size(0); 965 dtb.xoff(tlvInit, 0, TYnptr); 966 } 967 968 /** 969 * Creates the data symbol used to initialize a TLS variable for Mach-O. 970 * 971 * Params: 972 * vd = the variable declaration for the symbol 973 * s = the back end symbol corresponding to vd 974 * 975 * Returns: the newly created symbol 976 */ 977 static Symbol *createTLVDataSymbol(VarDeclaration vd, Symbol *s) 978 { 979 assert(config.objfmt == OBJ_MACH && target.isX86_64 && (s.Stype.Tty & mTYLINK) == mTYthread); 980 981 // Compute identifier for tlv symbol 982 OutBuffer buffer; 983 buffer.writestring(s.Sident.ptr); 984 buffer.writestring("$tlv$init"); 985 const(char)[] tlvInitName = buffer[]; 986 987 // Compute type for tlv symbol 988 type *t = type_fake(vd.type.ty); 989 type_setty(&t, t.Tty | mTYthreadData); 990 type_setmangle(&t, mangle(vd)); 991 992 Symbol *tlvInit = symbol_name(tlvInitName, SC.static_, t); 993 tlvInit.Sdt = null; 994 tlvInit.Salignment = type_alignsize(s.Stype); 995 if (vd._linkage == LINK.cpp) 996 tlvInit.Sflags |= SFLpublic; 997 998 return tlvInit; 999 } 1000 1001 /** 1002 * Returns the target mangling mangle_t for the given variable. 1003 * 1004 * Params: 1005 * vd = the variable declaration 1006 * 1007 * Returns: 1008 * the mangling that should be used for variable 1009 */ 1010 static mangle_t mangle(const VarDeclaration vd) 1011 { 1012 final switch (vd.resolvedLinkage()) 1013 { 1014 case LINK.windows: 1015 return target.isX86_64 ? mTYman_c : mTYman_std; 1016 1017 case LINK.objc: 1018 case LINK.c: 1019 return mTYman_c; 1020 1021 case LINK.d: 1022 return mTYman_d; 1023 1024 case LINK.cpp: 1025 return mTYman_cpp; 1026 1027 case LINK.default_: 1028 case LINK.system: 1029 printf("linkage = %d\n", vd._linkage); 1030 assert(0); 1031 } 1032 } 1033 } 1034 1035 scope v = new ToObjFile(multiobj); 1036 ds.accept(v); 1037 } 1038 1039 1040 /********************************* 1041 * Finish semantic analysis of functions in vtbl[]. 1042 * Params: 1043 * cd = class which has the vtbl[] 1044 * Returns: 1045 * true for success (no errors) 1046 */ 1047 private bool finishVtbl(ClassDeclaration cd) 1048 { 1049 bool hasError = false; 1050 1051 foreach (i; cd.vtblOffset() .. cd.vtbl.length) 1052 { 1053 FuncDeclaration fd = cd.vtbl[i].isFuncDeclaration(); 1054 1055 //printf("\tvtbl[%d] = %p\n", i, fd); 1056 if (!fd || !fd.fbody && cd.isAbstract()) 1057 { 1058 // Nothing to do 1059 continue; 1060 } 1061 // Ensure function has a return value 1062 // https://issues.dlang.org/show_bug.cgi?id=4869 1063 if (!fd.functionSemantic()) 1064 { 1065 hasError = true; 1066 } 1067 1068 if (!cd.isFuncHidden(fd) || fd.isFuture()) 1069 { 1070 // All good, no name hiding to check for 1071 continue; 1072 } 1073 1074 /* fd is hidden from the view of this class. 1075 * If fd overlaps with any function in the vtbl[], then 1076 * issue 'hidden' error. 1077 */ 1078 foreach (j; 1 .. cd.vtbl.length) 1079 { 1080 if (j == i) 1081 continue; 1082 FuncDeclaration fd2 = cd.vtbl[j].isFuncDeclaration(); 1083 if (!fd2.ident.equals(fd.ident)) 1084 continue; 1085 if (fd2.isFuture()) 1086 continue; 1087 if (!fd.leastAsSpecialized(fd2, null) && !fd2.leastAsSpecialized(fd, null)) 1088 continue; 1089 // Hiding detected: same name, overlapping specializations 1090 TypeFunction tf = fd.type.toTypeFunction(); 1091 .error(cd.loc, "%s `%s` use of `%s%s` is hidden by `%s`; use `alias %s = %s.%s;` to introduce base class overload set", cd.kind, cd.toPrettyChars, 1092 fd.toPrettyChars(), 1093 parametersTypeToChars(tf.parameterList), 1094 cd.toChars(), 1095 fd.toChars(), 1096 fd.parent.toChars(), 1097 fd.toChars()); 1098 hasError = true; 1099 break; 1100 } 1101 } 1102 1103 return !hasError; 1104 } 1105 1106 1107 /****************************************** 1108 * Get offset of base class's vtbl[] initializer from start of csym. 1109 * Returns ~0 if not this csym. 1110 */ 1111 1112 uint baseVtblOffset(ClassDeclaration cd, BaseClass *bc) 1113 { 1114 //printf("ClassDeclaration.baseVtblOffset('%s', bc = %p)\n", cd.toChars(), bc); 1115 uint csymoffset = target.classinfosize; // must be ClassInfo.size 1116 csymoffset += cd.vtblInterfaces.length * (4 * target.ptrsize); 1117 1118 for (size_t i = 0; i < cd.vtblInterfaces.length; i++) 1119 { 1120 BaseClass *b = (*cd.vtblInterfaces)[i]; 1121 1122 if (b == bc) 1123 return csymoffset; 1124 csymoffset += b.sym.vtbl.length * target.ptrsize; 1125 } 1126 1127 // Put out the overriding interface vtbl[]s. 1128 // This must be mirrored with ClassDeclaration.baseVtblOffset() 1129 //printf("putting out overriding interface vtbl[]s for '%s' at offset x%x\n", toChars(), offset); 1130 ClassDeclaration cd2; 1131 1132 for (cd2 = cd.baseClass; cd2; cd2 = cd2.baseClass) 1133 { 1134 foreach (k; 0 .. cd2.vtblInterfaces.length) 1135 { 1136 BaseClass *bs = (*cd2.vtblInterfaces)[k]; 1137 if (bs.fillVtbl(cd, null, 0)) 1138 { 1139 if (bc == bs) 1140 { 1141 //printf("\tcsymoffset = x%x\n", csymoffset); 1142 return csymoffset; 1143 } 1144 csymoffset += bs.sym.vtbl.length * target.ptrsize; 1145 } 1146 } 1147 } 1148 1149 return ~0; 1150 } 1151 1152 /******************* 1153 * Emit the vtbl[] to static data 1154 * Params: 1155 * dtb = static data builder 1156 * b = base class 1157 * bvtbl = array of functions to put in this vtbl[] 1158 * pc = classid for this vtbl[] 1159 * k = offset from pc to classinfo 1160 * Returns: 1161 * number of bytes emitted 1162 */ 1163 private size_t emitVtbl(ref DtBuilder dtb, BaseClass *b, ref FuncDeclarations bvtbl, ClassDeclaration pc, size_t k) 1164 { 1165 //printf("\toverriding vtbl[] for %s\n", b.sym.toChars()); 1166 ClassDeclaration id = b.sym; 1167 1168 const id_vtbl_dim = id.vtbl.length; 1169 assert(id_vtbl_dim <= bvtbl.length); 1170 1171 size_t jstart = 0; 1172 if (id.vtblOffset()) 1173 { 1174 // First entry is struct Interface reference 1175 dtb.xoff(toSymbol(pc), cast(uint)(target.classinfosize + k * (4 * target.ptrsize)), TYnptr); 1176 jstart = 1; 1177 } 1178 1179 foreach (j; jstart .. id_vtbl_dim) 1180 { 1181 FuncDeclaration fd = bvtbl[j]; 1182 if (fd) 1183 { 1184 auto offset2 = b.offset; 1185 if (fd.interfaceVirtual) 1186 { 1187 offset2 -= fd.interfaceVirtual.offset; 1188 } 1189 dtb.xoff(toThunkSymbol(fd, offset2), 0, TYnptr); 1190 } 1191 else 1192 dtb.size(0); 1193 } 1194 return id_vtbl_dim * target.ptrsize; 1195 } 1196 1197 1198 /****************************************************** 1199 * Generate the ClassInfo for a Class (__classZ) symbol. 1200 * Write it to the object file. 1201 * Similar to genClassInfoForInterface(). 1202 * Params: 1203 * cd = the class 1204 * sinit = the Initializer (__initZ) symbol for the class 1205 */ 1206 private void genClassInfoForClass(ClassDeclaration cd, Symbol* sinit) 1207 { 1208 // Put out the ClassInfo, which will be the __ClassZ symbol in the object file 1209 SC scclass = SC.comdat; 1210 cd.csym.Sclass = scclass; 1211 cd.csym.Sfl = FLdata; 1212 1213 /* The layout is: 1214 { 1215 void **vptr; 1216 monitor_t monitor; 1217 byte[] m_init; // static initialization data 1218 string name; // class name 1219 void*[] vtbl; 1220 Interface[] interfaces; 1221 ClassInfo base; // base class 1222 void* destructor; 1223 void function(Object) classInvariant; // class invariant 1224 ClassFlags m_flags; 1225 void* deallocator; 1226 OffsetTypeInfo[] offTi; 1227 void function(Object) defaultConstructor; 1228 //const(MemberInfo[]) function(string) xgetMembers; // module getMembers() function 1229 immutable(void)* m_RTInfo; 1230 //TypeInfo typeinfo; 1231 } 1232 */ 1233 uint offset = target.classinfosize; // must be ClassInfo.size 1234 if (Type.typeinfoclass) 1235 { 1236 if (Type.typeinfoclass.structsize != target.classinfosize) 1237 { 1238 debug printf("target.classinfosize = x%x, Type.typeinfoclass.structsize = x%x\n", offset, Type.typeinfoclass.structsize); 1239 .error(cd.loc, "%s `%s` mismatch between dmd and object.d or object.di found. Check installation and import paths with -v compiler switch.", cd.kind, cd.toPrettyChars); 1240 fatal(); 1241 } 1242 } 1243 1244 auto dtb = DtBuilder(0); 1245 1246 if (auto tic = Type.typeinfoclass) 1247 { 1248 dtb.xoff(toVtblSymbol(tic), 0, TYnptr); // vtbl for TypeInfo_Class : ClassInfo 1249 if (tic.hasMonitor()) 1250 dtb.size(0); // monitor 1251 } 1252 else 1253 { 1254 dtb.size(0); // BUG: should be an assert() 1255 dtb.size(0); // call hasMonitor()? 1256 } 1257 1258 // m_init[] 1259 assert(cd.structsize >= 8 || (cd.classKind == ClassKind.cpp && cd.structsize >= 4)); 1260 dtb.size(cd.structsize); // size 1261 dtb.xoff(sinit, 0, TYnptr); // initializer 1262 1263 // name[] 1264 const(char) *name = cd.ident.toChars(); 1265 size_t namelen = strlen(name); 1266 if (!(namelen > 9 && memcmp(name, "TypeInfo_".ptr, 9) == 0)) 1267 { 1268 name = cd.toPrettyChars(/*QualifyTypes=*/ true); 1269 namelen = strlen(name); 1270 } 1271 dtb.size(namelen); 1272 dt_t *pdtname = dtb.xoffpatch(cd.csym, 0, TYnptr); 1273 1274 // vtbl[] 1275 dtb.size(cd.vtbl.length); 1276 if (cd.vtbl.length) 1277 dtb.xoff(cd.vtblsym.csym, 0, TYnptr); 1278 else 1279 dtb.size(0); 1280 1281 // interfaces[] 1282 dtb.size(cd.vtblInterfaces.length); 1283 if (cd.vtblInterfaces.length) 1284 dtb.xoff(cd.csym, offset, TYnptr); // (*) 1285 else 1286 dtb.size(0); 1287 1288 // base 1289 if (cd.baseClass) 1290 dtb.xoff(toSymbol(cd.baseClass), 0, TYnptr); 1291 else 1292 dtb.size(0); 1293 1294 // destructor 1295 if (cd.tidtor) 1296 dtb.xoff(toSymbol(cd.tidtor), 0, TYnptr); 1297 else 1298 dtb.size(0); 1299 1300 // classInvariant 1301 if (cd.inv) 1302 dtb.xoff(toSymbol(cd.inv), 0, TYnptr); 1303 else 1304 dtb.size(0); 1305 1306 // flags 1307 ClassFlags flags = ClassFlags.hasOffTi; 1308 if (cd.isCOMclass()) flags |= ClassFlags.isCOMclass; 1309 if (cd.isCPPclass()) flags |= ClassFlags.isCPPclass; 1310 flags |= ClassFlags.hasGetMembers; 1311 flags |= ClassFlags.hasTypeInfo; 1312 if (cd.ctor) 1313 flags |= ClassFlags.hasCtor; 1314 for (ClassDeclaration pc = cd; pc; pc = pc.baseClass) 1315 { 1316 if (pc.dtor) 1317 { 1318 flags |= ClassFlags.hasDtor; 1319 break; 1320 } 1321 } 1322 if (cd.isAbstract()) 1323 flags |= ClassFlags.isAbstract; 1324 1325 flags |= ClassFlags.noPointers; // initially assume no pointers 1326 Louter: 1327 for (ClassDeclaration pc = cd; pc; pc = pc.baseClass) 1328 { 1329 if (pc.members) 1330 { 1331 for (size_t i = 0; i < pc.members.length; i++) 1332 { 1333 Dsymbol sm = (*pc.members)[i]; 1334 //printf("sm = %s %s\n", sm.kind(), sm.toChars()); 1335 if (sm.hasPointers()) 1336 { 1337 flags &= ~ClassFlags.noPointers; // not no-how, not no-way 1338 break Louter; 1339 } 1340 } 1341 } 1342 } 1343 dtb.size(flags); 1344 1345 // deallocator 1346 dtb.size(0); 1347 1348 // offTi[] 1349 dtb.size(0); 1350 dtb.size(0); // null for now, fix later 1351 1352 // defaultConstructor 1353 if (cd.defaultCtor && !(cd.defaultCtor.storage_class & STC.disable)) 1354 dtb.xoff(toSymbol(cd.defaultCtor), 0, TYnptr); 1355 else 1356 dtb.size(0); 1357 1358 // m_RTInfo 1359 if (cd.getRTInfo) 1360 Expression_toDt(cd.getRTInfo, dtb); 1361 else if (flags & ClassFlags.noPointers) 1362 dtb.size(0); 1363 else 1364 dtb.size(1); 1365 1366 //dtb.xoff(toSymbol(cd.type.vtinfo), 0, TYnptr); // typeinfo 1367 1368 ////////////////////////////////////////////// 1369 1370 // Put out (*vtblInterfaces)[]. Must immediately follow csym, because 1371 // of the fixup (*) 1372 1373 offset += cd.vtblInterfaces.length * (4 * target.ptrsize); 1374 for (size_t i = 0; i < cd.vtblInterfaces.length; i++) 1375 { 1376 BaseClass *b = (*cd.vtblInterfaces)[i]; 1377 ClassDeclaration id = b.sym; 1378 1379 /* The layout is: 1380 * struct Interface 1381 * { 1382 * ClassInfo classinfo; 1383 * void*[] vtbl; 1384 * size_t offset; 1385 * } 1386 */ 1387 1388 // Fill in vtbl[] 1389 b.fillVtbl(cd, &b.vtbl, 1); 1390 1391 // classinfo 1392 dtb.xoff(toSymbol(id), 0, TYnptr); 1393 1394 // vtbl[] 1395 dtb.size(id.vtbl.length); 1396 dtb.xoff(cd.csym, offset, TYnptr); 1397 1398 // offset 1399 dtb.size(b.offset); 1400 } 1401 1402 // Put out the (*vtblInterfaces)[].vtbl[] 1403 // This must be mirrored with ClassDeclaration.baseVtblOffset() 1404 //printf("putting out %d interface vtbl[]s for '%s'\n", vtblInterfaces.length, toChars()); 1405 foreach (i; 0 .. cd.vtblInterfaces.length) 1406 { 1407 BaseClass *b = (*cd.vtblInterfaces)[i]; 1408 offset += emitVtbl(dtb, b, b.vtbl, cd, i); 1409 } 1410 1411 // Put out the overriding interface vtbl[]s. 1412 // This must be mirrored with ClassDeclaration.baseVtblOffset() 1413 //printf("putting out overriding interface vtbl[]s for '%s' at offset x%x\n", toChars(), offset); 1414 for (ClassDeclaration pc = cd.baseClass; pc; pc = pc.baseClass) 1415 { 1416 foreach (i; 0 .. pc.vtblInterfaces.length) 1417 { 1418 BaseClass *b = (*pc.vtblInterfaces)[i]; 1419 FuncDeclarations bvtbl; 1420 if (b.fillVtbl(cd, &bvtbl, 0)) 1421 { 1422 offset += emitVtbl(dtb, b, bvtbl, pc, i); 1423 } 1424 } 1425 } 1426 1427 ////////////////////////////////////////////// 1428 1429 dtpatchoffset(pdtname, offset); 1430 1431 dtb.nbytes(cast(uint)(namelen + 1), name); 1432 const size_t namepad = -(namelen + 1) & (target.ptrsize - 1); // align 1433 dtb.nzeros(cast(uint)namepad); 1434 1435 cd.csym.Sdt = dtb.finish(); 1436 // ClassInfo cannot be const data, because we use the monitor on it 1437 outdata(cd.csym); 1438 if (cd.isExport()) 1439 objmod.export_symbol(cd.csym, 0); 1440 } 1441 1442 /****************************************************** 1443 * Generate the ClassInfo for an Interface (classZ symbol). 1444 * Write it to the object file. 1445 * Params: 1446 * id = the interface 1447 */ 1448 private void genClassInfoForInterface(InterfaceDeclaration id) 1449 { 1450 SC scclass = SC.comdat; 1451 1452 // Put out the ClassInfo 1453 id.csym.Sclass = scclass; 1454 id.csym.Sfl = FLdata; 1455 1456 /* The layout is: 1457 { 1458 void **vptr; 1459 monitor_t monitor; 1460 byte[] m_init; // static initialization data 1461 string name; // class name 1462 void*[] vtbl; 1463 Interface[] interfaces; 1464 ClassInfo base; // base class 1465 void* destructor; 1466 void function(Object) classInvariant; // class invariant 1467 ClassFlags m_flags; 1468 void* deallocator; 1469 OffsetTypeInfo[] offTi; 1470 void function(Object) defaultConstructor; 1471 //const(MemberInfo[]) function(string) xgetMembers; // module getMembers() function 1472 immutable(void)* m_RTInfo; 1473 //TypeInfo typeinfo; 1474 } 1475 */ 1476 auto dtb = DtBuilder(0); 1477 1478 if (auto tic = Type.typeinfoclass) 1479 { 1480 dtb.xoff(toVtblSymbol(tic), 0, TYnptr); // vtbl for ClassInfo 1481 if (tic.hasMonitor()) 1482 dtb.size(0); // monitor 1483 } 1484 else 1485 { 1486 dtb.size(0); // BUG: should be an assert() 1487 dtb.size(0); // call hasMonitor()? 1488 } 1489 1490 // m_init[] 1491 dtb.size(0); // size 1492 dtb.size(0); // initializer 1493 1494 // name[] 1495 const(char) *name = id.toPrettyChars(/*QualifyTypes=*/ true); 1496 size_t namelen = strlen(name); 1497 dtb.size(namelen); 1498 dt_t *pdtname = dtb.xoffpatch(id.csym, 0, TYnptr); 1499 1500 // vtbl[] 1501 dtb.size(0); 1502 dtb.size(0); 1503 1504 // interfaces[] 1505 uint offset = target.classinfosize; 1506 dtb.size(id.vtblInterfaces.length); 1507 if (id.vtblInterfaces.length) 1508 { 1509 if (Type.typeinfoclass) 1510 { 1511 if (Type.typeinfoclass.structsize != offset) 1512 { 1513 .error(id.loc, "%s `%s` mismatch between dmd and object.d or object.di found. Check installation and import paths with -v compiler switch.", id.kind, id.toPrettyChars); 1514 fatal(); 1515 } 1516 } 1517 dtb.xoff(id.csym, offset, TYnptr); // (*) 1518 } 1519 else 1520 { 1521 dtb.size(0); 1522 } 1523 1524 // base 1525 assert(!id.baseClass); 1526 dtb.size(0); 1527 1528 // destructor 1529 dtb.size(0); 1530 1531 // classInvariant 1532 dtb.size(0); 1533 1534 // flags 1535 ClassFlags flags = ClassFlags.hasOffTi | ClassFlags.hasTypeInfo; 1536 if (id.isCOMinterface()) flags |= ClassFlags.isCOMclass; 1537 dtb.size(flags); 1538 1539 // deallocator 1540 dtb.size(0); 1541 1542 // offTi[] 1543 dtb.size(0); 1544 dtb.size(0); // null for now, fix later 1545 1546 // defaultConstructor 1547 dtb.size(0); 1548 1549 // xgetMembers 1550 //dtb.size(0); 1551 1552 // m_RTInfo 1553 if (id.getRTInfo) 1554 Expression_toDt(id.getRTInfo, dtb); 1555 else 1556 dtb.size(0); // no pointers 1557 1558 //dtb.xoff(toSymbol(id.type.vtinfo), 0, TYnptr); // typeinfo 1559 1560 ////////////////////////////////////////////// 1561 1562 // Put out (*vtblInterfaces)[]. Must immediately follow csym, because 1563 // of the fixup (*) 1564 1565 offset += id.vtblInterfaces.length * (4 * target.ptrsize); 1566 for (size_t i = 0; i < id.vtblInterfaces.length; i++) 1567 { 1568 BaseClass *b = (*id.vtblInterfaces)[i]; 1569 ClassDeclaration base = b.sym; 1570 1571 // classinfo 1572 dtb.xoff(toSymbol(base), 0, TYnptr); 1573 1574 // vtbl[] 1575 dtb.size(0); 1576 dtb.size(0); 1577 1578 // offset 1579 dtb.size(b.offset); 1580 } 1581 1582 ////////////////////////////////////////////// 1583 1584 dtpatchoffset(pdtname, offset); 1585 1586 dtb.nbytes(cast(uint)(namelen + 1), name); 1587 const size_t namepad = -(namelen + 1) & (target.ptrsize - 1); // align 1588 dtb.nzeros(cast(uint)namepad); 1589 1590 id.csym.Sdt = dtb.finish(); 1591 out_readonly(id.csym); 1592 outdata(id.csym); 1593 if (id.isExport()) 1594 objmod.export_symbol(id.csym, 0); 1595 }