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 = fd.type.toTypeFunction(); 1082 cd.error("use of `%s%s` is hidden by `%s`; use `alias %s = %s.%s;` to introduce base class overload set", 1083 fd.toPrettyChars(), 1084 parametersTypeToChars(tf.parameterList), 1085 cd.toChars(), 1086 fd.toChars(), 1087 fd.parent.toChars(), 1088 fd.toChars()); 1089 hasError = true; 1090 break; 1091 } 1092 } 1093 1094 return !hasError; 1095 } 1096 1097 1098 /****************************************** 1099 * Get offset of base class's vtbl[] initializer from start of csym. 1100 * Returns ~0 if not this csym. 1101 */ 1102 1103 uint baseVtblOffset(ClassDeclaration cd, BaseClass *bc) 1104 { 1105 //printf("ClassDeclaration.baseVtblOffset('%s', bc = %p)\n", cd.toChars(), bc); 1106 uint csymoffset = target.classinfosize; // must be ClassInfo.size 1107 csymoffset += cd.vtblInterfaces.dim * (4 * target.ptrsize); 1108 1109 for (size_t i = 0; i < cd.vtblInterfaces.dim; i++) 1110 { 1111 BaseClass *b = (*cd.vtblInterfaces)[i]; 1112 1113 if (b == bc) 1114 return csymoffset; 1115 csymoffset += b.sym.vtbl.dim * target.ptrsize; 1116 } 1117 1118 // Put out the overriding interface vtbl[]s. 1119 // This must be mirrored with ClassDeclaration.baseVtblOffset() 1120 //printf("putting out overriding interface vtbl[]s for '%s' at offset x%x\n", toChars(), offset); 1121 ClassDeclaration cd2; 1122 1123 for (cd2 = cd.baseClass; cd2; cd2 = cd2.baseClass) 1124 { 1125 foreach (k; 0 .. cd2.vtblInterfaces.dim) 1126 { 1127 BaseClass *bs = (*cd2.vtblInterfaces)[k]; 1128 if (bs.fillVtbl(cd, null, 0)) 1129 { 1130 if (bc == bs) 1131 { 1132 //printf("\tcsymoffset = x%x\n", csymoffset); 1133 return csymoffset; 1134 } 1135 csymoffset += bs.sym.vtbl.dim * target.ptrsize; 1136 } 1137 } 1138 } 1139 1140 return ~0; 1141 } 1142 1143 /******************* 1144 * Emit the vtbl[] to static data 1145 * Params: 1146 * dtb = static data builder 1147 * b = base class 1148 * bvtbl = array of functions to put in this vtbl[] 1149 * pc = classid for this vtbl[] 1150 * k = offset from pc to classinfo 1151 * Returns: 1152 * number of bytes emitted 1153 */ 1154 private size_t emitVtbl(ref DtBuilder dtb, BaseClass *b, ref FuncDeclarations bvtbl, ClassDeclaration pc, size_t k) 1155 { 1156 //printf("\toverriding vtbl[] for %s\n", b.sym.toChars()); 1157 ClassDeclaration id = b.sym; 1158 1159 const id_vtbl_dim = id.vtbl.dim; 1160 assert(id_vtbl_dim <= bvtbl.dim); 1161 1162 size_t jstart = 0; 1163 if (id.vtblOffset()) 1164 { 1165 // First entry is struct Interface reference 1166 dtb.xoff(toSymbol(pc), cast(uint)(target.classinfosize + k * (4 * target.ptrsize)), TYnptr); 1167 jstart = 1; 1168 } 1169 1170 foreach (j; jstart .. id_vtbl_dim) 1171 { 1172 FuncDeclaration fd = bvtbl[j]; 1173 if (fd) 1174 { 1175 auto offset2 = b.offset; 1176 if (fd.interfaceVirtual) 1177 { 1178 offset2 -= fd.interfaceVirtual.offset; 1179 } 1180 dtb.xoff(toThunkSymbol(fd, offset2), 0, TYnptr); 1181 } 1182 else 1183 dtb.size(0); 1184 } 1185 return id_vtbl_dim * target.ptrsize; 1186 } 1187 1188 1189 /****************************************************** 1190 * Generate the ClassInfo for a Class (__classZ) symbol. 1191 * Write it to the object file. 1192 * Similar to genClassInfoForInterface(). 1193 * Params: 1194 * cd = the class 1195 * sinit = the Initializer (__initZ) symbol for the class 1196 */ 1197 private void genClassInfoForClass(ClassDeclaration cd, Symbol* sinit) 1198 { 1199 // Put out the ClassInfo, which will be the __ClassZ symbol in the object file 1200 enum_SC scclass = SCcomdat; 1201 cd.csym.Sclass = scclass; 1202 cd.csym.Sfl = FLdata; 1203 1204 /* The layout is: 1205 { 1206 void **vptr; 1207 monitor_t monitor; 1208 byte[] m_init; // static initialization data 1209 string name; // class name 1210 void*[] vtbl; 1211 Interface[] interfaces; 1212 ClassInfo base; // base class 1213 void* destructor; 1214 void function(Object) classInvariant; // class invariant 1215 ClassFlags m_flags; 1216 void* deallocator; 1217 OffsetTypeInfo[] offTi; 1218 void function(Object) defaultConstructor; 1219 //const(MemberInfo[]) function(string) xgetMembers; // module getMembers() function 1220 immutable(void)* m_RTInfo; 1221 //TypeInfo typeinfo; 1222 } 1223 */ 1224 uint offset = target.classinfosize; // must be ClassInfo.size 1225 if (Type.typeinfoclass) 1226 { 1227 if (Type.typeinfoclass.structsize != target.classinfosize) 1228 { 1229 debug printf("target.classinfosize = x%x, Type.typeinfoclass.structsize = x%x\n", offset, Type.typeinfoclass.structsize); 1230 cd.error("mismatch between dmd and object.d or object.di found. Check installation and import paths with -v compiler switch."); 1231 fatal(); 1232 } 1233 } 1234 1235 auto dtb = DtBuilder(0); 1236 1237 if (auto tic = Type.typeinfoclass) 1238 { 1239 dtb.xoff(toVtblSymbol(tic), 0, TYnptr); // vtbl for TypeInfo_Class : ClassInfo 1240 if (tic.hasMonitor()) 1241 dtb.size(0); // monitor 1242 } 1243 else 1244 { 1245 dtb.size(0); // BUG: should be an assert() 1246 dtb.size(0); // call hasMonitor()? 1247 } 1248 1249 // m_init[] 1250 assert(cd.structsize >= 8 || (cd.classKind == ClassKind.cpp && cd.structsize >= 4)); 1251 dtb.size(cd.structsize); // size 1252 dtb.xoff(sinit, 0, TYnptr); // initializer 1253 1254 // name[] 1255 const(char) *name = cd.ident.toChars(); 1256 size_t namelen = strlen(name); 1257 if (!(namelen > 9 && memcmp(name, "TypeInfo_".ptr, 9) == 0)) 1258 { 1259 name = cd.toPrettyChars(); 1260 namelen = strlen(name); 1261 } 1262 dtb.size(namelen); 1263 dt_t *pdtname = dtb.xoffpatch(cd.csym, 0, TYnptr); 1264 1265 // vtbl[] 1266 dtb.size(cd.vtbl.dim); 1267 if (cd.vtbl.dim) 1268 dtb.xoff(cd.vtblsym.csym, 0, TYnptr); 1269 else 1270 dtb.size(0); 1271 1272 // interfaces[] 1273 dtb.size(cd.vtblInterfaces.dim); 1274 if (cd.vtblInterfaces.dim) 1275 dtb.xoff(cd.csym, offset, TYnptr); // (*) 1276 else 1277 dtb.size(0); 1278 1279 // base 1280 if (cd.baseClass) 1281 dtb.xoff(toSymbol(cd.baseClass), 0, TYnptr); 1282 else 1283 dtb.size(0); 1284 1285 // destructor 1286 if (cd.tidtor) 1287 dtb.xoff(toSymbol(cd.tidtor), 0, TYnptr); 1288 else 1289 dtb.size(0); 1290 1291 // classInvariant 1292 if (cd.inv) 1293 dtb.xoff(toSymbol(cd.inv), 0, TYnptr); 1294 else 1295 dtb.size(0); 1296 1297 // flags 1298 ClassFlags flags = ClassFlags.hasOffTi; 1299 if (cd.isCOMclass()) flags |= ClassFlags.isCOMclass; 1300 if (cd.isCPPclass()) flags |= ClassFlags.isCPPclass; 1301 flags |= ClassFlags.hasGetMembers; 1302 flags |= ClassFlags.hasTypeInfo; 1303 if (cd.ctor) 1304 flags |= ClassFlags.hasCtor; 1305 for (ClassDeclaration pc = cd; pc; pc = pc.baseClass) 1306 { 1307 if (pc.dtor) 1308 { 1309 flags |= ClassFlags.hasDtor; 1310 break; 1311 } 1312 } 1313 if (cd.isAbstract()) 1314 flags |= ClassFlags.isAbstract; 1315 1316 flags |= ClassFlags.noPointers; // initially assume no pointers 1317 Louter: 1318 for (ClassDeclaration pc = cd; pc; pc = pc.baseClass) 1319 { 1320 if (pc.members) 1321 { 1322 for (size_t i = 0; i < pc.members.dim; i++) 1323 { 1324 Dsymbol sm = (*pc.members)[i]; 1325 //printf("sm = %s %s\n", sm.kind(), sm.toChars()); 1326 if (sm.hasPointers()) 1327 { 1328 flags &= ~ClassFlags.noPointers; // not no-how, not no-way 1329 break Louter; 1330 } 1331 } 1332 } 1333 } 1334 dtb.size(flags); 1335 1336 // deallocator 1337 dtb.size(0); 1338 1339 // offTi[] 1340 dtb.size(0); 1341 dtb.size(0); // null for now, fix later 1342 1343 // defaultConstructor 1344 if (cd.defaultCtor && !(cd.defaultCtor.storage_class & STC.disable)) 1345 dtb.xoff(toSymbol(cd.defaultCtor), 0, TYnptr); 1346 else 1347 dtb.size(0); 1348 1349 // m_RTInfo 1350 if (cd.getRTInfo) 1351 Expression_toDt(cd.getRTInfo, dtb); 1352 else if (flags & ClassFlags.noPointers) 1353 dtb.size(0); 1354 else 1355 dtb.size(1); 1356 1357 //dtb.xoff(toSymbol(cd.type.vtinfo), 0, TYnptr); // typeinfo 1358 1359 ////////////////////////////////////////////// 1360 1361 // Put out (*vtblInterfaces)[]. Must immediately follow csym, because 1362 // of the fixup (*) 1363 1364 offset += cd.vtblInterfaces.dim * (4 * target.ptrsize); 1365 for (size_t i = 0; i < cd.vtblInterfaces.dim; i++) 1366 { 1367 BaseClass *b = (*cd.vtblInterfaces)[i]; 1368 ClassDeclaration id = b.sym; 1369 1370 /* The layout is: 1371 * struct Interface 1372 * { 1373 * ClassInfo classinfo; 1374 * void*[] vtbl; 1375 * size_t offset; 1376 * } 1377 */ 1378 1379 // Fill in vtbl[] 1380 b.fillVtbl(cd, &b.vtbl, 1); 1381 1382 // classinfo 1383 dtb.xoff(toSymbol(id), 0, TYnptr); 1384 1385 // vtbl[] 1386 dtb.size(id.vtbl.dim); 1387 dtb.xoff(cd.csym, offset, TYnptr); 1388 1389 // offset 1390 dtb.size(b.offset); 1391 } 1392 1393 // Put out the (*vtblInterfaces)[].vtbl[] 1394 // This must be mirrored with ClassDeclaration.baseVtblOffset() 1395 //printf("putting out %d interface vtbl[]s for '%s'\n", vtblInterfaces.dim, toChars()); 1396 foreach (i; 0 .. cd.vtblInterfaces.dim) 1397 { 1398 BaseClass *b = (*cd.vtblInterfaces)[i]; 1399 offset += emitVtbl(dtb, b, b.vtbl, cd, i); 1400 } 1401 1402 // Put out the overriding interface vtbl[]s. 1403 // This must be mirrored with ClassDeclaration.baseVtblOffset() 1404 //printf("putting out overriding interface vtbl[]s for '%s' at offset x%x\n", toChars(), offset); 1405 for (ClassDeclaration pc = cd.baseClass; pc; pc = pc.baseClass) 1406 { 1407 foreach (i; 0 .. pc.vtblInterfaces.dim) 1408 { 1409 BaseClass *b = (*pc.vtblInterfaces)[i]; 1410 FuncDeclarations bvtbl; 1411 if (b.fillVtbl(cd, &bvtbl, 0)) 1412 { 1413 offset += emitVtbl(dtb, b, bvtbl, pc, i); 1414 } 1415 } 1416 } 1417 1418 ////////////////////////////////////////////// 1419 1420 dtpatchoffset(pdtname, offset); 1421 1422 dtb.nbytes(cast(uint)(namelen + 1), name); 1423 const size_t namepad = -(namelen + 1) & (target.ptrsize - 1); // align 1424 dtb.nzeros(cast(uint)namepad); 1425 1426 cd.csym.Sdt = dtb.finish(); 1427 // ClassInfo cannot be const data, because we use the monitor on it 1428 outdata(cd.csym); 1429 if (cd.isExport()) 1430 objmod.export_symbol(cd.csym, 0); 1431 } 1432 1433 /****************************************************** 1434 * Generate the ClassInfo for an Interface (classZ symbol). 1435 * Write it to the object file. 1436 * Params: 1437 * id = the interface 1438 */ 1439 private void genClassInfoForInterface(InterfaceDeclaration id) 1440 { 1441 enum_SC scclass = SCcomdat; 1442 1443 // Put out the ClassInfo 1444 id.csym.Sclass = scclass; 1445 id.csym.Sfl = FLdata; 1446 1447 /* The layout is: 1448 { 1449 void **vptr; 1450 monitor_t monitor; 1451 byte[] m_init; // static initialization data 1452 string name; // class name 1453 void*[] vtbl; 1454 Interface[] interfaces; 1455 ClassInfo base; // base class 1456 void* destructor; 1457 void function(Object) classInvariant; // class invariant 1458 ClassFlags m_flags; 1459 void* deallocator; 1460 OffsetTypeInfo[] offTi; 1461 void function(Object) defaultConstructor; 1462 //const(MemberInfo[]) function(string) xgetMembers; // module getMembers() function 1463 immutable(void)* m_RTInfo; 1464 //TypeInfo typeinfo; 1465 } 1466 */ 1467 auto dtb = DtBuilder(0); 1468 1469 if (auto tic = Type.typeinfoclass) 1470 { 1471 dtb.xoff(toVtblSymbol(tic), 0, TYnptr); // vtbl for ClassInfo 1472 if (tic.hasMonitor()) 1473 dtb.size(0); // monitor 1474 } 1475 else 1476 { 1477 dtb.size(0); // BUG: should be an assert() 1478 dtb.size(0); // call hasMonitor()? 1479 } 1480 1481 // m_init[] 1482 dtb.size(0); // size 1483 dtb.size(0); // initializer 1484 1485 // name[] 1486 const(char) *name = id.toPrettyChars(); 1487 size_t namelen = strlen(name); 1488 dtb.size(namelen); 1489 dt_t *pdtname = dtb.xoffpatch(id.csym, 0, TYnptr); 1490 1491 // vtbl[] 1492 dtb.size(0); 1493 dtb.size(0); 1494 1495 // interfaces[] 1496 uint offset = target.classinfosize; 1497 dtb.size(id.vtblInterfaces.dim); 1498 if (id.vtblInterfaces.dim) 1499 { 1500 if (Type.typeinfoclass) 1501 { 1502 if (Type.typeinfoclass.structsize != offset) 1503 { 1504 id.error("mismatch between dmd and object.d or object.di found. Check installation and import paths with -v compiler switch."); 1505 fatal(); 1506 } 1507 } 1508 dtb.xoff(id.csym, offset, TYnptr); // (*) 1509 } 1510 else 1511 { 1512 dtb.size(0); 1513 } 1514 1515 // base 1516 assert(!id.baseClass); 1517 dtb.size(0); 1518 1519 // destructor 1520 dtb.size(0); 1521 1522 // classInvariant 1523 dtb.size(0); 1524 1525 // flags 1526 ClassFlags flags = ClassFlags.hasOffTi | ClassFlags.hasTypeInfo; 1527 if (id.isCOMinterface()) flags |= ClassFlags.isCOMclass; 1528 dtb.size(flags); 1529 1530 // deallocator 1531 dtb.size(0); 1532 1533 // offTi[] 1534 dtb.size(0); 1535 dtb.size(0); // null for now, fix later 1536 1537 // defaultConstructor 1538 dtb.size(0); 1539 1540 // xgetMembers 1541 //dtb.size(0); 1542 1543 // m_RTInfo 1544 if (id.getRTInfo) 1545 Expression_toDt(id.getRTInfo, dtb); 1546 else 1547 dtb.size(0); // no pointers 1548 1549 //dtb.xoff(toSymbol(id.type.vtinfo), 0, TYnptr); // typeinfo 1550 1551 ////////////////////////////////////////////// 1552 1553 // Put out (*vtblInterfaces)[]. Must immediately follow csym, because 1554 // of the fixup (*) 1555 1556 offset += id.vtblInterfaces.dim * (4 * target.ptrsize); 1557 for (size_t i = 0; i < id.vtblInterfaces.dim; i++) 1558 { 1559 BaseClass *b = (*id.vtblInterfaces)[i]; 1560 ClassDeclaration base = b.sym; 1561 1562 // classinfo 1563 dtb.xoff(toSymbol(base), 0, TYnptr); 1564 1565 // vtbl[] 1566 dtb.size(0); 1567 dtb.size(0); 1568 1569 // offset 1570 dtb.size(b.offset); 1571 } 1572 1573 ////////////////////////////////////////////// 1574 1575 dtpatchoffset(pdtname, offset); 1576 1577 dtb.nbytes(cast(uint)(namelen + 1), name); 1578 const size_t namepad = -(namelen + 1) & (target.ptrsize - 1); // align 1579 dtb.nzeros(cast(uint)namepad); 1580 1581 id.csym.Sdt = dtb.finish(); 1582 out_readonly(id.csym); 1583 outdata(id.csym); 1584 if (id.isExport()) 1585 objmod.export_symbol(id.csym, 0); 1586 }