1 /** 2 * Convert an AST that went through all semantic phases into an object file. 3 * 4 * Copyright: Copyright (C) 1999-2020 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 // Generate C symbols 453 toSymbol(id); 454 455 ////////////////////////////////////////////// 456 457 // Put out the TypeInfo 458 if (global.params.useTypeInfo && Type.dtypeinfo) 459 { 460 genTypeInfo(id.loc, id.type, null); 461 id.type.vtinfo.accept(this); 462 } 463 464 ////////////////////////////////////////////// 465 466 genClassInfoForInterface(id); 467 } 468 469 override void visit(StructDeclaration sd) 470 { 471 //printf("StructDeclaration.toObjFile('%s')\n", sd.toChars()); 472 473 if (sd.type.ty == Terror) 474 { 475 sd.error("had semantic errors when compiling"); 476 return; 477 } 478 479 if (multiobj && !sd.hasStaticCtorOrDtor()) 480 { 481 obj_append(sd); 482 return; 483 } 484 485 // Anonymous structs/unions only exist as part of others, 486 // do not output forward referenced structs's 487 if (!sd.isAnonymous() && sd.members) 488 { 489 if (global.params.symdebugref) 490 Type_toCtype(sd.type); // calls toDebug() only once 491 else if (global.params.symdebug) 492 toDebug(sd); 493 494 if (global.params.useTypeInfo && Type.dtypeinfo) 495 genTypeInfo(sd.loc, sd.type, null); 496 497 // Generate static initializer 498 auto sinit = toInitializer(sd); 499 if (sinit.Sclass == SCextern) 500 { 501 if (sinit == bzeroSymbol) assert(0); 502 sinit.Sclass = sd.isInstantiated() ? SCcomdat : SCglobal; 503 sinit.Sfl = FLdata; 504 auto dtb = DtBuilder(0); 505 StructDeclaration_toDt(sd, dtb); 506 sinit.Sdt = dtb.finish(); 507 508 /* fails to link on OBJ_MACH 64 with: 509 * ld: in generated/osx/release/64/libphobos2.a(dwarfeh_8dc_56a.o), 510 * in section __TEXT,__textcoal_nt reloc 6: 511 * symbol index out of range for architecture x86_64 512 */ 513 if (config.objfmt != OBJ_MACH && 514 dtallzeros(sinit.Sdt)) 515 { 516 sinit.Sclass = SCglobal; 517 dt2common(&sinit.Sdt); 518 } 519 else 520 out_readonly(sinit); // put in read-only segment 521 outdata(sinit); 522 } 523 524 // Put out the members 525 /* There might be static ctors in the members, and they cannot 526 * be put in separate obj files. 527 */ 528 sd.members.foreachDsymbol( (s) { s.accept(this); } ); 529 530 if (sd.xeq && sd.xeq != StructDeclaration.xerreq) 531 sd.xeq.accept(this); 532 if (sd.xcmp && sd.xcmp != StructDeclaration.xerrcmp) 533 sd.xcmp.accept(this); 534 if (sd.xhash) 535 sd.xhash.accept(this); 536 } 537 } 538 539 override void visit(VarDeclaration vd) 540 { 541 542 //printf("VarDeclaration.toObjFile(%p '%s' type=%s) protection %d\n", vd, vd.toChars(), vd.type.toChars(), vd.protection); 543 //printf("\talign = %d\n", vd.alignment); 544 545 if (vd.type.ty == Terror) 546 { 547 vd.error("had semantic errors when compiling"); 548 return; 549 } 550 551 if (vd.aliassym) 552 { 553 visitNoMultiObj(vd.toAlias()); 554 return; 555 } 556 557 // Do not store variables we cannot take the address of 558 if (!vd.canTakeAddressOf()) 559 { 560 return; 561 } 562 563 if (!vd.isDataseg() || vd.storage_class & STC.extern_) 564 return; 565 566 Symbol *s = toSymbol(vd); 567 d_uns64 sz64 = vd.type.size(vd.loc); 568 if (sz64 == SIZE_INVALID) 569 { 570 vd.error("size overflow"); 571 return; 572 } 573 if (sz64 >= target.maxStaticDataSize) 574 { 575 vd.error("size of 0x%llx exceeds max allowed size 0x%llx", sz64, target.maxStaticDataSize); 576 } 577 uint sz = cast(uint)sz64; 578 579 Dsymbol parent = vd.toParent(); 580 s.Sclass = SCglobal; 581 582 do 583 { 584 /* Global template data members need to be in comdat's 585 * in case multiple .obj files instantiate the same 586 * template with the same types. 587 */ 588 if (parent.isTemplateInstance() && !parent.isTemplateMixin()) 589 { 590 s.Sclass = SCcomdat; 591 break; 592 } 593 parent = parent.parent; 594 } while (parent); 595 s.Sfl = FLdata; 596 597 if (!sz && vd.type.toBasetype().ty != Tsarray) 598 assert(0); // this shouldn't be possible 599 600 auto dtb = DtBuilder(0); 601 if (config.objfmt == OBJ_MACH && global.params.is64bit && (s.Stype.Tty & mTYLINK) == mTYthread) 602 { 603 tlsToDt(vd, s, sz, dtb); 604 } 605 else if (!sz) 606 { 607 /* Give it a byte of data 608 * so we can take the 'address' of this symbol 609 * and avoid problematic behavior of object file format 610 */ 611 dtb.nzeros(1); 612 } 613 else if (vd._init) 614 { 615 initializerToDt(vd, dtb); 616 } 617 else 618 { 619 Type_toDt(vd.type, dtb); 620 } 621 s.Sdt = dtb.finish(); 622 623 // See if we can convert a comdat to a comdef, 624 // which saves on exe file space. 625 if (s.Sclass == SCcomdat && 626 s.Sdt && 627 dtallzeros(s.Sdt) && 628 !vd.isThreadlocal()) 629 { 630 s.Sclass = SCglobal; 631 dt2common(&s.Sdt); 632 } 633 634 outdata(s); 635 if (vd.type.isMutable() || !vd._init) 636 write_pointers(vd.type, s, 0); 637 if (vd.isExport()) 638 objmod.export_symbol(s, 0); 639 } 640 641 override void visit(EnumDeclaration ed) 642 { 643 if (ed.semanticRun >= PASS.obj) // already written 644 return; 645 //printf("EnumDeclaration.toObjFile('%s')\n", ed.toChars()); 646 647 if (ed.errors || ed.type.ty == Terror) 648 { 649 ed.error("had semantic errors when compiling"); 650 return; 651 } 652 653 if (ed.isAnonymous()) 654 return; 655 656 if (global.params.symdebugref) 657 Type_toCtype(ed.type); // calls toDebug() only once 658 else if (global.params.symdebug) 659 toDebug(ed); 660 661 if (global.params.useTypeInfo && Type.dtypeinfo) 662 genTypeInfo(ed.loc, ed.type, null); 663 664 TypeEnum tc = cast(TypeEnum)ed.type; 665 if (!tc.sym.members || ed.type.isZeroInit(Loc.initial)) 666 { 667 } 668 else 669 { 670 enum_SC scclass = SCglobal; 671 if (ed.isInstantiated()) 672 scclass = SCcomdat; 673 674 // Generate static initializer 675 toInitializer(ed); 676 ed.sinit.Sclass = scclass; 677 ed.sinit.Sfl = FLdata; 678 auto dtb = DtBuilder(0); 679 Expression_toDt(tc.sym.defaultval, dtb); 680 ed.sinit.Sdt = dtb.finish(); 681 outdata(ed.sinit); 682 } 683 ed.semanticRun = PASS.obj; 684 } 685 686 override void visit(TypeInfoDeclaration tid) 687 { 688 if (isSpeculativeType(tid.tinfo)) 689 { 690 //printf("-speculative '%s'\n", tid.toPrettyChars()); 691 return; 692 } 693 //printf("TypeInfoDeclaration.toObjFile(%p '%s') protection %d\n", tid, tid.toChars(), tid.protection); 694 695 if (multiobj) 696 { 697 obj_append(tid); 698 return; 699 } 700 701 Symbol *s = toSymbol(tid); 702 s.Sclass = SCcomdat; 703 s.Sfl = FLdata; 704 705 auto dtb = DtBuilder(0); 706 TypeInfo_toDt(dtb, tid); 707 s.Sdt = dtb.finish(); 708 709 // See if we can convert a comdat to a comdef, 710 // which saves on exe file space. 711 if (s.Sclass == SCcomdat && 712 dtallzeros(s.Sdt)) 713 { 714 s.Sclass = SCglobal; 715 dt2common(&s.Sdt); 716 } 717 718 outdata(s); 719 if (tid.isExport()) 720 objmod.export_symbol(s, 0); 721 } 722 723 override void visit(AttribDeclaration ad) 724 { 725 Dsymbols *d = ad.include(null); 726 727 if (d) 728 { 729 for (size_t i = 0; i < d.dim; i++) 730 { 731 Dsymbol s = (*d)[i]; 732 s.accept(this); 733 } 734 } 735 } 736 737 override void visit(PragmaDeclaration pd) 738 { 739 if (pd.ident == Id.lib) 740 { 741 assert(pd.args && pd.args.dim == 1); 742 743 Expression e = (*pd.args)[0]; 744 745 assert(e.op == TOK.string_); 746 747 StringExp se = cast(StringExp)e; 748 char *name = cast(char *)mem.xmalloc(se.numberOfCodeUnits() + 1); 749 se.writeTo(name, true); 750 751 /* Embed the library names into the object file. 752 * The linker will then automatically 753 * search that library, too. 754 */ 755 if (!obj_includelib(name)) 756 { 757 /* The format does not allow embedded library names, 758 * so instead append the library name to the list to be passed 759 * to the linker. 760 */ 761 global.params.libfiles.push(name); 762 } 763 } 764 else if (pd.ident == Id.startaddress) 765 { 766 assert(pd.args && pd.args.dim == 1); 767 Expression e = (*pd.args)[0]; 768 Dsymbol sa = getDsymbol(e); 769 FuncDeclaration f = sa.isFuncDeclaration(); 770 assert(f); 771 Symbol *s = toSymbol(f); 772 obj_startaddress(s); 773 } 774 else if (pd.ident == Id.linkerDirective) 775 { 776 assert(pd.args && pd.args.dim == 1); 777 778 Expression e = (*pd.args)[0]; 779 780 assert(e.op == TOK.string_); 781 782 StringExp se = cast(StringExp)e; 783 char *directive = cast(char *)mem.xmalloc(se.numberOfCodeUnits() + 1); 784 se.writeTo(directive, true); 785 786 obj_linkerdirective(directive); 787 } 788 else if (pd.ident == Id.crt_constructor || pd.ident == Id.crt_destructor) 789 { 790 immutable isCtor = pd.ident == Id.crt_constructor; 791 792 static uint recurse(Dsymbol s, bool isCtor) 793 { 794 if (auto ad = s.isAttribDeclaration()) 795 { 796 uint nestedCount; 797 auto decls = ad.include(null); 798 if (decls) 799 { 800 for (size_t i = 0; i < decls.dim; ++i) 801 nestedCount += recurse((*decls)[i], isCtor); 802 } 803 return nestedCount; 804 } 805 else if (auto f = s.isFuncDeclaration()) 806 { 807 f.isCrtCtorDtor |= isCtor ? 1 : 2; 808 if (f.linkage != LINK.c) 809 f.error("must be `extern(C)` for `pragma(%s)`", isCtor ? "crt_constructor".ptr : "crt_destructor".ptr); 810 return 1; 811 } 812 else 813 return 0; 814 assert(0); 815 } 816 817 if (recurse(pd, isCtor) > 1) 818 pd.error("can only apply to a single declaration"); 819 } 820 821 visit(cast(AttribDeclaration)pd); 822 } 823 824 override void visit(TemplateInstance ti) 825 { 826 //printf("TemplateInstance.toObjFile(%p, '%s')\n", ti, ti.toChars()); 827 if (!isError(ti) && ti.members) 828 { 829 if (!ti.needsCodegen()) 830 { 831 //printf("-speculative (%p, %s)\n", ti, ti.toPrettyChars()); 832 return; 833 } 834 //printf("TemplateInstance.toObjFile(%p, '%s')\n", ti, ti.toPrettyChars()); 835 836 if (multiobj) 837 { 838 // Append to list of object files to be written later 839 obj_append(ti); 840 } 841 else 842 { 843 ti.members.foreachDsymbol( (s) { s.accept(this); } ); 844 } 845 } 846 } 847 848 override void visit(TemplateMixin tm) 849 { 850 //printf("TemplateMixin.toObjFile('%s')\n", tm.toChars()); 851 if (!isError(tm)) 852 { 853 tm.members.foreachDsymbol( (s) { s.accept(this); } ); 854 } 855 } 856 857 override void visit(StaticAssert sa) 858 { 859 } 860 861 override void visit(Nspace ns) 862 { 863 //printf("Nspace.toObjFile('%s', this = %p)\n", ns.toChars(), ns); 864 if (!isError(ns) && ns.members) 865 { 866 if (multiobj) 867 { 868 // Append to list of object files to be written later 869 obj_append(ns); 870 } 871 else 872 { 873 ns.members.foreachDsymbol( (s) { s.accept(this); } ); 874 } 875 } 876 } 877 878 private: 879 static void initializerToDt(VarDeclaration vd, ref DtBuilder dtb) 880 { 881 Initializer_toDt(vd._init, dtb); 882 883 // Look for static array that is block initialized 884 ExpInitializer ie = vd._init.isExpInitializer(); 885 886 Type tb = vd.type.toBasetype(); 887 if (tb.ty == Tsarray && ie && 888 !tb.nextOf().equals(ie.exp.type.toBasetype().nextOf()) && 889 ie.exp.implicitConvTo(tb.nextOf()) 890 ) 891 { 892 auto dim = (cast(TypeSArray)tb).dim.toInteger(); 893 894 // Duplicate Sdt 'dim-1' times, as we already have the first one 895 while (--dim > 0) 896 { 897 Expression_toDt(ie.exp, dtb); 898 } 899 } 900 } 901 902 /** 903 * Output a TLS symbol for Mach-O. 904 * 905 * A TLS variable in the Mach-O format consists of two symbols. 906 * One symbol for the data, which contains the initializer, if any. 907 * The name of this symbol is the same as the variable, but with the 908 * "$tlv$init" suffix. If the variable has an initializer it's placed in 909 * the __thread_data section. Otherwise it's placed in the __thread_bss 910 * section. 911 * 912 * The other symbol is for the TLV descriptor. The symbol has the same 913 * name as the variable and is placed in the __thread_vars section. 914 * A TLV descriptor has the following structure, where T is the type of 915 * the variable: 916 * 917 * struct TLVDescriptor(T) 918 * { 919 * extern(C) T* function(TLVDescriptor*) thunk; 920 * size_t key; 921 * size_t offset; 922 * } 923 * 924 * Params: 925 * vd = the variable declaration for the symbol 926 * s = the backend Symbol corresponsing to vd 927 * sz = data size of s 928 * dtb = where to put the data 929 */ 930 static void tlsToDt(VarDeclaration vd, Symbol *s, uint sz, ref DtBuilder dtb) 931 { 932 assert(config.objfmt == OBJ_MACH && global.params.is64bit && (s.Stype.Tty & mTYLINK) == mTYthread); 933 934 Symbol *tlvInit = createTLVDataSymbol(vd, s); 935 auto tlvInitDtb = DtBuilder(0); 936 937 if (sz == 0) 938 tlvInitDtb.nzeros(1); 939 else if (vd._init) 940 initializerToDt(vd, tlvInitDtb); 941 else 942 Type_toDt(vd.type, tlvInitDtb); 943 944 tlvInit.Sdt = tlvInitDtb.finish(); 945 outdata(tlvInit); 946 947 if (global.params.is64bit) 948 tlvInit.Sclass = SCextern; 949 950 Symbol* tlvBootstrap = objmod.tlv_bootstrap(); 951 dtb.xoff(tlvBootstrap, 0, TYnptr); 952 dtb.size(0); 953 dtb.xoff(tlvInit, 0, TYnptr); 954 } 955 956 /** 957 * Creates the data symbol used to initialize a TLS variable for Mach-O. 958 * 959 * Params: 960 * vd = the variable declaration for the symbol 961 * s = the back end symbol corresponding to vd 962 * 963 * Returns: the newly created symbol 964 */ 965 static Symbol *createTLVDataSymbol(VarDeclaration vd, Symbol *s) 966 { 967 assert(config.objfmt == OBJ_MACH && global.params.is64bit && (s.Stype.Tty & mTYLINK) == mTYthread); 968 969 // Compute identifier for tlv symbol 970 OutBuffer buffer; 971 buffer.writestring(s.Sident); 972 buffer.writestring("$tlv$init"); 973 const(char) *tlvInitName = buffer.peekChars(); 974 975 // Compute type for tlv symbol 976 type *t = type_fake(vd.type.ty); 977 type_setty(&t, t.Tty | mTYthreadData); 978 type_setmangle(&t, mangle(vd)); 979 980 Symbol *tlvInit = symbol_name(tlvInitName, SCstatic, t); 981 tlvInit.Sdt = null; 982 tlvInit.Salignment = type_alignsize(s.Stype); 983 if (vd.linkage == LINK.cpp) 984 tlvInit.Sflags |= SFLpublic; 985 986 return tlvInit; 987 } 988 989 /** 990 * Returns the target mangling mangle_t for the given variable. 991 * 992 * Params: 993 * vd = the variable declaration 994 * 995 * Returns: 996 * the mangling that should be used for variable 997 */ 998 static mangle_t mangle(const VarDeclaration vd) 999 { 1000 final switch (vd.linkage) 1001 { 1002 case LINK.windows: 1003 return global.params.is64bit ? mTYman_c : mTYman_std; 1004 1005 case LINK.pascal: 1006 return mTYman_pas; 1007 1008 case LINK.objc: 1009 case LINK.c: 1010 return mTYman_c; 1011 1012 case LINK.d: 1013 return mTYman_d; 1014 1015 case LINK.cpp: 1016 return mTYman_cpp; 1017 1018 case LINK.default_: 1019 case LINK.system: 1020 printf("linkage = %d\n", vd.linkage); 1021 assert(0); 1022 } 1023 } 1024 } 1025 1026 scope v = new ToObjFile(multiobj); 1027 ds.accept(v); 1028 } 1029 1030 1031 /********************************* 1032 * Finish semantic analysis of functions in vtbl[]. 1033 * Params: 1034 * cd = class which has the vtbl[] 1035 * Returns: 1036 * true for success (no errors) 1037 */ 1038 private bool finishVtbl(ClassDeclaration cd) 1039 { 1040 bool hasError = false; 1041 1042 foreach (i; cd.vtblOffset() .. cd.vtbl.dim) 1043 { 1044 FuncDeclaration fd = cd.vtbl[i].isFuncDeclaration(); 1045 1046 //printf("\tvtbl[%d] = %p\n", i, fd); 1047 if (!fd || !fd.fbody && cd.isAbstract()) 1048 { 1049 // Nothing to do 1050 continue; 1051 } 1052 // Ensure function has a return value 1053 // https://issues.dlang.org/show_bug.cgi?id=4869 1054 if (!fd.functionSemantic()) 1055 { 1056 hasError = true; 1057 } 1058 1059 if (!cd.isFuncHidden(fd) || fd.isFuture()) 1060 { 1061 // All good, no name hiding to check for 1062 continue; 1063 } 1064 1065 /* fd is hidden from the view of this class. 1066 * If fd overlaps with any function in the vtbl[], then 1067 * issue 'hidden' error. 1068 */ 1069 foreach (j; 1 .. cd.vtbl.dim) 1070 { 1071 if (j == i) 1072 continue; 1073 FuncDeclaration fd2 = cd.vtbl[j].isFuncDeclaration(); 1074 if (!fd2.ident.equals(fd.ident)) 1075 continue; 1076 if (fd2.isFuture()) 1077 continue; 1078 if (!fd.leastAsSpecialized(fd2) && !fd2.leastAsSpecialized(fd)) 1079 continue; 1080 // Hiding detected: same name, overlapping specializations 1081 TypeFunction tf = cast(TypeFunction)fd.type; 1082 if (tf.ty == Tfunction) 1083 { 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 } 1092 else 1093 { 1094 cd.error("use of `%s` is hidden by `%s`", fd.toPrettyChars(), cd.toChars()); 1095 } 1096 hasError = true; 1097 break; 1098 } 1099 } 1100 1101 return !hasError; 1102 } 1103 1104 1105 /****************************************** 1106 * Get offset of base class's vtbl[] initializer from start of csym. 1107 * Returns ~0 if not this csym. 1108 */ 1109 1110 uint baseVtblOffset(ClassDeclaration cd, BaseClass *bc) 1111 { 1112 //printf("ClassDeclaration.baseVtblOffset('%s', bc = %p)\n", cd.toChars(), bc); 1113 uint csymoffset = target.classinfosize; // must be ClassInfo.size 1114 csymoffset += cd.vtblInterfaces.dim * (4 * target.ptrsize); 1115 1116 for (size_t i = 0; i < cd.vtblInterfaces.dim; i++) 1117 { 1118 BaseClass *b = (*cd.vtblInterfaces)[i]; 1119 1120 if (b == bc) 1121 return csymoffset; 1122 csymoffset += b.sym.vtbl.dim * target.ptrsize; 1123 } 1124 1125 // Put out the overriding interface vtbl[]s. 1126 // This must be mirrored with ClassDeclaration.baseVtblOffset() 1127 //printf("putting out overriding interface vtbl[]s for '%s' at offset x%x\n", toChars(), offset); 1128 ClassDeclaration cd2; 1129 1130 for (cd2 = cd.baseClass; cd2; cd2 = cd2.baseClass) 1131 { 1132 foreach (k; 0 .. cd2.vtblInterfaces.dim) 1133 { 1134 BaseClass *bs = (*cd2.vtblInterfaces)[k]; 1135 if (bs.fillVtbl(cd, null, 0)) 1136 { 1137 if (bc == bs) 1138 { 1139 //printf("\tcsymoffset = x%x\n", csymoffset); 1140 return csymoffset; 1141 } 1142 csymoffset += bs.sym.vtbl.dim * target.ptrsize; 1143 } 1144 } 1145 } 1146 1147 return ~0; 1148 } 1149 1150 /******************* 1151 * Emit the vtbl[] to static data 1152 * Params: 1153 * dtb = static data builder 1154 * b = base class 1155 * bvtbl = array of functions to put in this vtbl[] 1156 * pc = classid for this vtbl[] 1157 * k = offset from pc to classinfo 1158 * Returns: 1159 * number of bytes emitted 1160 */ 1161 private size_t emitVtbl(ref DtBuilder dtb, BaseClass *b, ref FuncDeclarations bvtbl, ClassDeclaration pc, size_t k) 1162 { 1163 //printf("\toverriding vtbl[] for %s\n", b.sym.toChars()); 1164 ClassDeclaration id = b.sym; 1165 1166 const id_vtbl_dim = id.vtbl.dim; 1167 assert(id_vtbl_dim <= bvtbl.dim); 1168 1169 size_t jstart = 0; 1170 if (id.vtblOffset()) 1171 { 1172 // First entry is struct Interface reference 1173 dtb.xoff(toSymbol(pc), cast(uint)(target.classinfosize + k * (4 * target.ptrsize)), TYnptr); 1174 jstart = 1; 1175 } 1176 1177 foreach (j; jstart .. id_vtbl_dim) 1178 { 1179 FuncDeclaration fd = bvtbl[j]; 1180 if (fd) 1181 { 1182 auto offset2 = b.offset; 1183 if (fd.interfaceVirtual) 1184 { 1185 offset2 -= fd.interfaceVirtual.offset; 1186 } 1187 dtb.xoff(toThunkSymbol(fd, offset2), 0, TYnptr); 1188 } 1189 else 1190 dtb.size(0); 1191 } 1192 return id_vtbl_dim * target.ptrsize; 1193 } 1194 1195 1196 /****************************************************** 1197 * Generate the ClassInfo for a Class (__classZ) symbol. 1198 * Write it to the object file. 1199 * Similar to genClassInfoForInterface(). 1200 * Params: 1201 * cd = the class 1202 * sinit = the Initializer (__initZ) symbol for the class 1203 */ 1204 private void genClassInfoForClass(ClassDeclaration cd, Symbol* sinit) 1205 { 1206 // Put out the ClassInfo, which will be the __ClassZ symbol in the object file 1207 enum_SC scclass = SCcomdat; 1208 cd.csym.Sclass = scclass; 1209 cd.csym.Sfl = FLdata; 1210 1211 /* The layout is: 1212 { 1213 void **vptr; 1214 monitor_t monitor; 1215 byte[] m_init; // static initialization data 1216 string name; // class name 1217 void*[] vtbl; 1218 Interface[] interfaces; 1219 ClassInfo base; // base class 1220 void* destructor; 1221 void function(Object) classInvariant; // class invariant 1222 ClassFlags m_flags; 1223 void* deallocator; 1224 OffsetTypeInfo[] offTi; 1225 void function(Object) defaultConstructor; 1226 //const(MemberInfo[]) function(string) xgetMembers; // module getMembers() function 1227 immutable(void)* m_RTInfo; 1228 //TypeInfo typeinfo; 1229 } 1230 */ 1231 uint offset = target.classinfosize; // must be ClassInfo.size 1232 if (Type.typeinfoclass) 1233 { 1234 if (Type.typeinfoclass.structsize != target.classinfosize) 1235 { 1236 debug printf("target.classinfosize = x%x, Type.typeinfoclass.structsize = x%x\n", offset, Type.typeinfoclass.structsize); 1237 cd.error("mismatch between dmd and object.d or object.di found. Check installation and import paths with -v compiler switch."); 1238 fatal(); 1239 } 1240 } 1241 1242 auto dtb = DtBuilder(0); 1243 1244 if (auto tic = Type.typeinfoclass) 1245 { 1246 dtb.xoff(toVtblSymbol(tic), 0, TYnptr); // vtbl for TypeInfo_Class : ClassInfo 1247 if (tic.hasMonitor()) 1248 dtb.size(0); // monitor 1249 } 1250 else 1251 { 1252 dtb.size(0); // BUG: should be an assert() 1253 dtb.size(0); // call hasMonitor()? 1254 } 1255 1256 // m_init[] 1257 assert(cd.structsize >= 8 || (cd.classKind == ClassKind.cpp && cd.structsize >= 4)); 1258 dtb.size(cd.structsize); // size 1259 dtb.xoff(sinit, 0, TYnptr); // initializer 1260 1261 // name[] 1262 const(char) *name = cd.ident.toChars(); 1263 size_t namelen = strlen(name); 1264 if (!(namelen > 9 && memcmp(name, "TypeInfo_".ptr, 9) == 0)) 1265 { 1266 name = cd.toPrettyChars(); 1267 namelen = strlen(name); 1268 } 1269 dtb.size(namelen); 1270 dt_t *pdtname = dtb.xoffpatch(cd.csym, 0, TYnptr); 1271 1272 // vtbl[] 1273 dtb.size(cd.vtbl.dim); 1274 if (cd.vtbl.dim) 1275 dtb.xoff(cd.vtblsym.csym, 0, TYnptr); 1276 else 1277 dtb.size(0); 1278 1279 // interfaces[] 1280 dtb.size(cd.vtblInterfaces.dim); 1281 if (cd.vtblInterfaces.dim) 1282 dtb.xoff(cd.csym, offset, TYnptr); // (*) 1283 else 1284 dtb.size(0); 1285 1286 // base 1287 if (cd.baseClass) 1288 dtb.xoff(toSymbol(cd.baseClass), 0, TYnptr); 1289 else 1290 dtb.size(0); 1291 1292 // destructor 1293 if (cd.tidtor) 1294 dtb.xoff(toSymbol(cd.tidtor), 0, TYnptr); 1295 else 1296 dtb.size(0); 1297 1298 // classInvariant 1299 if (cd.inv) 1300 dtb.xoff(toSymbol(cd.inv), 0, TYnptr); 1301 else 1302 dtb.size(0); 1303 1304 // flags 1305 ClassFlags flags = ClassFlags.hasOffTi; 1306 if (cd.isCOMclass()) flags |= ClassFlags.isCOMclass; 1307 if (cd.isCPPclass()) flags |= ClassFlags.isCPPclass; 1308 flags |= ClassFlags.hasGetMembers; 1309 flags |= ClassFlags.hasTypeInfo; 1310 if (cd.ctor) 1311 flags |= ClassFlags.hasCtor; 1312 for (ClassDeclaration pc = cd; pc; pc = pc.baseClass) 1313 { 1314 if (pc.dtor) 1315 { 1316 flags |= ClassFlags.hasDtor; 1317 break; 1318 } 1319 } 1320 if (cd.isAbstract()) 1321 flags |= ClassFlags.isAbstract; 1322 1323 flags |= ClassFlags.noPointers; // initially assume no pointers 1324 Louter: 1325 for (ClassDeclaration pc = cd; pc; pc = pc.baseClass) 1326 { 1327 if (pc.members) 1328 { 1329 for (size_t i = 0; i < pc.members.dim; i++) 1330 { 1331 Dsymbol sm = (*pc.members)[i]; 1332 //printf("sm = %s %s\n", sm.kind(), sm.toChars()); 1333 if (sm.hasPointers()) 1334 { 1335 flags &= ~ClassFlags.noPointers; // not no-how, not no-way 1336 break Louter; 1337 } 1338 } 1339 } 1340 } 1341 dtb.size(flags); 1342 1343 // deallocator 1344 dtb.size(0); 1345 1346 // offTi[] 1347 dtb.size(0); 1348 dtb.size(0); // null for now, fix later 1349 1350 // defaultConstructor 1351 if (cd.defaultCtor && !(cd.defaultCtor.storage_class & STC.disable)) 1352 dtb.xoff(toSymbol(cd.defaultCtor), 0, TYnptr); 1353 else 1354 dtb.size(0); 1355 1356 // m_RTInfo 1357 if (cd.getRTInfo) 1358 Expression_toDt(cd.getRTInfo, dtb); 1359 else if (flags & ClassFlags.noPointers) 1360 dtb.size(0); 1361 else 1362 dtb.size(1); 1363 1364 //dtb.xoff(toSymbol(cd.type.vtinfo), 0, TYnptr); // typeinfo 1365 1366 ////////////////////////////////////////////// 1367 1368 // Put out (*vtblInterfaces)[]. Must immediately follow csym, because 1369 // of the fixup (*) 1370 1371 offset += cd.vtblInterfaces.dim * (4 * target.ptrsize); 1372 for (size_t i = 0; i < cd.vtblInterfaces.dim; i++) 1373 { 1374 BaseClass *b = (*cd.vtblInterfaces)[i]; 1375 ClassDeclaration id = b.sym; 1376 1377 /* The layout is: 1378 * struct Interface 1379 * { 1380 * ClassInfo classinfo; 1381 * void*[] vtbl; 1382 * size_t offset; 1383 * } 1384 */ 1385 1386 // Fill in vtbl[] 1387 b.fillVtbl(cd, &b.vtbl, 1); 1388 1389 // classinfo 1390 dtb.xoff(toSymbol(id), 0, TYnptr); 1391 1392 // vtbl[] 1393 dtb.size(id.vtbl.dim); 1394 dtb.xoff(cd.csym, offset, TYnptr); 1395 1396 // offset 1397 dtb.size(b.offset); 1398 } 1399 1400 // Put out the (*vtblInterfaces)[].vtbl[] 1401 // This must be mirrored with ClassDeclaration.baseVtblOffset() 1402 //printf("putting out %d interface vtbl[]s for '%s'\n", vtblInterfaces.dim, toChars()); 1403 foreach (i; 0 .. cd.vtblInterfaces.dim) 1404 { 1405 BaseClass *b = (*cd.vtblInterfaces)[i]; 1406 offset += emitVtbl(dtb, b, b.vtbl, cd, i); 1407 } 1408 1409 // Put out the overriding interface vtbl[]s. 1410 // This must be mirrored with ClassDeclaration.baseVtblOffset() 1411 //printf("putting out overriding interface vtbl[]s for '%s' at offset x%x\n", toChars(), offset); 1412 for (ClassDeclaration pc = cd.baseClass; pc; pc = pc.baseClass) 1413 { 1414 foreach (i; 0 .. pc.vtblInterfaces.dim) 1415 { 1416 BaseClass *b = (*pc.vtblInterfaces)[i]; 1417 FuncDeclarations bvtbl; 1418 if (b.fillVtbl(cd, &bvtbl, 0)) 1419 { 1420 offset += emitVtbl(dtb, b, bvtbl, pc, i); 1421 } 1422 } 1423 } 1424 1425 ////////////////////////////////////////////// 1426 1427 dtpatchoffset(pdtname, offset); 1428 1429 dtb.nbytes(cast(uint)(namelen + 1), name); 1430 const size_t namepad = -(namelen + 1) & (target.ptrsize - 1); // align 1431 dtb.nzeros(cast(uint)namepad); 1432 1433 cd.csym.Sdt = dtb.finish(); 1434 // ClassInfo cannot be const data, because we use the monitor on it 1435 outdata(cd.csym); 1436 if (cd.isExport()) 1437 objmod.export_symbol(cd.csym, 0); 1438 } 1439 1440 /****************************************************** 1441 * Generate the ClassInfo for an Interface (classZ symbol). 1442 * Write it to the object file. 1443 * Params: 1444 * id = the interface 1445 */ 1446 private void genClassInfoForInterface(InterfaceDeclaration id) 1447 { 1448 enum_SC scclass = SCcomdat; 1449 1450 // Put out the ClassInfo 1451 id.csym.Sclass = scclass; 1452 id.csym.Sfl = FLdata; 1453 1454 /* The layout is: 1455 { 1456 void **vptr; 1457 monitor_t monitor; 1458 byte[] m_init; // static initialization data 1459 string name; // class name 1460 void*[] vtbl; 1461 Interface[] interfaces; 1462 ClassInfo base; // base class 1463 void* destructor; 1464 void function(Object) classInvariant; // class invariant 1465 ClassFlags m_flags; 1466 void* deallocator; 1467 OffsetTypeInfo[] offTi; 1468 void function(Object) defaultConstructor; 1469 //const(MemberInfo[]) function(string) xgetMembers; // module getMembers() function 1470 immutable(void)* m_RTInfo; 1471 //TypeInfo typeinfo; 1472 } 1473 */ 1474 auto dtb = DtBuilder(0); 1475 1476 if (auto tic = Type.typeinfoclass) 1477 { 1478 dtb.xoff(toVtblSymbol(tic), 0, TYnptr); // vtbl for ClassInfo 1479 if (tic.hasMonitor()) 1480 dtb.size(0); // monitor 1481 } 1482 else 1483 { 1484 dtb.size(0); // BUG: should be an assert() 1485 dtb.size(0); // call hasMonitor()? 1486 } 1487 1488 // m_init[] 1489 dtb.size(0); // size 1490 dtb.size(0); // initializer 1491 1492 // name[] 1493 const(char) *name = id.toPrettyChars(); 1494 size_t namelen = strlen(name); 1495 dtb.size(namelen); 1496 dt_t *pdtname = dtb.xoffpatch(id.csym, 0, TYnptr); 1497 1498 // vtbl[] 1499 dtb.size(0); 1500 dtb.size(0); 1501 1502 // interfaces[] 1503 uint offset = target.classinfosize; 1504 dtb.size(id.vtblInterfaces.dim); 1505 if (id.vtblInterfaces.dim) 1506 { 1507 if (Type.typeinfoclass) 1508 { 1509 if (Type.typeinfoclass.structsize != offset) 1510 { 1511 id.error("mismatch between dmd and object.d or object.di found. Check installation and import paths with -v compiler switch."); 1512 fatal(); 1513 } 1514 } 1515 dtb.xoff(id.csym, offset, TYnptr); // (*) 1516 } 1517 else 1518 { 1519 dtb.size(0); 1520 } 1521 1522 // base 1523 assert(!id.baseClass); 1524 dtb.size(0); 1525 1526 // destructor 1527 dtb.size(0); 1528 1529 // classInvariant 1530 dtb.size(0); 1531 1532 // flags 1533 ClassFlags flags = ClassFlags.hasOffTi | ClassFlags.hasTypeInfo; 1534 if (id.isCOMinterface()) flags |= ClassFlags.isCOMclass; 1535 dtb.size(flags); 1536 1537 // deallocator 1538 dtb.size(0); 1539 1540 // offTi[] 1541 dtb.size(0); 1542 dtb.size(0); // null for now, fix later 1543 1544 // defaultConstructor 1545 dtb.size(0); 1546 1547 // xgetMembers 1548 //dtb.size(0); 1549 1550 // m_RTInfo 1551 if (id.getRTInfo) 1552 Expression_toDt(id.getRTInfo, dtb); 1553 else 1554 dtb.size(0); // no pointers 1555 1556 //dtb.xoff(toSymbol(id.type.vtinfo), 0, TYnptr); // typeinfo 1557 1558 ////////////////////////////////////////////// 1559 1560 // Put out (*vtblInterfaces)[]. Must immediately follow csym, because 1561 // of the fixup (*) 1562 1563 offset += id.vtblInterfaces.dim * (4 * target.ptrsize); 1564 for (size_t i = 0; i < id.vtblInterfaces.dim; i++) 1565 { 1566 BaseClass *b = (*id.vtblInterfaces)[i]; 1567 ClassDeclaration base = b.sym; 1568 1569 // classinfo 1570 dtb.xoff(toSymbol(base), 0, TYnptr); 1571 1572 // vtbl[] 1573 dtb.size(0); 1574 dtb.size(0); 1575 1576 // offset 1577 dtb.size(b.offset); 1578 } 1579 1580 ////////////////////////////////////////////// 1581 1582 dtpatchoffset(pdtname, offset); 1583 1584 dtb.nbytes(cast(uint)(namelen + 1), name); 1585 const size_t namepad = -(namelen + 1) & (target.ptrsize - 1); // align 1586 dtb.nzeros(cast(uint)namepad); 1587 1588 id.csym.Sdt = dtb.finish(); 1589 out_readonly(id.csym); 1590 outdata(id.csym); 1591 if (id.isExport()) 1592 objmod.export_symbol(id.csym, 0); 1593 }