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 1
    if (!Module.moduleinfo)
87
    {
88 0
        ObjectNotFound(Id.ModuleInfo);
89
    }
90

91 1
    Symbol *msym = toSymbol(m);
92

93
    //////////////////////////////////////////////
94

95 1
    m.csym.Sclass = SCglobal;
96 1
    m.csym.Sfl = FLdata;
97

98 1
    auto dtb = DtBuilder(0);
99 1
    ClassDeclarations aclasses;
100

101
    //printf("members.dim = %d\n", members.dim);
102 1
    foreach (i; 0 .. m.members.dim)
103
    {
104 1
        Dsymbol member = (*m.members)[i];
105

106
        //printf("\tmember '%s'\n", member.toChars());
107 1
        member.addLocalClass(&aclasses);
108
    }
109

110
    // importedModules[]
111 1
    size_t aimports_dim = m.aimports.dim;
112 1
    for (size_t i = 0; i < m.aimports.dim; i++)
113
    {
114 1
        Module mod = m.aimports[i];
115 1
        if (!mod.needmoduleinfo)
116 1
            aimports_dim--;
117
    }
118

119 1
    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 1
    uint flags = 0;
138 1
    if (!m.needmoduleinfo)
139 1
        flags |= MIstandalone;
140 1
    if (m.sctor)
141 1
        flags |= MItlsctor;
142 1
    if (m.sdtor)
143 1
        flags |= MItlsdtor;
144 1
    if (m.ssharedctor)
145 1
        flags |= MIctor;
146 1
    if (m.sshareddtor)
147 1
        flags |= MIdtor;
148 1
    if (sgetmembers)
149 0
        flags |= MIxgetMembers;
150 1
    if (m.sictor)
151 1
        flags |= MIictor;
152 1
    if (m.stest)
153 1
        flags |= MIunitTest;
154 1
    if (aimports_dim)
155 1
        flags |= MIimportedModules;
156 1
    if (aclasses.dim)
157 1
        flags |= MIlocalClasses;
158 1
    flags |= MIname;
159

160 1
    dtb.dword(flags);        // _flags
161 1
    dtb.dword(0);            // _index
162

163 1
    if (flags & MItlsctor)
164 1
        dtb.xoff(m.sctor, 0, TYnptr);
165 1
    if (flags & MItlsdtor)
166 1
        dtb.xoff(m.sdtor, 0, TYnptr);
167 1
    if (flags & MIctor)
168 1
        dtb.xoff(m.ssharedctor, 0, TYnptr);
169 1
    if (flags & MIdtor)
170 1
        dtb.xoff(m.sshareddtor, 0, TYnptr);
171 1
    if (flags & MIxgetMembers)
172 0
        dtb.xoff(toSymbol(sgetmembers), 0, TYnptr);
173 1
    if (flags & MIictor)
174 1
        dtb.xoff(m.sictor, 0, TYnptr);
175 1
    if (flags & MIunitTest)
176 1
        dtb.xoff(m.stest, 0, TYnptr);
177 1
    if (flags & MIimportedModules)
178
    {
179 1
        dtb.size(aimports_dim);
180 1
        foreach (i; 0 .. m.aimports.dim)
181
        {
182 1
            Module mod = m.aimports[i];
183

184 1
            if (!mod.needmoduleinfo)
185 1
                continue;
186

187 1
            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 1
            s.Sflags |= SFLweak;
194 1
            dtb.xoff(s, 0, TYnptr);
195
        }
196
    }
197 1
    if (flags & MIlocalClasses)
198
    {
199 1
        dtb.size(aclasses.dim);
200 1
        foreach (i; 0 .. aclasses.dim)
201
        {
202 1
            ClassDeclaration cd = aclasses[i];
203 1
            dtb.xoff(toSymbol(cd), 0, TYnptr);
204
        }
205
    }
206 1
    if (flags & MIname)
207
    {
208
        // Put out module name as a 0-terminated string, to save bytes
209 1
        m.nameoffset = dtb.length();
210 1
        const(char) *name = m.toPrettyChars();
211 1
        m.namelen = strlen(name);
212 1
        dtb.nbytes(cast(uint)m.namelen + 1, name);
213
        //printf("nameoffset = x%x\n", nameoffset);
214
    }
215

216 1
    objc.generateModuleInfo(m);
217 1
    m.csym.Sdt = dtb.finish();
218 1
    out_readonly(m.csym);
219 1
    outdata(m.csym);
220

221
    //////////////////////////////////////////////
222

223 1
    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 1
    uint ty = type.toBasetype().ty;
237 1
    if (ty == Tclass)
238 1
        return objmod.write_pointerRef(s, offset);
239

240 1
    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 1
    if (!type.hasPointers())
254 1
        return;
255

256 1
    Array!(d_uns64) data;
257 1
    d_uns64 sz = getTypePointerBitmap(Loc.initial, type, &data);
258 1
    if (sz == d_uns64.max)
259 0
        return;
260

261 1
    const bytes_size_t = cast(size_t)Type.tsize_t.size(Loc.initial);
262 1
    const bits_size_t = bytes_size_t * 8;
263 1
    auto words = cast(size_t)(sz / bytes_size_t);
264 1
    for (size_t i = 0; i < data.dim; i++)
