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