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