265
    {
266 1
        size_t bits = words < bits_size_t ? words : bits_size_t;
267 1
        for (size_t b = 0; b < bits; b++)
268 1
            if (data[i] & (1L << b))
269
            {
270 1
                auto off = cast(uint) ((i * bits_size_t + b) * bytes_size_t);
271 1
                objmod.write_pointerRef(s, off + offset);
272
            }
273 1
        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 1
        this(bool multiobj)
289
        {
290 1
            this.multiobj = multiobj;
291
        }
292

293
        void visitNoMultiObj(Dsymbol ds)
294
        {
295 1
            bool multiobjsave = multiobj;
296 1
            multiobj = false;
297 1
            ds.accept(this);
298 1
            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 1
            FuncDeclaration_toObjFile(fd, multiobj);
311
        }
312

313
        override void visit(ClassDeclaration cd)
314
        {
315
            //printf("ClassDeclaration.toObjFile('%s')\n", cd.toChars());
316

317 1
            if (cd.type.ty == Terror)
318
            {
319 0
                cd.error("had semantic errors when compiling");
320 0
                return;
321
            }
322

323 1
            if (!cd.members)
324 1
                return;
325

326 1
            if (multiobj && !cd.hasStaticCtorOrDtor())
327
            {
328 1
                obj_append(cd);
329 1
                return;
330
            }
331

332 1
            if (global.params.symdebugref)
333 0
                Type_toCtype(cd.type); // calls toDebug() only once
334 1
            else if (global.params.symdebug)
335 1
                toDebug(cd);
336

337 1
            assert(cd.semanticRun >= PASS.semantic3done);     // semantic() should have been run to completion
338

339 1
            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 1
            cd.members.foreachDsymbol( (s) { s.accept(this); } );
346

347 1
            if (cd.classKind == ClassKind.objc)
348
            {
349 0
                objc.toObjFile(cd);
350 0
                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 1
            if (!finishVtbl(cd))
357
            {
358 1
                return;
359
            }
360

361 1
            const bool gentypeinfo = global.params.useTypeInfo && Type.dtypeinfo;
362 1
            const bool genclassinfo = gentypeinfo || !(cd.isCPPclass || cd.isCOMclass);
363

364
            // Generate C symbols
365 1
            if (genclassinfo)
366 1
                toSymbol(cd);                           // __ClassZ symbol
367 1
            toVtblSymbol(cd);                           // __vtblZ symbol
368 1
            Symbol *sinit = toInitializer(cd);          // __initZ symbol
369

370
            //////////////////////////////////////////////
371

372
            // Generate static initializer
373
            {
374 1
                sinit.Sclass = scclass;
375 1
                sinit.Sfl = FLdata;
376 1
                auto dtb = DtBuilder(0);
377 1
                ClassDeclaration_toDt(cd, dtb);
378 1
                sinit.Sdt = dtb.finish();
379 1
                out_readonly(sinit);
380 1
                outdata(sinit);
381
            }
382

383
            //////////////////////////////////////////////
384

385
            // Put out the TypeInfo
386 1
            if (gentypeinfo)
387 1
                genTypeInfo(cd.loc, cd.type, null);
388
            //toObjFile(cd.type.vtinfo, multiobj);
389

390 1
            if (genclassinfo)
391
            {
392 1
                genClassInfoForClass(cd, sinit);
393
            }
394

395
            //////////////////////////////////////////////
396

397
            // Put out the vtbl[]
398
            //printf("putting out %s.vtbl[]\n", toChars());
399 1
            auto dtbv = DtBuilder(0);
400 1
            if (cd.vtblOffset())
401 1
                dtbv.xoff(cd.csym, 0, TYnptr);           // first entry is ClassInfo reference
402 1
            foreach (i; cd.vtblOffset() .. cd.vtbl.dim)
403
            {
404 1
                FuncDeclaration fd = cd.vtbl[i].isFuncDeclaration();
405

406
                //printf("\tvtbl[%d] = %p\n", i, fd);
407 1
                if (fd && (fd.fbody || !cd.isAbstract()))
408
                {
409 1
                    dtbv.xoff(toSymbol(fd), 0, TYnptr);
410
                }
411
                else
412 1
                    dtbv.size(0);
413
            }
414 1
            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 1
                dtbv.size(0);
421
            }
422 1
            cd.vtblsym.csym.Sdt = dtbv.finish();
423 1
            cd.vtblsym.csym.Sclass = scclass;
424 1
            cd.vtblsym.csym.Sfl = FLdata;
425 1
            out_readonly(cd.vtblsym.csym);
426 1
            outdata(cd.vtblsym.csym);
427 1
            if (cd.isExport())
428 1
                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 1
            if (id.type.ty == Terror)
436
            {
437 0
                id.error("had semantic errors when compiling");
438 0
                return;
439
            }
440

441 1
            if (!id.members)
442 1
                return;
443

444 1
            if (global.params.symdebugref)
445 0
                Type_toCtype(id.type); // calls toDebug() only once
446 1
            else if (global.params.symdebug)
447 1
                toDebug(id);
448

449
            // Put out the members
450 1
            id.members.foreachDsymbol( (s) { visitNoMultiObj(s); } );
451

452
            // Generate C symbols
453 1
            toSymbol(id);
454

455
            //////////////////////////////////////////////
456

457
            // Put out the TypeInfo
458 1
            if (global.params.useTypeInfo && Type.dtypeinfo)
459
            {
460 1
                genTypeInfo(id.loc, id.type, null);
461 1
                id.type.vtinfo.accept(this);
462
            }
463

464
            //////////////////////////////////////////////
465

466 1
            genClassInfoForInterface(id);
467
        }
468

469
        override void visit(StructDeclaration sd)
470
        {
471
            //printf("StructDeclaration.toObjFile('%s')\n", sd.toChars());
472

473 1
            if (sd.type.ty == Terror)
474
            {
475 1
                sd.error("had semantic errors when compiling");
476 1
                return;
477
            }
478

479 1
            if (multiobj && !sd.hasStaticCtorOrDtor())
480
            {
481 1
                obj_append(sd);
482 1
                return;
483
            }
484

485
            // Anonymous structs/unions only exist as part of others,
486
            // do not output forward referenced structs's
487 1
            if (!sd.isAnonymous() && sd.members)
488
            {
489 1
                if (global.params.symdebugref)
490 0
                    Type_toCtype(sd.type); // calls toDebug() only once
491 1
                else if (global.params.symdebug)
492 1
                    toDebug(sd);
493

494 1
                if (global.params.useTypeInfo && Type.dtypeinfo)
495 1
                    genTypeInfo(sd.loc, sd.type, null);
496

497
                // Generate static initializer
498 1
                auto sinit = toInitializer(sd);
499 1
                if (sinit.Sclass == SCextern)
500
                {
501 1
                    if (sinit == bzeroSymbol) assert(0);
502 1
                    sinit.Sclass = sd.isInstantiated() ? SCcomdat : SCglobal;
503 1
                    sinit.Sfl = FLdata;
504 1
                    auto dtb = DtBuilder(0);
505 1
                    StructDeclaration_toDt(sd, dtb);
506 1
                    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 1
                    if (config.objfmt != OBJ_MACH &&
514 1
                        dtallzeros(sinit.Sdt))
515
                    {
516 1
                        sinit.Sclass = SCglobal;
517 1
                        dt2common(&sinit.Sdt);
518
                    }
519
                    else
520 1
                        out_readonly(sinit);    // put in read-only segment
521 1
                    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 1
                sd.members.foreachDsymbol( (s) { s.accept(this); } );
529

530 1
                if (sd.xeq && sd.xeq != StructDeclaration.xerreq)
531 1
                    sd.xeq.accept(this);
532 1
                if (sd.xcmp && sd.xcmp != StructDeclaration.xerrcmp)
533 1
                    sd.xcmp.accept(this);
534 1
                if (sd.xhash)
535 1
                    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 1
            if (vd.type.ty == Terror)
546
            {
547 0
                vd.error("had semantic errors when compiling");
548 0
                return;
549
            }
550

551 1
            if (vd.aliassym)
552
            {
553 1
                visitNoMultiObj(vd.toAlias());
554 1
                return;
555
            }
556

557
            // Do not store variables we cannot take the address of
558 1
            if (!vd.canTakeAddressOf())
559
            {
560 1
                return;
561
            }
562

563 1
            if (!vd.isDataseg() || vd.storage_class & STC.extern_)
564 1
                return;
565

566 1
            Symbol *s = toSymbol(vd);
567 1
            d_uns64 sz64 = vd.type.size(vd.loc);
568 1
            if (sz64 == SIZE_INVALID)
569
            {
570 1
                vd.error("size overflow");
571 1
                return;
572
            }
573 1
            if (sz64 >= target.maxStaticDataSize)
574
            {
575 0
                vd.error("size of 0x%llx exceeds max allowed size 0x%llx", sz64, target.maxStaticDataSize);
576
            }
577 1
            uint sz = cast(uint)sz64;
578

579 1
            Dsymbol parent = vd.toParent();
580 1
            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 1
                if (parent.isTemplateInstance() && !parent.isTemplateMixin())
589
                {
590 1
                    s.Sclass = SCcomdat;
591 1
                    break;
592
                }
593 1
                parent = parent.parent;
594 1
            } while (parent);
595 1
            s.Sfl = FLdata;
596

597 1
            if (!sz && vd.type.toBasetype().ty != Tsarray)
598 0
                assert(0); // this shouldn't be possible
599

600 1
            auto dtb = DtBuilder(0);
601 1
            if (config.objfmt == OBJ_MACH && global.params.is64bit && (s.Stype.Tty & mTYLINK) == mTYthread)
602
            {
603 0
                tlsToDt(vd, s, sz, dtb);
604
            }
605 1
            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 1
                dtb.nzeros(1);
612
            }
613 1
            else if (vd._init)
614
            {
615 1
                initializerToDt(vd, dtb);
616
            }
617
            else
618
            {
619 1
                Type_toDt(vd.type, dtb);
620
            }
621 1
            s.Sdt = dtb.finish();
622

623
            // See if we can convert a comdat to a comdef,
624
            // which saves on exe file space.
625 1
            if (s.Sclass == SCcomdat &&
626 1
                s.Sdt &&
627 1
                dtallzeros(s.Sdt) &&
628 1
                !vd.isThreadlocal())
629
            {
630 1
                s.Sclass = SCglobal;
631 1
                dt2common(&s.Sdt);
632
            }
633

634 1
            outdata(s);
635 1
            if (vd.type.isMutable() || !vd._init)
636 1
                write_pointers(vd.type, s, 0);
637 1
            if (vd.isExport())
638 0
                objmod.export_symbol(s, 0);
639
        }
640

641
        override void visit(EnumDeclaration ed)
642
        {
643 1
            if (ed.semanticRun >= PASS.obj)  // already written
644 0
                return;
645
            //printf("EnumDeclaration.toObjFile('%s')\n", ed.toChars());
646

647 1
            if (ed.errors || ed.type.ty == Terror)
648
            {
649 0
                ed.error("had semantic errors when compiling");
650 0
                return;
651
            }
652

653 1
            if (ed.isAnonymous())
654 1
                return;
655

656 1
            if (global.params.symdebugref)
657 0
                Type_toCtype(ed.type); // calls toDebug() only once
658 1
            else if (global.params.symdebug)
659 1
                toDebug(ed);
660

661 1
            if (global.params.useTypeInfo && Type.dtypeinfo)
662 1
                genTypeInfo(ed.loc, ed.type, null);
663

664 1
            TypeEnum tc = cast(TypeEnum)ed.type;
665 1
            if (!tc.sym.members || ed.type.isZeroInit(Loc.initial))
666
            {
667
            }
668
            else
669
            {
670 1
                enum_SC scclass = SCglobal;
671 1
                if (ed.isInstantiated())
672 0
                    scclass = SCcomdat;
673

674
                // Generate static initializer
675 1
                toInitializer(ed);
676 1
                ed.sinit.Sclass = scclass;
677 1
                ed.sinit.Sfl = FLdata;
678 1
                auto dtb = DtBuilder(0);
679 1
                Expression_toDt(tc.sym.defaultval, dtb);
680 1
                ed.sinit.Sdt = dtb.finish();
681 1
                outdata(ed.sinit);
682
            }
683 1
            ed.semanticRun = PASS.obj;
684
        }
685

686
        override void visit(TypeInfoDeclaration tid)
687
        {
688 1
            if (isSpeculativeType(tid.tinfo))
689
            {
690
                //printf("-speculative '%s'\n", tid.toPrettyChars());
691 1
                return;
692
            }
693
            //printf("TypeInfoDeclaration.toObjFile(%p '%s') protection %d\n", tid, tid.toChars(), tid.protection);
694

695 1
            if (multiobj)
696
            {
697 1
                obj_append(tid);
698 1
                return;
699
            }
700

701 1
            Symbol *s = toSymbol(tid);
702 1
            s.Sclass = SCcomdat;
703 1
            s.Sfl = FLdata;
704

705 1
            auto dtb = DtBuilder(0);
706 1
            TypeInfo_toDt(dtb, tid);
707 1
            s.Sdt = dtb.finish();
708

709
            // See if we can convert a comdat to a comdef,
710
            // which saves on exe file space.
711 1
            if (s.Sclass == SCcomdat &&
712 1
                dtallzeros(s.Sdt))
713
            {
714 0
                s.Sclass = SCglobal;
715 0
                dt2common(&s.Sdt);
716
            }
717

718 1
            outdata(s);
719 1
            if (tid.isExport())
720 0
                objmod.export_symbol(s, 0);
721
        }
722

723
        override void visit(AttribDeclaration ad)
724
        {
725 1
            Dsymbols *d = ad.include(null);
726

727 1
            if (d)
728
            {
729 1
                for (size_t i = 0; i < d.dim; i++)
730
                {
731 1
                    Dsymbol s = (*d)[i];
732 1
                    s.accept(this);
733
                }
734
            }
735
        }
736

737
        override void visit(PragmaDeclaration pd)
738
        {
739 1
            if (pd.ident == Id.lib)
740
            {
741 1
                assert(pd.args && pd.args.dim == 1);
742

743 1
                Expression e = (*pd.args)[0];
744

745 1
                assert(e.op == TOK.string_);
746

747 1
                StringExp se = cast(StringExp)e;
748 1
                char *name = cast(char *)mem.xmalloc(se.numberOfCodeUnits() + 1);
749 1
                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 1
                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 1
                    global.params.libfiles.push(name);
762
                }
763
            }
764 1
            else if (pd.ident == Id.startaddress)
765
            {
766 1
                assert(pd.args && pd.args.dim == 1);
767 1
                Expression e = (*pd.args)[0];
768 1
                Dsymbol sa = getDsymbol(e);
769 1
                FuncDeclaration f = sa.isFuncDeclaration();
770 1
                assert(f);
771 1
                Symbol *s = toSymbol(f);
772 1
                obj_startaddress(s);
773
            }
774 1
            else if (pd.ident == Id.linkerDirective)
775
            {
776 0
                assert(pd.args && pd.args.dim == 1);
777

778 0
                Expression e = (*pd.args)[0];
779

780 0
                assert(e.op == TOK.string_);
781

782 0
                StringExp se = cast(StringExp)e;
783 0
                char *directive = cast(char *)mem.xmalloc(se.numberOfCodeUnits() + 1);
784 0
                se.writeTo(directive, true);
785

786 0
                obj_linkerdirective(directive);
787
            }
788 1
            else if (pd.ident == Id.crt_constructor || pd.ident == Id.crt_destructor)
789
            {
790 1
                immutable isCtor = pd.ident == Id.crt_constructor;
791

792
                static uint recurse(Dsymbol s, bool isCtor)
793
                {
794 1
                    if (auto ad = s.isAttribDeclaration())
795
                    {
796 1
                        uint nestedCount;
797 1
                        auto decls = ad.include(null);
798 1
                        if (decls)
799
                        {
800 1
                            for (size_t i = 0; i < decls.dim; ++i)
801 1
                                nestedCount += recurse((*decls)[i], isCtor);
802
                        }
803 1
                        return nestedCount;
804
                    }
805 1
                    else if (auto f = s.isFuncDeclaration())
806
                    {
807 1
                        f.isCrtCtorDtor |= isCtor ? 1 : 2;
808 1
                        if (f.linkage != LINK.c)
809 1
                            f.error("must be `extern(C)` for `pragma(%s)`", isCtor ? "crt_constructor".ptr : "crt_destructor".ptr);
810 1
                        return 1;
811
                    }
812
                    else
813 1
                        return 0;
814 0
                    assert(0);
815
                }
816

817 1
                if (recurse(pd, isCtor) > 1)
818 1
                    pd.error("can only apply to a single declaration");
819
            }
820

821 1
            visit(cast(AttribDeclaration)pd);
822
        }
