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 }