823

824
        override void visit(TemplateInstance ti)
825
        {
826
            //printf("TemplateInstance.toObjFile(%p, '%s')\n", ti, ti.toChars());
827 1
            if (!isError(ti) && ti.members)
828
            {
829 1
                if (!ti.needsCodegen())
830
                {
831
                    //printf("-speculative (%p, %s)\n", ti, ti.toPrettyChars());
832 1
                    return;
833
                }
834
                //printf("TemplateInstance.toObjFile(%p, '%s')\n", ti, ti.toPrettyChars());
835

836 1
                if (multiobj)
837
                {
838
                    // Append to list of object files to be written later
839 1
                    obj_append(ti);
840
                }
841
                else
842
                {
843 1
                    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 1
            if (!isError(tm))
852
            {
853 1
                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 1
            if (!isError(ns) && ns.members)
865
            {
866 1
                if (multiobj)
867
                {
868
                    // Append to list of object files to be written later
869 0
                    obj_append(ns);
870
                }
871
                else
872
                {
873 1
                    ns.members.foreachDsymbol( (s) { s.accept(this); } );
874
                }
875
            }
876
        }
877

878
    private:
879
        static void initializerToDt(VarDeclaration vd, ref DtBuilder dtb)
880
        {
881 1
            Initializer_toDt(vd._init, dtb);
882

883
            // Look for static array that is block initialized
884 1
            ExpInitializer ie = vd._init.isExpInitializer();
885

886 1
            Type tb = vd.type.toBasetype();
887 1
            if (tb.ty == Tsarray && ie &&
888 1
                !tb.nextOf().equals(ie.exp.type.toBasetype().nextOf()) &&
889 1
                ie.exp.implicitConvTo(tb.nextOf())
890
                )
891
            {
892 1
                auto dim = (cast(TypeSArray)tb).dim.toInteger();
893

894
                // Duplicate Sdt 'dim-1' times, as we already have the first one
895 1
                while (--dim > 0)
896
                {
897 1
                    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 0
            assert(config.objfmt == OBJ_MACH && global.params.is64bit && (s.Stype.Tty & mTYLINK) == mTYthread);
933

934 0
            Symbol *tlvInit = createTLVDataSymbol(vd, s);
935 0
            auto tlvInitDtb = DtBuilder(0);
936

937 0
            if (sz == 0)
938 0
                tlvInitDtb.nzeros(1);
939 0
            else if (vd._init)
940 0
                initializerToDt(vd, tlvInitDtb);
941
            else
942 0
                Type_toDt(vd.type, tlvInitDtb);
943

944 0
            tlvInit.Sdt = tlvInitDtb.finish();
945 0
            outdata(tlvInit);
946

947 0
            if (global.params.is64bit)
948 0
                tlvInit.Sclass = SCextern;
949

950 0
            Symbol* tlvBootstrap = objmod.tlv_bootstrap();
951 0
            dtb.xoff(tlvBootstrap, 0, TYnptr);
952 0
            dtb.size(0);
953 0
            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 0
            assert(config.objfmt == OBJ_MACH && global.params.is64bit && (s.Stype.Tty & mTYLINK) == mTYthread);
968

969
            // Compute identifier for tlv symbol
970 0
            OutBuffer buffer;
971 0
            buffer.writestring(s.Sident);
972 0
            buffer.writestring("$tlv$init");
973 0
            const(char) *tlvInitName = buffer.peekChars();
974

975
            // Compute type for tlv symbol
976 0
            type *t = type_fake(vd.type.ty);
977 0
            type_setty(&t, t.Tty | mTYthreadData);
978 0
            type_setmangle(&t, mangle(vd));
979

980 0
            Symbol *tlvInit = symbol_name(tlvInitName, SCstatic, t);
981 0
            tlvInit.Sdt = null;
982 0
            tlvInit.Salignment = type_alignsize(s.Stype);
983 0
            if (vd.linkage == LINK.cpp)
984 0
                tlvInit.Sflags |= SFLpublic;
985

986 0
            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 0
            final switch (vd.linkage)
1001
            {
1002 0
                case LINK.windows:
1003 0
                    return global.params.is64bit ? mTYman_c : mTYman_std;
1004

1005 0
                case LINK.pascal:
1006 0
                    return mTYman_pas;
1007

1008 0
                case LINK.objc:
1009 0
                case LINK.c:
1010 0
                    return mTYman_c;
1011

1012 0
                case LINK.d:
1013 0
                    return mTYman_d;
1014

1015 0
                case LINK.cpp:
1016 0
                    return mTYman_cpp;
1017

1018 0
                case LINK.default_:
1019 0
                case LINK.system:
1020 0
                    printf("linkage = %d\n", vd.linkage);
1021 0
                    assert(0);
1022
            }
1023
        }
1024
    }
1025

1026 1
    scope v = new ToObjFile(multiobj);
1027 1
    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 1
    bool hasError = false;
1041

1042 1
    foreach (i; cd.vtblOffset() .. cd.vtbl.dim)
1043
    {
1044 1
        FuncDeclaration fd = cd.vtbl[i].isFuncDeclaration();
1045

1046
        //printf("\tvtbl[%d] = %p\n", i, fd);
1047 1
        if (!fd || !fd.fbody && cd.isAbstract())
1048
        {
1049
            // Nothing to do
1050 1
            continue;
1051
        }
1052
        // Ensure function has a return value
1053
        // https://issues.dlang.org/show_bug.cgi?id=4869
1054 1
        if (!fd.functionSemantic())
1055
        {
1056 1
            hasError = true;
1057
        }
1058

1059 1
        if (!cd.isFuncHidden(fd) || fd.isFuture())
1060
        {
1061
            // All good, no name hiding to check for
1062 1
            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 1
        foreach (j; 1 .. cd.vtbl.dim)
1070
        {
1071 1
            if (j == i)
1072 1
                continue;
1073 1
            FuncDeclaration fd2 = cd.vtbl[j].isFuncDeclaration();
1074 1
            if (!fd2.ident.equals(fd.ident))
1075 1
                continue;
1076 1
            if (fd2.isFuture())
1077 0
                continue;
1078 1
            if (!fd.leastAsSpecialized(fd2) && !fd2.leastAsSpecialized(fd))
1079 1
                continue;
1080
            // Hiding detected: same name, overlapping specializations
1081 1
            TypeFunction tf = fd.type.toTypeFunction();
1082 1
            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 1
            hasError = true;
1090 1
            break;
1091
        }
1092
    }
1093

1094 1
    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 1
    uint csymoffset = target.classinfosize;    // must be ClassInfo.size
1107 1
    csymoffset += cd.vtblInterfaces.dim * (4 * target.ptrsize);
1108

1109 1
    for (size_t i = 0; i < cd.vtblInterfaces.dim; i++)
1110
    {
1111 1
        BaseClass *b = (*cd.vtblInterfaces)[i];
1112

1113 1
        if (b == bc)
1114 1
            return csymoffset;
1115 1
        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 1
    ClassDeclaration cd2;
1122

1123 1
    for (cd2 = cd.baseClass; cd2; cd2 = cd2.baseClass)
1124
    {
1125 1
        foreach (k; 0 .. cd2.vtblInterfaces.dim)
1126
        {
1127 1
            BaseClass *bs = (*cd2.vtblInterfaces)[k];
1128 1
            if (bs.fillVtbl(cd, null, 0))
1129
            {
1130 1
                if (bc == bs)
1131
                {
1132
                    //printf("\tcsymoffset = x%x\n", csymoffset);
1133 1
                    return csymoffset;
1134
                }
1135 1
                csymoffset += bs.sym.vtbl.dim * target.ptrsize;
1136
            }
1137
        }
1138
    }
1139

1140 1
    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 1
    ClassDeclaration id = b.sym;
1158

1159 1
    const id_vtbl_dim = id.vtbl.dim;
1160 1
    assert(id_vtbl_dim <= bvtbl.dim);
1161

1162 1
    size_t jstart = 0;
1163 1
    if (id.vtblOffset())
1164
    {
1165
        // First entry is struct Interface reference
1166 1
        dtb.xoff(toSymbol(pc), cast(uint)(target.classinfosize + k * (4 * target.ptrsize)), TYnptr);
1167 1
        jstart = 1;
1168
    }
1169

1170 1
    foreach (j; jstart .. id_vtbl_dim)
1171
    {
1172 1
        FuncDeclaration fd = bvtbl[j];
1173 1
        if (fd)
1174
        {
1175 1
            auto offset2 = b.offset;
1176 1
            if (fd.interfaceVirtual)
1177
            {
1178 0
                offset2 -= fd.interfaceVirtual.offset;
1179
            }
1180 1
            dtb.xoff(toThunkSymbol(fd, offset2), 0, TYnptr);
1181
        }
1182
        else
1183 1
            dtb.size(0);
1184
    }
1185 1
    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 1
    enum_SC scclass = SCcomdat;
1201 1
    cd.csym.Sclass = scclass;
1202 1
    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 1
    uint offset = target.classinfosize;    // must be ClassInfo.size
1225 1
    if (Type.typeinfoclass)
1226
    {
1227 1
        if (Type.typeinfoclass.structsize != target.classinfosize)
1228
        {
1229 0
            debug printf("target.classinfosize = x%x, Type.typeinfoclass.structsize = x%x\n", offset, Type.typeinfoclass.structsize);
1230 0
            cd.error("mismatch between dmd and object.d or object.di found. Check installation and import paths with -v compiler switch.");
1231 0
            fatal();
1232
        }
1233
    }
1234

1235 1
    auto dtb = DtBuilder(0);
1236

1237 1
    if (auto tic = Type.typeinfoclass)
1238
    {
1239 1
        dtb.xoff(toVtblSymbol(tic), 0, TYnptr); // vtbl for TypeInfo_Class : ClassInfo
1240 1
        if (tic.hasMonitor())
1241 1
            dtb.size(0);                        // monitor
1242
    }
1243
    else
1244
    {
1245 1
        dtb.size(0);                    // BUG: should be an assert()
1246 1
        dtb.size(0);                    // call hasMonitor()?
1247
    }
1248

1249
    // m_init[]
1250 1
    assert(cd.structsize >= 8 || (cd.classKind == ClassKind.cpp && cd.structsize >= 4));
1251 1
    dtb.size(cd.structsize);           // size
1252 1
    dtb.xoff(sinit, 0, TYnptr);         // initializer
1253

1254
    // name[]
1255 1
    const(char) *name = cd.ident.toChars();
1256 1
    size_t namelen = strlen(name);
1257 1
    if (!(namelen > 9 && memcmp(name, "TypeInfo_".ptr, 9) == 0))
1258
    {
1259 1
        name = cd.toPrettyChars();
1260 1
        namelen = strlen(name);
1261
    }
1262 1
    dtb.size(namelen);
1263 1
    dt_t *pdtname = dtb.xoffpatch(cd.csym, 0, TYnptr);
1264

1265
    // vtbl[]
1266 1
    dtb.size(cd.vtbl.dim);
1267 1
    if (cd.vtbl.dim)
1268 1
        dtb.xoff(cd.vtblsym.csym, 0, TYnptr);
1269
    else
1270 1
        dtb.size(0);
1271

1272
    // interfaces[]
1273 1
    dtb.size(cd.vtblInterfaces.dim);
1274 1
    if (cd.vtblInterfaces.dim)
1275 1
        dtb.xoff(cd.csym, offset, TYnptr);      // (*)
1276
    else
1277 1
        dtb.size(0);
1278

1279
    // base
1280 1
    if (cd.baseClass)
1281 1
        dtb.xoff(toSymbol(cd.baseClass), 0, TYnptr);
1282
    else
1283 1
        dtb.size(0);
1284

1285
    // destructor
1286 1
    if (cd.tidtor)
1287 1
        dtb.xoff(toSymbol(cd.tidtor), 0, TYnptr);
1288
    else
1289 1
        dtb.size(0);
1290

1291
    // classInvariant
1292 1
    if (cd.inv)
1293 1
        dtb.xoff(toSymbol(cd.inv), 0, TYnptr);
1294
    else
1295 1
        dtb.size(0);
1296

1297
    // flags
1298 1
    ClassFlags flags = ClassFlags.hasOffTi;
1299 1
    if (cd.isCOMclass()) flags |= ClassFlags.isCOMclass;
1300 1
    if (cd.isCPPclass()) flags |= ClassFlags.isCPPclass;
1301 1
    flags |= ClassFlags.hasGetMembers;
1302 1
    flags |= ClassFlags.hasTypeInfo;
1303 1
    if (cd.ctor)
1304 1
        flags |= ClassFlags.hasCtor;
1305 1
    for (ClassDeclaration pc = cd; pc; pc = pc.baseClass)
1306
    {
1307 1
        if (pc.dtor)
1308
        {
1309 1
            flags |= ClassFlags.hasDtor;
1310 1
            break;
1311
        }
1312
    }
1313 1
    if (cd.isAbstract())
1314 1
        flags |= ClassFlags.isAbstract;
1315

1316 1
    flags |= ClassFlags.noPointers;     // initially assume no pointers
1317
Louter:
1318 1
    for (ClassDeclaration pc = cd; pc; pc = pc.baseClass)
1319
    {
1320 1
        if (pc.members)
1321
        {
1322 1
            for (size_t i = 0; i < pc.members.dim; i++)
1323
            {
1324 1
                Dsymbol sm = (*pc.members)[i];
1325
                //printf("sm = %s %s\n", sm.kind(), sm.toChars());
1326 1
                if (sm.hasPointers())
1327
                {
1328 1
                    flags &= ~ClassFlags.noPointers;  // not no-how, not no-way
1329 1
                    break Louter;
1330
                }
1331
            }
1332
        }
1333
    }
1334 1
    dtb.size(flags);
1335

1336
    // deallocator
1337 1
    dtb.size(0);
1338

1339
    // offTi[]
1340 1
    dtb.size(0);
1341 1
    dtb.size(0);            // null for now, fix later
1342

1343
    // defaultConstructor
1344 1
    if (cd.defaultCtor && !(cd.defaultCtor.storage_class & STC.disable))
1345 1
        dtb.xoff(toSymbol(cd.defaultCtor), 0, TYnptr);
1346
    else
1347 1
        dtb.size(0);
1348

1349
    // m_RTInfo
1350 1
    if (cd.getRTInfo)
1351 1
        Expression_toDt(cd.getRTInfo, dtb);
1352 1
    else if (flags & ClassFlags.noPointers)
1353 1
        dtb.size(0);
1354
    else
1355 0
        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 1
    offset += cd.vtblInterfaces.dim * (4 * target.ptrsize);
1365 1
    for (size_t i = 0; i < cd.vtblInterfaces.dim; i++)
1366
    {
1367 1
        BaseClass *b = (*cd.vtblInterfaces)[i];
1368 1
        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 1
        b.fillVtbl(cd, &b.vtbl, 1);
1381

1382
        // classinfo
1383 1
        dtb.xoff(toSymbol(id), 0, TYnptr);
1384

1385
        // vtbl[]
1386 1
        dtb.size(id.vtbl.dim);
1387 1
        dtb.xoff(cd.csym, offset, TYnptr);
1388

1389
        // offset
1390 1
        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 1
    foreach (i; 0 .. cd.vtblInterfaces.dim)
1397
    {
1398 1
        BaseClass *b = (*cd.vtblInterfaces)[i];
1399 1
        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 1
    for (ClassDeclaration pc = cd.baseClass; pc; pc = pc.baseClass)
1406
    {
1407 1
        foreach (i; 0 .. pc.vtblInterfaces.dim)
1408
        {
1409 1
            BaseClass *b = (*pc.vtblInterfaces)[i];
1410 1
            FuncDeclarations bvtbl;
1411 1
            if (b.fillVtbl(cd, &bvtbl, 0))
1412
            {
1413 1
                offset += emitVtbl(dtb, b, bvtbl, pc, i);
1414
            }
1415
        }
1416
    }
1417

1418
    //////////////////////////////////////////////
1419

1420 1
    dtpatchoffset(pdtname, offset);
1421

1422 1
    dtb.nbytes(cast(uint)(namelen + 1), name);
1423 1
    const size_t namepad = -(namelen + 1) & (target.ptrsize - 1); // align
1424 1
    dtb.nzeros(cast(uint)namepad);
1425

1426 1
    cd.csym.Sdt = dtb.finish();
1427
    // ClassInfo cannot be const data, because we use the monitor on it
1428 1
    outdata(cd.csym);
1429 1
    if (cd.isExport())
1430 1
        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 1
    enum_SC scclass = SCcomdat;
1442

1443
    // Put out the ClassInfo
1444 1
    id.csym.Sclass = scclass;
1445 1
    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 1
    auto dtb = DtBuilder(0);
1468

1469 1
    if (auto tic = Type.typeinfoclass)
1470
    {
1471 1
        dtb.xoff(toVtblSymbol(tic), 0, TYnptr); // vtbl for ClassInfo
1472 1
        if (tic.hasMonitor())
1473 1
            dtb.size(0);                        // monitor
1474
    }
1475
    else
1476
    {
1477 1
        dtb.size(0);                    // BUG: should be an assert()
1478 1
        dtb.size(0);                    // call hasMonitor()?
1479
    }
1480

1481
    // m_init[]
1482 1
    dtb.size(0);                        // size
1483 1
    dtb.size(0);                        // initializer
1484

1485
    // name[]
1486 1
    const(char) *name = id.toPrettyChars();
1487 1
    size_t namelen = strlen(name);
1488 1
    dtb.size(namelen);
1489 1
    dt_t *pdtname = dtb.xoffpatch(id.csym, 0, TYnptr);
1490

1491
    // vtbl[]
1492 1
    dtb.size(0);
1493 1
    dtb.size(0);
1494

1495
    // interfaces[]
1496 1
    uint offset = target.classinfosize;
1497 1
    dtb.size(id.vtblInterfaces.dim);
1498 1
    if (id.vtblInterfaces.dim)
1499
    {
1500 1
        if (Type.typeinfoclass)
1501
        {
1502 1
            if (Type.typeinfoclass.structsize != offset)
1503
            {
1504 0
                id.error("mismatch between dmd and object.d or object.di found. Check installation and import paths with -v compiler switch.");
1505 0
                fatal();
1506
            }
1507
        }
1508 1
        dtb.xoff(id.csym, offset, TYnptr);      // (*)
1509
    }
1510
    else
1511
    {
1512 1
        dtb.size(0);
1513
    }
1514

1515
    // base
1516 1
    assert(!id.baseClass);
1517 1
    dtb.size(0);
1518

1519
    // destructor
1520 1
    dtb.size(0);
1521

1522
    // classInvariant
1523 1
    dtb.size(0);
1524

1525
    // flags
1526 1
    ClassFlags flags = ClassFlags.hasOffTi | ClassFlags.hasTypeInfo;
1527 1
    if (id.isCOMinterface()) flags |= ClassFlags.isCOMclass;
1528 1
    dtb.size(flags);
1529

1530
    // deallocator
1531 1
    dtb.size(0);
1532

1533
    // offTi[]
1534 1
    dtb.size(0);
1535 1
    dtb.size(0);            // null for now, fix later
1536

1537
    // defaultConstructor
1538 1
    dtb.size(0);
1539

1540
    // xgetMembers
1541
    //dtb.size(0);
1542

1543
    // m_RTInfo
1544 1
    if (id.getRTInfo)
1545 1
        Expression_toDt(id.getRTInfo, dtb);
1546
    else
1547 1
        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 1
    offset += id.vtblInterfaces.dim * (4 * target.ptrsize);
1557 1
    for (size_t i = 0; i < id.vtblInterfaces.dim; i++)
1558
    {
1559 1
        BaseClass *b = (*id.vtblInterfaces)[i];
1560 1
        ClassDeclaration base = b.sym;
1561

1562
        // classinfo
1563 1
        dtb.xoff(toSymbol(base), 0, TYnptr);
1564

1565
        // vtbl[]
1566 1
        dtb.size(0);
1567 1
        dtb.size(0);
1568

1569
        // offset
1570 1
        dtb.size(b.offset);
1571
    }
1572

1573
    //////////////////////////////////////////////
1574

1575 1
    dtpatchoffset(pdtname, offset);
1576

1577 1
    dtb.nbytes(cast(uint)(namelen + 1), name);
1578 1
    const size_t namepad =  -(namelen + 1) & (target.ptrsize - 1); // align
1579 1
    dtb.nzeros(cast(uint)namepad);
1580

1581 1
    id.csym.Sdt = dtb.finish();
1582 1
    out_readonly(id.csym);
1583 1
    outdata(id.csym);
1584 1
    if (id.isExport())
1585 1
        objmod.export_symbol(id.csym, 0);
1586
}

Read our documentation on viewing source code .

Loading