Symbol *objc_getCString(const char *str, size_t len, const char *symbolName, ObjcSegment segment) { objc_hasSymbols = true; // create data dt_t *dt = NULL; dtnbytes(&dt, len + 1, str); // find segment int seg = objc_getSegment(segment); // create symbol Symbol *s; s = symbol_name(symbolName, SCstatic, type_allocn(TYarray, tschar)); s->Sdt = dt; s->Sseg = seg; return s; }
void Module::genobjfile(int multiobj) { //EEcontext *ee = env->getEEcontext(); //printf("Module::genobjfile(multiobj = %d) %s\n", multiobj, toChars()); lastmname = srcfile->toChars(); obj_initfile(lastmname, NULL, toPrettyChars()); eictor = NULL; ictorlocalgot = NULL; ector = NULL; ectorgates.setDim(0); edtor = NULL; etest = NULL; dtorcount = 0; if (doppelganger) { /* Generate a reference to the moduleinfo, so the module constructors * and destructors get linked in. */ Module *m = (Module *)aimports.data[0]; assert(m); if (m->sictor || m->sctor || m->sdtor) { Symbol *s = m->toSymbol(); //objextern(s); //if (!s->Sxtrnnum) objextdef(s->Sident); if (!s->Sxtrnnum) { //printf("%s\n", s->Sident); #if 0 /* This should work, but causes optlink to fail in common/newlib.asm */ objextdef(s->Sident); #else #if ELFOBJ || MACHOBJ int nbytes = reftoident(DATA, Offset(DATA), s, 0, CFoff); Offset(DATA) += nbytes; #else int nbytes = reftoident(DATA, Doffset, s, 0, CFoff); Doffset += nbytes; #endif #endif } } } if (global.params.cov) { /* Create coverage identifier: * private uint[numlines] __coverage; */ cov = symbol_calloc("__coverage"); cov->Stype = type_fake(TYint); cov->Stype->Tmangle = mTYman_c; cov->Stype->Tcount++; cov->Sclass = SCstatic; cov->Sfl = FLdata; #if ELFOBJ || MACHOBJ cov->Sseg = UDATA; #endif dtnzeros(&cov->Sdt, 4 * numlines); outdata(cov); slist_add(cov); covb = (unsigned *)calloc((numlines + 32) / 32, sizeof(*covb)); } for (int i = 0; i < members->dim; i++) { Dsymbol *member = (Dsymbol *)members->data[i]; member->toObjFile(multiobj); } if (global.params.cov) { /* Generate * bit[numlines] __bcoverage; */ Symbol *bcov = symbol_calloc("__bcoverage"); bcov->Stype = type_fake(TYuint); bcov->Stype->Tcount++; bcov->Sclass = SCstatic; bcov->Sfl = FLdata; #if ELFOBJ || MACHOBJ bcov->Sseg = DATA; #endif dtnbytes(&bcov->Sdt, (numlines + 32) / 32 * sizeof(*covb), (char *)covb); outdata(bcov); free(covb); covb = NULL; /* Generate: * _d_cover_register(uint[] __coverage, BitArray __bcoverage, string filename); * and prepend it to the static constructor. */ /* t will be the type of the functions generated: * extern (C) void func(); */ type *t = type_alloc(TYnfunc); t->Tflags |= TFprototype | TFfixed; t->Tmangle = mTYman_c; t->Tnext = tsvoid; tsvoid->Tcount++; sictor = toSymbolX("__modictor", SCglobal, t, "FZv"); cstate.CSpsymtab = &sictor->Sfunc->Flocsym; localgot = ictorlocalgot; elem *e; e = el_params(el_ptr(cov), el_long(TYuint, numlines), el_ptr(bcov), el_long(TYuint, numlines), toEfilename(), NULL); e = el_bin(OPcall, TYvoid, el_var(rtlsym[RTLSYM_DCOVER]), e); eictor = el_combine(e, eictor); ictorlocalgot = localgot; } // If coverage / static constructor / destructor / unittest calls if (eictor || ector || ectorgates.dim || edtor || etest) { /* t will be the type of the functions generated: * extern (C) void func(); */ type *t = type_alloc(TYnfunc); t->Tflags |= TFprototype | TFfixed; t->Tmangle = mTYman_c; t->Tnext = tsvoid; tsvoid->Tcount++; static char moddeco[] = "FZv"; if (eictor) { localgot = ictorlocalgot; block *b = block_calloc(); b->BC = BCret; b->Belem = eictor; sictor->Sfunc->Fstartblock = b; writefunc(sictor); } if (ector || ectorgates.dim) { localgot = NULL; sctor = toSymbolX("__modctor", SCglobal, t, moddeco); cstate.CSpsymtab = &sctor->Sfunc->Flocsym; for (int i = 0; i < ectorgates.dim; i++) { StaticDtorDeclaration *f = (StaticDtorDeclaration *)ectorgates.data[i]; Symbol *s = f->vgate->toSymbol(); elem *e = el_var(s); e = el_bin(OPaddass, TYint, e, el_long(TYint, 1)); ector = el_combine(ector, e); } block *b = block_calloc(); b->BC = BCret; b->Belem = ector; sctor->Sfunc->Fstartblock = b; writefunc(sctor); #if STATICCTOR obj_staticctor(sctor, dtorcount, 1); #endif } if (edtor) { localgot = NULL; sdtor = toSymbolX("__moddtor", SCglobal, t, moddeco); block *b = block_calloc(); b->BC = BCret; b->Belem = edtor; sdtor->Sfunc->Fstartblock = b; writefunc(sdtor); } if (etest) { localgot = NULL; stest = toSymbolX("__modtest", SCglobal, t, moddeco); block *b = block_calloc(); b->BC = BCret; b->Belem = etest; stest->Sfunc->Fstartblock = b; writefunc(stest); } if (doppelganger) genmoduleinfo(); } if (doppelganger) { obj_termfile(); return; } if (global.params.multiobj) { /* This is necessary because the main .obj for this module is written * first, but determining whether marray or massert are needed is done * possibly later in the doppelganger modules. * Another way to fix it is do the main one last. */ toModuleAssert(); toModuleArray(); } // If module assert for (int i = 0; i < 2; i++) { Symbol *ma = i ? marray : massert; if (ma) { elem *elinnum; elem *efilename; localgot = NULL; // Call dassert(filename, line) // Get sole parameter, linnum { Symbol *sp; sp = symbol_calloc("linnum"); sp->Stype = type_fake(TYint); sp->Stype->Tcount++; sp->Sclass = SCfastpar; sp->Spreg = AX; sp->Sflags &= ~SFLspill; sp->Sfl = FLpara; // FLauto? cstate.CSpsymtab = &ma->Sfunc->Flocsym; symbol_add(sp); elinnum = el_var(sp); } efilename = toEmodulename(); elem *e = el_var(rtlsym[i ? RTLSYM_DARRAY : RTLSYM_DASSERT]); e = el_bin(OPcall, TYvoid, e, el_param(elinnum, efilename)); block *b = block_calloc(); b->BC = BCret; b->Belem = e; ma->Sfunc->Fstartblock = b; ma->Sclass = SCglobal; ma->Sfl = 0; writefunc(ma); } } #if 1 // Always generate module info, because of templates and -cov if (1 || needModuleInfo()) genmoduleinfo(); #endif obj_termfile(); }
void genObjFile(Module *m, bool multiobj) { //EEcontext *ee = env->getEEcontext(); //printf("Module::genobjfile(multiobj = %d) %s\n", multiobj, m->toChars()); if (m->ident == Id::entrypoint) { bool v = global.params.verbose; global.params.verbose = false; for (size_t i = 0; i < m->members->dim; i++) { Dsymbol *member = (*m->members)[i]; //printf("toObjFile %s %s\n", member->kind(), member->toChars()); toObjFile(member, global.params.multiobj); } global.params.verbose = v; return; } lastmname = m->srcfile->toChars(); objmod->initfile(lastmname, NULL, m->toPrettyChars()); eictor = NULL; ictorlocalgot = NULL; sctors.setDim(0); ectorgates.setDim(0); sdtors.setDim(0); ssharedctors.setDim(0); esharedctorgates.setDim(0); sshareddtors.setDim(0); stests.setDim(0); if (m->doppelganger) { /* Generate a reference to the moduleinfo, so the module constructors * and destructors get linked in. */ Module *mod = m->aimports[0]; assert(mod); if (mod->sictor || mod->sctor || mod->sdtor || mod->ssharedctor || mod->sshareddtor) { Symbol *s = toSymbol(mod); //objextern(s); //if (!s->Sxtrnnum) objextdef(s->Sident); if (!s->Sxtrnnum) { //printf("%s\n", s->Sident); #if 0 /* This should work, but causes optlink to fail in common/newlib.asm */ objextdef(s->Sident); #else Symbol *sref = symbol_generate(SCstatic, type_fake(TYnptr)); sref->Sfl = FLdata; dtxoff(&sref->Sdt, s, 0, TYnptr); outdata(sref); #endif } } } if (global.params.cov) { /* Create coverage identifier: * private uint[numlines] __coverage; */ m->cov = symbol_calloc("__coverage"); m->cov->Stype = type_fake(TYint); m->cov->Stype->Tmangle = mTYman_c; m->cov->Stype->Tcount++; m->cov->Sclass = SCstatic; m->cov->Sfl = FLdata; dtnzeros(&m->cov->Sdt, 4 * m->numlines); outdata(m->cov); slist_add(m->cov); m->covb = (unsigned *)calloc((m->numlines + 32) / 32, sizeof(*m->covb)); } for (size_t i = 0; i < m->members->dim; i++) { Dsymbol *member = (*m->members)[i]; //printf("toObjFile %s %s\n", member->kind(), member->toChars()); toObjFile(member, multiobj); } if (global.params.cov) { /* Generate * bit[numlines] __bcoverage; */ Symbol *bcov = symbol_calloc("__bcoverage"); bcov->Stype = type_fake(TYuint); bcov->Stype->Tcount++; bcov->Sclass = SCstatic; bcov->Sfl = FLdata; dtnbytes(&bcov->Sdt, (m->numlines + 32) / 32 * sizeof(*m->covb), (char *)m->covb); outdata(bcov); free(m->covb); m->covb = NULL; /* Generate: * _d_cover_register(uint[] __coverage, BitArray __bcoverage, string filename); * and prepend it to the static constructor. */ /* t will be the type of the functions generated: * extern (C) void func(); */ type *t = type_function(TYnfunc, NULL, 0, false, tsvoid); t->Tmangle = mTYman_c; m->sictor = toSymbolX(m, "__modictor", SCglobal, t, "FZv"); cstate.CSpsymtab = &m->sictor->Sfunc->Flocsym; localgot = ictorlocalgot; elem *ecov = el_pair(TYdarray, el_long(TYsize_t, m->numlines), el_ptr(m->cov)); elem *ebcov = el_pair(TYdarray, el_long(TYsize_t, m->numlines), el_ptr(bcov)); if (config.exe == EX_WIN64) { ecov = addressElem(ecov, Type::tvoid->arrayOf(), false); ebcov = addressElem(ebcov, Type::tvoid->arrayOf(), false); } elem *efilename = toEfilename(m); if (config.exe == EX_WIN64) efilename = addressElem(efilename, Type::tstring, true); elem *e = el_params( el_long(TYuchar, global.params.covPercent), ecov, ebcov, efilename, NULL); e = el_bin(OPcall, TYvoid, el_var(rtlsym[RTLSYM_DCOVER2]), e); eictor = el_combine(e, eictor); ictorlocalgot = localgot; } // If coverage / static constructor / destructor / unittest calls if (eictor || sctors.dim || ectorgates.dim || sdtors.dim || ssharedctors.dim || esharedctorgates.dim || sshareddtors.dim || stests.dim) { if (eictor) { localgot = ictorlocalgot; block *b = block_calloc(); b->BC = BCret; b->Belem = eictor; m->sictor->Sfunc->Fstartline.Sfilename = m->arg; m->sictor->Sfunc->Fstartblock = b; writefunc(m->sictor); } m->sctor = callFuncsAndGates(m, &sctors, &ectorgates, "__modctor"); m->sdtor = callFuncsAndGates(m, &sdtors, NULL, "__moddtor"); m->ssharedctor = callFuncsAndGates(m, &ssharedctors, (StaticDtorDeclarations *)&esharedctorgates, "__modsharedctor"); m->sshareddtor = callFuncsAndGates(m, &sshareddtors, NULL, "__modshareddtor"); m->stest = callFuncsAndGates(m, &stests, NULL, "__modtest"); if (m->doppelganger) genModuleInfo(m); } if (m->doppelganger) { objmod->termfile(); return; } if (global.params.multiobj) { /* This is necessary because the main .obj for this module is written * first, but determining whether marray or massert or munittest are needed is done * possibly later in the doppelganger modules. * Another way to fix it is do the main one last. */ toModuleAssert(m); toModuleUnittest(m); toModuleArray(m); } /* Always generate module info, because of templates and -cov. * But module info needs the runtime library, so disable it for betterC. */ if (!global.params.betterC /*|| needModuleInfo()*/) genModuleInfo(m); genhelpers(m, false); objmod->termfile(); }
void TypeInfoStructDeclaration::toDt(dt_t **pdt) { //printf("TypeInfoStructDeclaration::toDt() '%s'\n", toChars()); unsigned offset = Type::typeinfostruct->structsize; dtxoff(pdt, Type::typeinfostruct->toVtblSymbol(), 0, TYnptr); // vtbl for TypeInfo_Struct dtsize_t(pdt, 0); // monitor assert(tinfo->ty == Tstruct); TypeStruct *tc = (TypeStruct *)tinfo; StructDeclaration *sd = tc->sym; /* Put out: * char[] name; * void[] init; * hash_t function(in void*) xtoHash; * bool function(in void*, in void*) xopEquals; * int function(in void*, in void*) xopCmp; * string function(const(void)*) xtoString; * uint m_flags; * xgetMembers; * xdtor; * xpostblit; * uint m_align; * version (X86_64) * TypeInfo m_arg1; * TypeInfo m_arg2; * * name[] */ const char *name = sd->toPrettyChars(); size_t namelen = strlen(name); dtsize_t(pdt, namelen); //dtabytes(pdt, TYnptr, 0, namelen + 1, name); dtxoff(pdt, toSymbol(), offset, TYnptr); offset += namelen + 1; // void[] init; dtsize_t(pdt, sd->structsize); // init.length if (sd->zeroInit) dtsize_t(pdt, 0); // NULL for 0 initialization else dtxoff(pdt, sd->toInitializer(), 0, TYnptr); // init.ptr FuncDeclaration *fd; FuncDeclaration *fdx; TypeFunction *tf; Type *ta; Dsymbol *s; static TypeFunction *tftohash; static TypeFunction *tftostring; if (!tftohash) { Scope sc; tftohash = new TypeFunction(NULL, Type::thash_t, 0, LINKd); tftohash->mod = MODconst; tftohash = (TypeFunction *)tftohash->semantic(0, &sc); tftostring = new TypeFunction(NULL, Type::tchar->invariantOf()->arrayOf(), 0, LINKd); tftostring = (TypeFunction *)tftostring->semantic(0, &sc); } TypeFunction *tfcmpptr; { Scope sc; Parameters *arguments = new Parameters; #if STRUCTTHISREF // arg type is ref const T Parameter *arg = new Parameter(STCref, tc->constOf(), NULL, NULL); #else // arg type is const T* Parameter *arg = new Parameter(STCin, tc->pointerTo(), NULL, NULL); #endif arguments->push(arg); tfcmpptr = new TypeFunction(arguments, Type::tint32, 0, LINKd); tfcmpptr->mod = MODconst; tfcmpptr = (TypeFunction *)tfcmpptr->semantic(0, &sc); } s = search_function(sd, Id::tohash); fdx = s ? s->isFuncDeclaration() : NULL; if (fdx) { fd = fdx->overloadExactMatch(tftohash); if (fd) dtxoff(pdt, fd->toSymbol(), 0, TYnptr); else //fdx->error("must be declared as extern (D) uint toHash()"); dtsize_t(pdt, 0); } else dtsize_t(pdt, 0); if (sd->eq) dtxoff(pdt, sd->eq->toSymbol(), 0, TYnptr); else dtsize_t(pdt, 0); s = search_function(sd, Id::cmp); fdx = s ? s->isFuncDeclaration() : NULL; if (fdx) { //printf("test1 %s, %s, %s\n", fdx->toChars(), fdx->type->toChars(), tfeqptr->toChars()); fd = fdx->overloadExactMatch(tfcmpptr); if (fd) { dtxoff(pdt, fd->toSymbol(), 0, TYnptr); //printf("test2\n"); } else //fdx->error("must be declared as extern (D) int %s(%s*)", fdx->toChars(), sd->toChars()); dtsize_t(pdt, 0); } else dtsize_t(pdt, 0); s = search_function(sd, Id::tostring); fdx = s ? s->isFuncDeclaration() : NULL; if (fdx) { fd = fdx->overloadExactMatch(tftostring); if (fd) dtxoff(pdt, fd->toSymbol(), 0, TYnptr); else //fdx->error("must be declared as extern (D) char[] toString()"); dtsize_t(pdt, 0); } else dtsize_t(pdt, 0); // uint m_flags; dtsize_t(pdt, tc->hasPointers()); #if DMDV2 // xgetMembers FuncDeclaration *sgetmembers = sd->findGetMembers(); if (sgetmembers) dtxoff(pdt, sgetmembers->toSymbol(), 0, TYnptr); else dtsize_t(pdt, 0); // xgetMembers // xdtor FuncDeclaration *sdtor = sd->dtor; if (sdtor) dtxoff(pdt, sdtor->toSymbol(), 0, TYnptr); else dtsize_t(pdt, 0); // xdtor // xpostblit FuncDeclaration *spostblit = sd->postblit; if (spostblit && !(spostblit->storage_class & STCdisable)) dtxoff(pdt, spostblit->toSymbol(), 0, TYnptr); else dtsize_t(pdt, 0); // xpostblit #endif // uint m_align; dtsize_t(pdt, tc->alignsize()); if (global.params.is64bit) { TypeTuple *tup = tc->toArgTypes(); assert(tup->arguments->dim <= 2); for (int i = 0; i < 2; i++) { if (i < tup->arguments->dim) { Type *targ = (tup->arguments->tdata()[i])->type; targ = targ->merge(); targ->getTypeInfo(NULL); dtxoff(pdt, targ->vtinfo->toSymbol(), 0, TYnptr); // m_argi } else dtsize_t(pdt, 0); // m_argi } } // name[] dtnbytes(pdt, namelen + 1, name); }
void genModuleInfo(Module *m) { //printf("Module::genmoduleinfo() %s\n", m->toChars()); if (!Module::moduleinfo) { ObjectNotFound(Id::ModuleInfo); } Symbol *msym = toSymbol(m); ////////////////////////////////////////////// m->csym->Sclass = SCglobal; m->csym->Sfl = FLdata; dt_t *dt = NULL; ClassDeclarations aclasses; //printf("members->dim = %d\n", members->dim); for (size_t i = 0; i < m->members->dim; i++) { Dsymbol *member = (*m->members)[i]; //printf("\tmember '%s'\n", member->toChars()); member->addLocalClass(&aclasses); } // importedModules[] size_t aimports_dim = m->aimports.dim; for (size_t i = 0; i < m->aimports.dim; i++) { Module *mod = m->aimports[i]; if (!mod->needmoduleinfo) aimports_dim--; } FuncDeclaration *sgetmembers = m->findGetMembers(); // These must match the values in druntime/src/object_.d #define MIstandalone 0x4 #define MItlsctor 0x8 #define MItlsdtor 0x10 #define MIctor 0x20 #define MIdtor 0x40 #define MIxgetMembers 0x80 #define MIictor 0x100 #define MIunitTest 0x200 #define MIimportedModules 0x400 #define MIlocalClasses 0x800 #define MIname 0x1000 unsigned flags = 0; if (!m->needmoduleinfo) flags |= MIstandalone; if (m->sctor) flags |= MItlsctor; if (m->sdtor) flags |= MItlsdtor; if (m->ssharedctor) flags |= MIctor; if (m->sshareddtor) flags |= MIdtor; if (sgetmembers) flags |= MIxgetMembers; if (m->sictor) flags |= MIictor; if (m->stest) flags |= MIunitTest; if (aimports_dim) flags |= MIimportedModules; if (aclasses.dim) flags |= MIlocalClasses; flags |= MIname; dtdword(&dt, flags); // _flags dtdword(&dt, 0); // _index if (flags & MItlsctor) dtxoff(&dt, m->sctor, 0, TYnptr); if (flags & MItlsdtor) dtxoff(&dt, m->sdtor, 0, TYnptr); if (flags & MIctor) dtxoff(&dt, m->ssharedctor, 0, TYnptr); if (flags & MIdtor) dtxoff(&dt, m->sshareddtor, 0, TYnptr); if (flags & MIxgetMembers) dtxoff(&dt, toSymbol(sgetmembers), 0, TYnptr); if (flags & MIictor) dtxoff(&dt, m->sictor, 0, TYnptr); if (flags & MIunitTest) dtxoff(&dt, m->stest, 0, TYnptr); if (flags & MIimportedModules) { dtsize_t(&dt, aimports_dim); for (size_t i = 0; i < m->aimports.dim; i++) { Module *mod = m->aimports[i]; if (!mod->needmoduleinfo) continue; Symbol *s = toSymbol(mod); /* Weak references don't pull objects in from the library, * they resolve to 0 if not pulled in by something else. * Don't pull in a module just because it was imported. */ s->Sflags |= SFLweak; dtxoff(&dt, s, 0, TYnptr); } } if (flags & MIlocalClasses) { dtsize_t(&dt, aclasses.dim); for (size_t i = 0; i < aclasses.dim; i++) { ClassDeclaration *cd = aclasses[i]; dtxoff(&dt, toSymbol(cd), 0, TYnptr); } } if (flags & MIname) { // Put out module name as a 0-terminated string, to save bytes m->nameoffset = dt_size(dt); const char *name = m->toPrettyChars(); m->namelen = strlen(name); dtnbytes(&dt, m->namelen + 1, name); //printf("nameoffset = x%x\n", nameoffset); } objc_Module_genmoduleinfo_classes(); m->csym->Sdt = dt; out_readonly(m->csym); outdata(m->csym); ////////////////////////////////////////////// objmod->moduleinfo(msym); }
void visit(InterfaceDeclaration *id) { //printf("InterfaceDeclaration::toObjFile('%s')\n", id->toChars()); if (id->type->ty == Terror) { id->error("had semantic errors when compiling"); return; } if (!id->members) return; if (global.params.symdebug) toDebug(id); enum_SC scclass = SCglobal; if (id->isInstantiated()) scclass = SCcomdat; // Put out the members for (size_t i = 0; i < id->members->dim; i++) { Dsymbol *member = (*id->members)[i]; visitNoMultiObj(member); } // Generate C symbols toSymbol(id); ////////////////////////////////////////////// // Put out the TypeInfo genTypeInfo(id->type, NULL); id->type->vtinfo->accept(this); ////////////////////////////////////////////// // Put out the ClassInfo id->csym->Sclass = scclass; id->csym->Sfl = FLdata; /* The layout is: { void **vptr; monitor_t monitor; byte[] initializer; // static initialization data char[] name; // class name void *[] vtbl; Interface[] interfaces; Object *base; // base class void *destructor; void *invariant; // class invariant uint flags; void *deallocator; OffsetTypeInfo[] offTi; void *defaultConstructor; //const(MemberInfo[]) function(string) xgetMembers; // module getMembers() function void* xgetRTInfo; //TypeInfo typeinfo; } */ dt_t *dt = NULL; if (Type::typeinfoclass) dtxoff(&dt, toVtblSymbol(Type::typeinfoclass), 0, TYnptr); // vtbl for ClassInfo else dtsize_t(&dt, 0); // BUG: should be an assert() dtsize_t(&dt, 0); // monitor // initializer[] dtsize_t(&dt, 0); // size dtsize_t(&dt, 0); // initializer // name[] const char *name = id->toPrettyChars(); size_t namelen = strlen(name); dt_t **pdtname = dtsize_t(&dt, namelen); dtxoff(&dt, id->csym, 0, TYnptr); // vtbl[] dtsize_t(&dt, 0); dtsize_t(&dt, 0); // (*vtblInterfaces)[] unsigned offset = Target::classinfosize; dtsize_t(&dt, id->vtblInterfaces->dim); if (id->vtblInterfaces->dim) { if (Type::typeinfoclass) { if (Type::typeinfoclass->structsize != offset) { id->error("mismatch between dmd and object.d or object.di found. Check installation and import paths with -v compiler switch."); fatal(); } } dtxoff(&dt, id->csym, offset, TYnptr); // (*) } else { dtsize_t(&dt, 0); } // base assert(!id->baseClass); dtsize_t(&dt, 0); // dtor dtsize_t(&dt, 0); // invariant dtsize_t(&dt, 0); // flags ClassFlags::Type flags = ClassFlags::hasOffTi | ClassFlags::hasTypeInfo; if (id->isCOMinterface()) flags |= ClassFlags::isCOMclass; dtsize_t(&dt, flags); // deallocator dtsize_t(&dt, 0); // offTi[] dtsize_t(&dt, 0); dtsize_t(&dt, 0); // null for now, fix later // defaultConstructor dtsize_t(&dt, 0); // xgetMembers //dtsize_t(&dt, 0); // xgetRTInfo // xgetRTInfo if (id->getRTInfo) Expression_toDt(id->getRTInfo, &dt); else dtsize_t(&dt, 0); // no pointers //dtxoff(&dt, toSymbol(id->type->vtinfo), 0, TYnptr); // typeinfo ////////////////////////////////////////////// // Put out (*vtblInterfaces)[]. Must immediately follow csym, because // of the fixup (*) offset += id->vtblInterfaces->dim * (4 * Target::ptrsize); for (size_t i = 0; i < id->vtblInterfaces->dim; i++) { BaseClass *b = (*id->vtblInterfaces)[i]; ClassDeclaration *base = b->sym; // ClassInfo dtxoff(&dt, toSymbol(base), 0, TYnptr); // vtbl[] dtsize_t(&dt, 0); dtsize_t(&dt, 0); // this offset dtsize_t(&dt, b->offset); } ////////////////////////////////////////////// dtpatchoffset(*pdtname, offset); dtnbytes(&dt, namelen + 1, name); const size_t namepad = -(namelen + 1) & (Target::ptrsize - 1); // align dtnzeros(&dt, namepad); id->csym->Sdt = dt; out_readonly(id->csym); outdata(id->csym); if (id->isExport()) objmod->export_symbol(id->csym, 0); }
void visit(ClassDeclaration *cd) { //printf("ClassDeclaration::toObjFile('%s')\n", cd->toChars()); if (cd->type->ty == Terror) { cd->error("had semantic errors when compiling"); return; } if (!cd->members) return; if (multiobj && !cd->hasStaticCtorOrDtor()) { obj_append(cd); return; } if (global.params.symdebug) toDebug(cd); assert(!cd->scope); // semantic() should have been run to completion enum_SC scclass = SCglobal; if (cd->isInstantiated()) scclass = SCcomdat; // Put out the members for (size_t i = 0; i < cd->members->dim; i++) { Dsymbol *member = (*cd->members)[i]; /* There might be static ctors in the members, and they cannot * be put in separate obj files. */ member->accept(this); } // Generate C symbols toSymbol(cd); toVtblSymbol(cd); Symbol *sinit = toInitializer(cd); ////////////////////////////////////////////// // Generate static initializer sinit->Sclass = scclass; sinit->Sfl = FLdata; ClassDeclaration_toDt(cd, &sinit->Sdt); out_readonly(sinit); outdata(sinit); ////////////////////////////////////////////// // Put out the TypeInfo genTypeInfo(cd->type, NULL); //toObjFile(cd->type->vtinfo, multiobj); ////////////////////////////////////////////// // Put out the ClassInfo cd->csym->Sclass = scclass; cd->csym->Sfl = FLdata; /* The layout is: { void **vptr; monitor_t monitor; byte[] initializer; // static initialization data char[] name; // class name void *[] vtbl; Interface[] interfaces; ClassInfo *base; // base class void *destructor; void *invariant; // class invariant ClassFlags flags; void *deallocator; OffsetTypeInfo[] offTi; void *defaultConstructor; //const(MemberInfo[]) function(string) xgetMembers; // module getMembers() function void *xgetRTInfo; //TypeInfo typeinfo; } */ dt_t *dt = NULL; unsigned offset = Target::classinfosize; // must be ClassInfo.size if (Type::typeinfoclass) { if (Type::typeinfoclass->structsize != Target::classinfosize) { #ifdef DEBUG printf("Target::classinfosize = x%x, Type::typeinfoclass->structsize = x%x\n", offset, Type::typeinfoclass->structsize); #endif cd->error("mismatch between dmd and object.d or object.di found. Check installation and import paths with -v compiler switch."); fatal(); } } if (Type::typeinfoclass) dtxoff(&dt, toVtblSymbol(Type::typeinfoclass), 0, TYnptr); // vtbl for ClassInfo else dtsize_t(&dt, 0); // BUG: should be an assert() dtsize_t(&dt, 0); // monitor // initializer[] assert(cd->structsize >= 8 || (cd->cpp && cd->structsize >= 4)); dtsize_t(&dt, cd->structsize); // size dtxoff(&dt, sinit, 0, TYnptr); // initializer // name[] const char *name = cd->ident->toChars(); size_t namelen = strlen(name); if (!(namelen > 9 && memcmp(name, "TypeInfo_", 9) == 0)) { name = cd->toPrettyChars(); namelen = strlen(name); } dt_t **pdtname = dtsize_t(&dt, namelen); dtxoff(&dt, cd->csym, 0, TYnptr); // vtbl[] dtsize_t(&dt, cd->vtbl.dim); dtxoff(&dt, cd->vtblsym, 0, TYnptr); // interfaces[] dtsize_t(&dt, cd->vtblInterfaces->dim); if (cd->vtblInterfaces->dim) dtxoff(&dt, cd->csym, offset, TYnptr); // (*) else dtsize_t(&dt, 0); // base if (cd->baseClass) dtxoff(&dt, toSymbol(cd->baseClass), 0, TYnptr); else dtsize_t(&dt, 0); // destructor if (cd->dtor) dtxoff(&dt, toSymbol(cd->dtor), 0, TYnptr); else dtsize_t(&dt, 0); // invariant if (cd->inv) dtxoff(&dt, toSymbol(cd->inv), 0, TYnptr); else dtsize_t(&dt, 0); // flags ClassFlags::Type flags = ClassFlags::hasOffTi; if (cd->isCOMclass()) flags |= ClassFlags::isCOMclass; if (cd->isCPPclass()) flags |= ClassFlags::isCPPclass; flags |= ClassFlags::hasGetMembers; flags |= ClassFlags::hasTypeInfo; if (cd->ctor) flags |= ClassFlags::hasCtor; for (ClassDeclaration *pc = cd; pc; pc = pc->baseClass) { if (pc->dtor) { flags |= ClassFlags::hasDtor; break; } } if (cd->isabstract) flags |= ClassFlags::isAbstract; for (ClassDeclaration *pc = cd; pc; pc = pc->baseClass) { if (pc->members) { for (size_t i = 0; i < pc->members->dim; i++) { Dsymbol *sm = (*pc->members)[i]; //printf("sm = %s %s\n", sm->kind(), sm->toChars()); if (sm->hasPointers()) goto L2; } } } flags |= ClassFlags::noPointers; L2: dtsize_t(&dt, flags); // deallocator if (cd->aggDelete) dtxoff(&dt, toSymbol(cd->aggDelete), 0, TYnptr); else dtsize_t(&dt, 0); // offTi[] dtsize_t(&dt, 0); dtsize_t(&dt, 0); // null for now, fix later // defaultConstructor if (cd->defaultCtor && !(cd->defaultCtor->storage_class & STCdisable)) dtxoff(&dt, toSymbol(cd->defaultCtor), 0, TYnptr); else dtsize_t(&dt, 0); // xgetRTInfo if (cd->getRTInfo) Expression_toDt(cd->getRTInfo, &dt); else if (flags & ClassFlags::noPointers) dtsize_t(&dt, 0); else dtsize_t(&dt, 1); //dtxoff(&dt, toSymbol(type->vtinfo), 0, TYnptr); // typeinfo ////////////////////////////////////////////// // Put out (*vtblInterfaces)[]. Must immediately follow csym, because // of the fixup (*) offset += cd->vtblInterfaces->dim * (4 * Target::ptrsize); for (size_t i = 0; i < cd->vtblInterfaces->dim; i++) { BaseClass *b = (*cd->vtblInterfaces)[i]; ClassDeclaration *id = b->sym; /* The layout is: * struct Interface * { * ClassInfo *interface; * void *[] vtbl; * size_t offset; * } */ // Fill in vtbl[] b->fillVtbl(cd, &b->vtbl, 1); dtxoff(&dt, toSymbol(id), 0, TYnptr); // ClassInfo // vtbl[] dtsize_t(&dt, id->vtbl.dim); dtxoff(&dt, cd->csym, offset, TYnptr); dtsize_t(&dt, b->offset); // this offset offset += id->vtbl.dim * Target::ptrsize; } // Put out the (*vtblInterfaces)[].vtbl[] // This must be mirrored with ClassDeclaration::baseVtblOffset() //printf("putting out %d interface vtbl[]s for '%s'\n", vtblInterfaces->dim, toChars()); for (size_t i = 0; i < cd->vtblInterfaces->dim; i++) { BaseClass *b = (*cd->vtblInterfaces)[i]; ClassDeclaration *id = b->sym; //printf(" interface[%d] is '%s'\n", i, id->toChars()); size_t j = 0; if (id->vtblOffset()) { // First entry is ClassInfo reference //dtxoff(&dt, toSymbol(id), 0, TYnptr); // First entry is struct Interface reference dtxoff(&dt, cd->csym, Target::classinfosize + i * (4 * Target::ptrsize), TYnptr); j = 1; } assert(id->vtbl.dim == b->vtbl.dim); for (; j < id->vtbl.dim; j++) { assert(j < b->vtbl.dim); #if 0 RootObject *o = b->vtbl[j]; if (o) { printf("o = %p\n", o); assert(o->dyncast() == DYNCAST_DSYMBOL); Dsymbol *s = (Dsymbol *)o; printf("s->kind() = '%s'\n", s->kind()); } #endif FuncDeclaration *fd = b->vtbl[j]; if (fd) dtxoff(&dt, toThunkSymbol(fd, b->offset), 0, TYnptr); else dtsize_t(&dt, 0); } } // Put out the overriding interface vtbl[]s. // This must be mirrored with ClassDeclaration::baseVtblOffset() //printf("putting out overriding interface vtbl[]s for '%s' at offset x%x\n", toChars(), offset); ClassDeclaration *pc; for (pc = cd->baseClass; pc; pc = pc->baseClass) { for (size_t k = 0; k < pc->vtblInterfaces->dim; k++) { BaseClass *bs = (*pc->vtblInterfaces)[k]; FuncDeclarations bvtbl; if (bs->fillVtbl(cd, &bvtbl, 0)) { //printf("\toverriding vtbl[] for %s\n", bs->sym->toChars()); ClassDeclaration *id = bs->sym; size_t j = 0; if (id->vtblOffset()) { // First entry is ClassInfo reference //dtxoff(&dt, toSymbol(id), 0, TYnptr); // First entry is struct Interface reference dtxoff(&dt, toSymbol(pc), Target::classinfosize + k * (4 * Target::ptrsize), TYnptr); offset += Target::ptrsize; j = 1; } for (; j < id->vtbl.dim; j++) { assert(j < bvtbl.dim); FuncDeclaration *fd = bvtbl[j]; if (fd) dtxoff(&dt, toThunkSymbol(fd, bs->offset), 0, TYnptr); else dtsize_t(&dt, 0); offset += Target::ptrsize; } } } } ////////////////////////////////////////////// dtpatchoffset(*pdtname, offset); dtnbytes(&dt, namelen + 1, name); const size_t namepad = -(namelen + 1) & (Target::ptrsize - 1); // align dtnzeros(&dt, namepad); cd->csym->Sdt = dt; // ClassInfo cannot be const data, because we use the monitor on it outdata(cd->csym); if (cd->isExport()) objmod->export_symbol(cd->csym, 0); ////////////////////////////////////////////// // Put out the vtbl[] //printf("putting out %s.vtbl[]\n", toChars()); dt = NULL; if (cd->vtblOffset()) dtxoff(&dt, cd->csym, 0, TYnptr); // first entry is ClassInfo reference for (size_t i = cd->vtblOffset(); i < cd->vtbl.dim; i++) { FuncDeclaration *fd = cd->vtbl[i]->isFuncDeclaration(); //printf("\tvtbl[%d] = %p\n", i, fd); if (fd && (fd->fbody || !cd->isAbstract())) { // Ensure function has a return value (Bugzilla 4869) fd->functionSemantic(); Symbol *s = toSymbol(fd); if (cd->isFuncHidden(fd)) { /* fd is hidden from the view of this class. * If fd overlaps with any function in the vtbl[], then * issue 'hidden' error. */ for (size_t j = 1; j < cd->vtbl.dim; j++) { if (j == i) continue; FuncDeclaration *fd2 = cd->vtbl[j]->isFuncDeclaration(); if (!fd2->ident->equals(fd->ident)) continue; if (fd->leastAsSpecialized(fd2) || fd2->leastAsSpecialized(fd)) { TypeFunction *tf = (TypeFunction *)fd->type; if (tf->ty == Tfunction) cd->error("use of %s%s is hidden by %s; use 'alias %s = %s.%s;' to introduce base class overload set", fd->toPrettyChars(), parametersTypeToChars(tf->parameters, tf->varargs), cd->toChars(), fd->toChars(), fd->parent->toChars(), fd->toChars()); else cd->error("use of %s is hidden by %s", fd->toPrettyChars(), cd->toChars()); break; } } } dtxoff(&dt, s, 0, TYnptr); } else dtsize_t(&dt, 0); } cd->vtblsym->Sdt = dt; cd->vtblsym->Sclass = scclass; cd->vtblsym->Sfl = FLdata; out_readonly(cd->vtblsym); outdata(cd->vtblsym); if (cd->isExport()) objmod->export_symbol(cd->vtblsym,0); }
dt_t *ArrayInitializer::toDtBit() { #if DMDV1 unsigned size; unsigned length; unsigned tadim; dt_t *d; dt_t **pdtend; Type *tb = type->toBasetype(); //printf("ArrayInitializer::toDtBit('%s')\n", toChars()); Bits databits; Bits initbits; if (tb->ty == Tsarray) { /* The 'dim' for ArrayInitializer is only the maximum dimension * seen in the initializer, not the type. So, for static arrays, * use instead the dimension of the type in order * to get the whole thing. */ dinteger_t value = ((TypeSArray*)tb)->dim->toInteger(); tadim = value; assert(tadim == value); // truncation overflow should already be checked databits.resize(tadim); initbits.resize(tadim); } else { databits.resize(dim); initbits.resize(dim); } /* The default initializer may be something other than zero. */ if (tb->next->defaultInit()->toInteger()) databits.set(); size = sizeof(databits.data[0]); length = 0; for (size_t i = 0; i < index.dim; i++) { Expression *idx; Initializer *val; Expression *eval; idx = (Expression *)index.data[i]; if (idx) { dinteger_t value; value = idx->toInteger(); length = value; if (length != value) { error(loc, "index overflow %llu", value); length = 0; } } assert(length < dim); val = (Initializer *)value.data[i]; eval = val->toExpression(); if (initbits.test(length)) error(loc, "duplicate initializations for index %d", length); initbits.set(length); if (eval->toInteger()) // any non-zero value is boolean 'true' databits.set(length); else databits.clear(length); // boolean 'false' length++; } d = NULL; #ifdef IN_GCC pdtend = dtnbits(&d, databits.allocdim * size, (char *)databits.data, sizeof(databits.data[0])); #else pdtend = dtnbytes(&d, databits.allocdim * size, (char *)databits.data); #endif switch (tb->ty) { case Tsarray: { if (dim > tadim) { error(loc, "too many initializers, %d, for array[%d]", dim, tadim); } else { tadim = (tadim + 31) / 32; if (databits.allocdim < tadim) pdtend = dtnzeros(pdtend, size * (tadim - databits.allocdim)); // pad out end of array } break; } case Tpointer: case Tarray: // Create symbol, and then refer to it Symbol *s; s = static_sym(); s->Sdt = d; outdata(s); d = NULL; if (tb->ty == Tarray) dtsize_t(&d, dim); dtxoff(&d, s, 0, TYnptr); break; default: assert(0); } return d; #else return NULL; #endif }
void Module::genobjfile(int multiobj) { //EEcontext *ee = env->getEEcontext(); //printf("Module::genobjfile(multiobj = %d) %s\n", multiobj, toChars()); lastmname = srcfile->toChars(); obj_initfile(lastmname, NULL, toPrettyChars()); eictor = NULL; ictorlocalgot = NULL; sctors.setDim(0); ectorgates.setDim(0); sdtors.setDim(0); ssharedctors.setDim(0); esharedctorgates.setDim(0); sshareddtors.setDim(0); stests.setDim(0); dtorcount = 0; shareddtorcount = 0; if (doppelganger) { /* Generate a reference to the moduleinfo, so the module constructors * and destructors get linked in. */ Module *m = aimports[0]; assert(m); if (m->sictor || m->sctor || m->sdtor || m->ssharedctor || m->sshareddtor) { Symbol *s = m->toSymbol(); //objextern(s); //if (!s->Sxtrnnum) objextdef(s->Sident); if (!s->Sxtrnnum) { //printf("%s\n", s->Sident); #if 0 /* This should work, but causes optlink to fail in common/newlib.asm */ objextdef(s->Sident); #else #if ELFOBJ || MACHOBJ int nbytes = reftoident(DATA, Offset(DATA), s, 0, I64 ? (CFoff | CFoffset64) : CFoff); #else int nbytes = reftoident(DATA, Doffset, s, 0, CFoff); Doffset += nbytes; #endif #endif } } } if (global.params.cov) { /* Create coverage identifier: * private uint[numlines] __coverage; */ cov = symbol_calloc("__coverage"); cov->Stype = type_fake(TYint); cov->Stype->Tmangle = mTYman_c; cov->Stype->Tcount++; cov->Sclass = SCstatic; cov->Sfl = FLdata; #if ELFOBJ || MACHOBJ cov->Sseg = UDATA; #endif dtnzeros(&cov->Sdt, 4 * numlines); outdata(cov); slist_add(cov); covb = (unsigned *)calloc((numlines + 32) / 32, sizeof(*covb)); } for (size_t i = 0; i < members->dim; i++) { Dsymbol *member = (*members)[i]; member->toObjFile(multiobj); } if (global.params.cov) { /* Generate * bit[numlines] __bcoverage; */ Symbol *bcov = symbol_calloc("__bcoverage"); bcov->Stype = type_fake(TYuint); bcov->Stype->Tcount++; bcov->Sclass = SCstatic; bcov->Sfl = FLdata; #if ELFOBJ || MACHOBJ bcov->Sseg = DATA; #endif dtnbytes(&bcov->Sdt, (numlines + 32) / 32 * sizeof(*covb), (char *)covb); outdata(bcov); free(covb); covb = NULL; /* Generate: * _d_cover_register(uint[] __coverage, BitArray __bcoverage, string filename); * and prepend it to the static constructor. */ /* t will be the type of the functions generated: * extern (C) void func(); */ type *t = type_alloc(TYnfunc); t->Tflags |= TFprototype | TFfixed; t->Tmangle = mTYman_c; t->Tnext = tsvoid; tsvoid->Tcount++; sictor = toSymbolX("__modictor", SCglobal, t, "FZv"); cstate.CSpsymtab = &sictor->Sfunc->Flocsym; localgot = ictorlocalgot; elem *e; e = el_params(el_pair(TYdarray, el_long(TYsize_t, numlines), el_ptr(cov)), el_pair(TYdarray, el_long(TYsize_t, numlines), el_ptr(bcov)), toEfilename(), NULL); e = el_bin(OPcall, TYvoid, el_var(rtlsym[RTLSYM_DCOVER]), e); eictor = el_combine(e, eictor); ictorlocalgot = localgot; } // If coverage / static constructor / destructor / unittest calls if (eictor || sctors.dim || ectorgates.dim || sdtors.dim || ssharedctors.dim || esharedctorgates.dim || sshareddtors.dim || stests.dim) { if (eictor) { localgot = ictorlocalgot; block *b = block_calloc(); b->BC = BCret; b->Belem = eictor; sictor->Sfunc->Fstartline.Sfilename = arg; sictor->Sfunc->Fstartblock = b; writefunc(sictor); } sctor = callFuncsAndGates(this, &sctors, &ectorgates, "__modctor"); sdtor = callFuncsAndGates(this, &sdtors, NULL, "__moddtor"); #if DMDV2 ssharedctor = callFuncsAndGates(this, &ssharedctors, (StaticDtorDeclarations *)&esharedctorgates, "__modsharedctor"); sshareddtor = callFuncsAndGates(this, &sshareddtors, NULL, "__modshareddtor"); #endif stest = callFuncsAndGates(this, &stests, NULL, "__modtest"); if (doppelganger) genmoduleinfo(); } if (doppelganger) { obj_termfile(); return; } if (global.params.multiobj) { /* This is necessary because the main .obj for this module is written * first, but determining whether marray or massert or munittest are needed is done * possibly later in the doppelganger modules. * Another way to fix it is do the main one last. */ toModuleAssert(); toModuleUnittest(); toModuleArray(); } #if 1 // Always generate module info, because of templates and -cov if (1 || needModuleInfo()) genmoduleinfo(); #endif // If module assert for (int i = 0; i < 3; i++) { Symbol *ma; unsigned rt; unsigned bc; switch (i) { case 0: ma = marray; rt = RTLSYM_DARRAY; bc = BCexit; break; case 1: ma = massert; rt = RTLSYM_DASSERTM; bc = BCexit; break; case 2: ma = munittest; rt = RTLSYM_DUNITTESTM; bc = BCret; break; default: assert(0); } if (ma) { elem *elinnum; localgot = NULL; // Call dassert(filename, line) // Get sole parameter, linnum { Symbol *sp = symbol_calloc("linnum"); sp->Stype = type_fake(TYint); sp->Stype->Tcount++; sp->Sclass = SCfastpar; size_t num; sp->Spreg = getintegerparamsreglist(TYjfunc, &num)[0]; sp->Sflags &= ~SFLspill; sp->Sfl = FLpara; // FLauto? cstate.CSpsymtab = &ma->Sfunc->Flocsym; symbol_add(sp); elinnum = el_var(sp); } elem *efilename = el_ptr(toSymbol()); elem *e = el_var(rtlsym[rt]); e = el_bin(OPcall, TYvoid, e, el_param(elinnum, efilename)); block *b = block_calloc(); b->BC = bc; b->Belem = e; ma->Sfunc->Fstartline.Sfilename = arg; ma->Sfunc->Fstartblock = b; ma->Sclass = SCglobal; ma->Sfl = 0; ma->Sflags |= rtlsym[rt]->Sflags & SFLexit; writefunc(ma); } } obj_termfile(); }
void Module::genobjfile(int multiobj) { //EEcontext *ee = env->getEEcontext(); //printf("Module::genobjfile(multiobj = %d) %s\n", multiobj, toChars()); lastmname = srcfile->toChars(); objmod->initfile(lastmname, NULL, toPrettyChars()); eictor = NULL; ictorlocalgot = NULL; sctors.setDim(0); ectorgates.setDim(0); sdtors.setDim(0); ssharedctors.setDim(0); esharedctorgates.setDim(0); sshareddtors.setDim(0); stests.setDim(0); dtorcount = 0; shareddtorcount = 0; if (doppelganger) { /* Generate a reference to the moduleinfo, so the module constructors * and destructors get linked in. */ Module *m = aimports[0]; assert(m); if (m->sictor || m->sctor || m->sdtor || m->ssharedctor || m->sshareddtor) { Symbol *s = m->toSymbol(); //objextern(s); //if (!s->Sxtrnnum) objextdef(s->Sident); if (!s->Sxtrnnum) { //printf("%s\n", s->Sident); #if 0 /* This should work, but causes optlink to fail in common/newlib.asm */ objextdef(s->Sident); #else Symbol *sref = symbol_generate(SCstatic, type_fake(TYnptr)); sref->Sfl = FLdata; dtxoff(&sref->Sdt, s, 0, TYnptr); outdata(sref); #endif } } } if (global.params.cov) { /* Create coverage identifier: * private uint[numlines] __coverage; */ cov = symbol_calloc("__coverage"); cov->Stype = type_fake(TYint); cov->Stype->Tmangle = mTYman_c; cov->Stype->Tcount++; cov->Sclass = SCstatic; cov->Sfl = FLdata; dtnzeros(&cov->Sdt, 4 * numlines); outdata(cov); slist_add(cov); covb = (unsigned *)calloc((numlines + 32) / 32, sizeof(*covb)); } for (size_t i = 0; i < members->dim; i++) { Dsymbol *member = (*members)[i]; //printf("toObjFile %s %s\n", member->kind(), member->toChars()); member->toObjFile(multiobj); } if (global.params.cov) { /* Generate * bit[numlines] __bcoverage; */ Symbol *bcov = symbol_calloc("__bcoverage"); bcov->Stype = type_fake(TYuint); bcov->Stype->Tcount++; bcov->Sclass = SCstatic; bcov->Sfl = FLdata; dtnbytes(&bcov->Sdt, (numlines + 32) / 32 * sizeof(*covb), (char *)covb); outdata(bcov); free(covb); covb = NULL; /* Generate: * _d_cover_register(uint[] __coverage, BitArray __bcoverage, string filename); * and prepend it to the static constructor. */ /* t will be the type of the functions generated: * extern (C) void func(); */ type *t = type_function(TYnfunc, NULL, 0, false, tsvoid); t->Tmangle = mTYman_c; sictor = toSymbolX("__modictor", SCglobal, t, "FZv"); cstate.CSpsymtab = &sictor->Sfunc->Flocsym; localgot = ictorlocalgot; elem *ecov = el_pair(TYdarray, el_long(TYsize_t, numlines), el_ptr(cov)); elem *ebcov = el_pair(TYdarray, el_long(TYsize_t, numlines), el_ptr(bcov)); if (config.exe == EX_WIN64) { ecov = addressElem(ecov, Type::tvoid->arrayOf(), false); ebcov = addressElem(ebcov, Type::tvoid->arrayOf(), false); } elem *e = el_params( el_long(TYuchar, global.params.covPercent), ecov, ebcov, toEfilename(), NULL); e = el_bin(OPcall, TYvoid, el_var(rtlsym[RTLSYM_DCOVER2]), e); eictor = el_combine(e, eictor); ictorlocalgot = localgot; } // If coverage / static constructor / destructor / unittest calls if (eictor || sctors.dim || ectorgates.dim || sdtors.dim || ssharedctors.dim || esharedctorgates.dim || sshareddtors.dim || stests.dim) { if (eictor) { localgot = ictorlocalgot; block *b = block_calloc(); b->BC = BCret; b->Belem = eictor; sictor->Sfunc->Fstartline.Sfilename = arg; sictor->Sfunc->Fstartblock = b; writefunc(sictor); } sctor = callFuncsAndGates(this, &sctors, &ectorgates, "__modctor"); sdtor = callFuncsAndGates(this, &sdtors, NULL, "__moddtor"); #if DMDV2 ssharedctor = callFuncsAndGates(this, &ssharedctors, (StaticDtorDeclarations *)&esharedctorgates, "__modsharedctor"); sshareddtor = callFuncsAndGates(this, &sshareddtors, NULL, "__modshareddtor"); #endif stest = callFuncsAndGates(this, &stests, NULL, "__modtest"); if (doppelganger) genmoduleinfo(); } if (doppelganger) { objmod->termfile(); return; } if (global.params.multiobj) { /* This is necessary because the main .obj for this module is written * first, but determining whether marray or massert or munittest are needed is done * possibly later in the doppelganger modules. * Another way to fix it is do the main one last. */ toModuleAssert(); toModuleUnittest(); toModuleArray(); } /* Always generate module info, because of templates and -cov. * But module info needs the runtime library, so disable it for betterC. */ if (!global.params.betterC /*|| needModuleInfo()*/) genmoduleinfo(); // If module assert for (int i = 0; i < 3; i++) { Symbol *ma; unsigned rt; unsigned bc; switch (i) { case 0: ma = marray; rt = RTLSYM_DARRAY; bc = BCexit; break; case 1: ma = massert; rt = RTLSYM_DASSERTM; bc = BCexit; break; case 2: ma = munittest; rt = RTLSYM_DUNITTESTM; bc = BCret; break; default: assert(0); } if (ma) { elem *elinnum; localgot = NULL; // Call dassert(filename, line) // Get sole parameter, linnum { Symbol *sp = symbol_calloc("linnum"); sp->Stype = type_fake(TYint); sp->Stype->Tcount++; sp->Sclass = (config.exe == EX_WIN64) ? SCshadowreg : SCfastpar; FuncParamRegs fpr(TYjfunc); fpr.alloc(sp->Stype, sp->Stype->Tty, &sp->Spreg, &sp->Spreg2); sp->Sflags &= ~SFLspill; sp->Sfl = (sp->Sclass == SCshadowreg) ? FLpara : FLfast; cstate.CSpsymtab = &ma->Sfunc->Flocsym; symbol_add(sp); elinnum = el_var(sp); } elem *efilename = el_ptr(toSymbol()); elem *e = el_var(rtlsym[rt]); e = el_bin(OPcall, TYvoid, e, el_param(elinnum, efilename)); block *b = block_calloc(); b->BC = bc; b->Belem = e; ma->Sfunc->Fstartline.Sfilename = arg; ma->Sfunc->Fstartblock = b; ma->Sclass = SCglobal; ma->Sfl = 0; ma->Sflags |= rtlsym[rt]->Sflags & SFLexit; writefunc(ma); } } objmod->termfile(); }
void TypeInfoStructDeclaration::toDt(dt_t **pdt) { //printf("TypeInfoStructDeclaration::toDt() '%s'\n", toChars()); unsigned offset = Type::typeinfostruct->structsize; dtxoff(pdt, Type::typeinfostruct->toVtblSymbol(), 0, TYnptr); // vtbl for TypeInfo_Struct dtdword(pdt, 0); // monitor assert(tinfo->ty == Tstruct); TypeStruct *tc = (TypeStruct *)tinfo; StructDeclaration *sd = tc->sym; /* Put out: * char[] name; * void[] init; * hash_t function(void*) xtoHash; * int function(void*,void*) xopEquals; * int function(void*,void*) xopCmp; * char[] function(void*) xtoString; * uint m_flags; * * name[] */ const char *name = sd->toPrettyChars(); size_t namelen = strlen(name); dtdword(pdt, namelen); //dtabytes(pdt, TYnptr, 0, namelen + 1, name); dtxoff(pdt, toSymbol(), offset, TYnptr); offset += namelen + 1; // void[] init; dtdword(pdt, sd->structsize); // init.length if (sd->zeroInit) dtdword(pdt, 0); // NULL for 0 initialization else dtxoff(pdt, sd->toInitializer(), 0, TYnptr); // init.ptr FuncDeclaration *fd; FuncDeclaration *fdx; TypeFunction *tf; Type *ta; Dsymbol *s; static TypeFunction *tftohash; static TypeFunction *tftostring; if (!tftohash) { Scope sc; tftohash = new TypeFunction(NULL, Type::thash_t, 0, LINKd); tftohash = (TypeFunction *)tftohash->semantic(0, &sc); tftostring = new TypeFunction(NULL, Type::tchar->arrayOf(), 0, LINKd); tftostring = (TypeFunction *)tftostring->semantic(0, &sc); } TypeFunction *tfeqptr; { Scope sc; Parameters *arguments = new Parameters; #if STRUCTTHISREF // arg type is ref const T Parameter *arg = new Parameter(STCref, tc->constOf(), NULL, NULL); #else // arg type is const T* Parameter *arg = new Parameter(STCin, tc->pointerTo(), NULL, NULL); #endif arguments->push(arg); tfeqptr = new TypeFunction(arguments, Type::tint32, 0, LINKd); tfeqptr = (TypeFunction *)tfeqptr->semantic(0, &sc); } #if 0 TypeFunction *tfeq; { Scope sc; Array *arguments = new Array; Parameter *arg = new Parameter(In, tc, NULL, NULL); arguments->push(arg); tfeq = new TypeFunction(arguments, Type::tint32, 0, LINKd); tfeq = (TypeFunction *)tfeq->semantic(0, &sc); } #endif s = search_function(sd, Id::tohash); fdx = s ? s->isFuncDeclaration() : NULL; if (fdx) { fd = fdx->overloadExactMatch(tftohash); if (fd) dtxoff(pdt, fd->toSymbol(), 0, TYnptr); else //fdx->error("must be declared as extern (D) uint toHash()"); dtdword(pdt, 0); } else dtdword(pdt, 0); s = search_function(sd, Id::eq); fdx = s ? s->isFuncDeclaration() : NULL; for (int i = 0; i < 2; i++) { if (fdx) { fd = fdx->overloadExactMatch(tfeqptr); if (fd) dtxoff(pdt, fd->toSymbol(), 0, TYnptr); else //fdx->error("must be declared as extern (D) int %s(%s*)", fdx->toChars(), sd->toChars()); dtdword(pdt, 0); } else //fdx->error("must be declared as extern (D) int %s(%s*)", fdx->toChars(), sd->toChars()); dtdword(pdt, 0); s = search_function(sd, Id::cmp); fdx = s ? s->isFuncDeclaration() : NULL; } s = search_function(sd, Id::tostring); fdx = s ? s->isFuncDeclaration() : NULL; if (fdx) { fd = fdx->overloadExactMatch(tftostring); if (fd) dtxoff(pdt, fd->toSymbol(), 0, TYnptr); else //fdx->error("must be declared as extern (D) char[] toString()"); dtdword(pdt, 0); } else dtdword(pdt, 0); // uint m_flags; dtdword(pdt, tc->hasPointers()); #if DMDV2 // xgetMembers FuncDeclaration *sgetmembers = sd->findGetMembers(); if (sgetmembers) dtxoff(pdt, sgetmembers->toSymbol(), 0, TYnptr); else dtdword(pdt, 0); // xgetMembers // xdtor FuncDeclaration *sdtor = sd->dtor; if (sdtor) dtxoff(pdt, sdtor->toSymbol(), 0, TYnptr); else dtdword(pdt, 0); // xdtor // xpostblit FuncDeclaration *spostblit = sd->postblit; if (spostblit) dtxoff(pdt, spostblit->toSymbol(), 0, TYnptr); else dtdword(pdt, 0); // xpostblit #endif // name[] dtnbytes(pdt, namelen + 1, name); }
void FuncDeclaration::toObjFile(int multiobj) { FuncDeclaration *func = this; ClassDeclaration *cd = func->parent->isClassDeclaration(); int reverse; int has_arguments; //printf("FuncDeclaration::toObjFile(%p, %s.%s)\n", func, parent->toChars(), func->toChars()); //if (type) printf("type = %s\n", func->type->toChars()); #if 0 //printf("line = %d\n",func->getWhere() / LINEINC); EEcontext *ee = env->getEEcontext(); if (ee->EEcompile == 2) { if (ee->EElinnum < (func->getWhere() / LINEINC) || ee->EElinnum > (func->endwhere / LINEINC) ) return; // don't compile this function ee->EEfunc = func->toSymbol(); } #endif if (semanticRun >= PASSobj) // if toObjFile() already run return; // If errors occurred compiling it, such as bugzilla 6118 if (type && type->ty == Tfunction && ((TypeFunction *)type)->next->ty == Terror) return; if (!func->fbody) { return; } if (func->isUnitTestDeclaration() && !global.params.useUnitTests) return; if (multiobj && !isStaticDtorDeclaration() && !isStaticCtorDeclaration()) { obj_append(this); return; } if (semanticRun == PASSsemanticdone) { /* What happened is this function failed semantic3() with errors, * but the errors were gagged. * Try to reproduce those errors, and then fail. */ error("errors compiling the function"); return; } assert(semanticRun == PASSsemantic3done); semanticRun = PASSobj; if (global.params.verbose) printf("function %s\n",func->toPrettyChars()); Symbol *s = func->toSymbol(); func_t *f = s->Sfunc; #if TARGET_WINDOS /* This is done so that the 'this' pointer on the stack is the same * distance away from the function parameters, so that an overriding * function can call the nested fdensure or fdrequire of its overridden function * and the stack offsets are the same. */ if (isVirtual() && (fensure || frequire)) f->Fflags3 |= Ffakeeh; #endif #if TARGET_OSX s->Sclass = SCcomdat; #else s->Sclass = SCglobal; #endif for (Dsymbol *p = parent; p; p = p->parent) { if (p->isTemplateInstance()) { s->Sclass = SCcomdat; break; } } /* Vector operations should be comdat's */ if (isArrayOp) s->Sclass = SCcomdat; if (isNested()) { // if (!(config.flags3 & CFG3pic)) // s->Sclass = SCstatic; f->Fflags3 |= Fnested; /* The enclosing function must have its code generated first, * so we know things like where its local symbols are stored. */ FuncDeclaration *fdp = toAliasFunc()->toParent2()->isFuncDeclaration(); // Bug 8016 - only include the function if it is a template instance Dsymbol * owner = NULL; if (fdp) { owner = fdp->toParent(); while (owner && !owner->isTemplateInstance()) owner = owner->toParent(); } if (owner && fdp && fdp->semanticRun == PASSsemantic3done && !fdp->isUnitTestDeclaration()) { /* Can't do unittest's out of order, they are order dependent in that their * execution is done in lexical order, and some modules (std.datetime *cough* * *cough*) rely on this. */ fdp->toObjFile(multiobj); } } else { const char *libname = (global.params.symdebug) ? global.params.debuglibname : global.params.defaultlibname; // Pull in RTL startup code (but only once) if (func->isMain() && onlyOneMain(loc)) { #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS objmod->external_def("_main"); objmod->ehsections(); // initialize exception handling sections #endif #if TARGET_WINDOS if (I64) { objmod->external_def("main"); objmod->ehsections(); // initialize exception handling sections } else { objmod->external_def("_main"); objmod->external_def("__acrtused_con"); } #endif objmod->includelib(libname); s->Sclass = SCglobal; } else if (strcmp(s->Sident, "main") == 0 && linkage == LINKc) { #if TARGET_WINDOS if (I64) { objmod->includelib("LIBCMT"); objmod->includelib("OLDNAMES"); } else { objmod->external_def("__acrtused_con"); // bring in C startup code objmod->includelib("snn.lib"); // bring in C runtime library } #endif s->Sclass = SCglobal; } #if TARGET_WINDOS else if (func->isWinMain() && onlyOneMain(loc)) { if (I64) { objmod->includelib("uuid"); objmod->includelib("LIBCMT"); objmod->includelib("OLDNAMES"); objmod->ehsections(); // initialize exception handling sections } else { objmod->external_def("__acrtused"); } objmod->includelib(libname); s->Sclass = SCglobal; } // Pull in RTL startup code else if (func->isDllMain() && onlyOneMain(loc)) { if (I64) { objmod->includelib("uuid"); objmod->includelib("LIBCMT"); objmod->includelib("OLDNAMES"); objmod->ehsections(); // initialize exception handling sections } else { objmod->external_def("__acrtused_dll"); } objmod->includelib(libname); s->Sclass = SCglobal; } #endif } cstate.CSpsymtab = &f->Flocsym; // Find module m for this function Module *m = NULL; for (Dsymbol *p = parent; p; p = p->parent) { m = p->isModule(); if (m) break; } IRState irs(m, func); Dsymbols deferToObj; // write these to OBJ file later irs.deferToObj = &deferToObj; TypeFunction *tf; enum RET retmethod; symbol *shidden = NULL; Symbol *sthis = NULL; tym_t tyf; tyf = tybasic(s->Stype->Tty); //printf("linkage = %d, tyf = x%x\n", linkage, tyf); reverse = tyrevfunc(s->Stype->Tty); assert(func->type->ty == Tfunction); tf = (TypeFunction *)(func->type); has_arguments = (tf->linkage == LINKd) && (tf->varargs == 1); retmethod = tf->retStyle(); if (retmethod == RETstack) { // If function returns a struct, put a pointer to that // as the first argument ::type *thidden = tf->next->pointerTo()->toCtype(); char hiddenparam[5+4+1]; static int hiddenparami; // how many we've generated so far sprintf(hiddenparam,"__HID%d",++hiddenparami); shidden = symbol_name(hiddenparam,SCparameter,thidden); shidden->Sflags |= SFLtrue | SFLfree; #if DMDV1 if (func->nrvo_can && func->nrvo_var && func->nrvo_var->nestedref) #else if (func->nrvo_can && func->nrvo_var && func->nrvo_var->nestedrefs.dim) #endif type_setcv(&shidden->Stype, shidden->Stype->Tty | mTYvolatile); irs.shidden = shidden; this->shidden = shidden; } else { // Register return style cannot make nrvo. // Auto functions keep the nrvo_can flag up to here, // so we should eliminate it before entering backend. nrvo_can = 0; } if (vthis) { assert(!vthis->csym); sthis = vthis->toSymbol(); irs.sthis = sthis; if (!(f->Fflags3 & Fnested)) f->Fflags3 |= Fmember; } Symbol **params; // Estimate number of parameters, pi size_t pi = (v_arguments != NULL); if (parameters) pi += parameters->dim; // Allow extra 2 for sthis and shidden params = (Symbol **)alloca((pi + 2) * sizeof(Symbol *)); // Get the actual number of parameters, pi, and fill in the params[] pi = 0; if (v_arguments) { params[pi] = v_arguments->toSymbol(); pi += 1; } if (parameters) { for (size_t i = 0; i < parameters->dim; i++) { VarDeclaration *v = (*parameters)[i]; if (v->csym) { error("compiler error, parameter '%s', bugzilla 2962?", v->toChars()); assert(0); } params[pi + i] = v->toSymbol(); } pi += parameters->dim; } if (reverse) { // Reverse params[] entries for (size_t i = 0; i < pi/2; i++) { Symbol *sptmp = params[i]; params[i] = params[pi - 1 - i]; params[pi - 1 - i] = sptmp; } } if (shidden) { #if 0 // shidden becomes last parameter params[pi] = shidden; #else // shidden becomes first parameter memmove(params + 1, params, pi * sizeof(params[0])); params[0] = shidden; #endif pi++; } if (sthis) { #if 0 // sthis becomes last parameter params[pi] = sthis; #else // sthis becomes first parameter memmove(params + 1, params, pi * sizeof(params[0])); params[0] = sthis; #endif pi++; } if ((global.params.isLinux || global.params.isOSX || global.params.isFreeBSD || global.params.isSolaris) && linkage != LINKd && shidden && sthis) { /* swap shidden and sthis */ Symbol *sp = params[0]; params[0] = params[1]; params[1] = sp; } for (size_t i = 0; i < pi; i++) { Symbol *sp = params[i]; sp->Sclass = SCparameter; sp->Sflags &= ~SFLspill; sp->Sfl = FLpara; symbol_add(sp); } // Determine register assignments if (pi) { FuncParamRegs fpr(tyf); for (size_t i = 0; i < pi; i++) { Symbol *sp = params[i]; if (fpr.alloc(sp->Stype, sp->Stype->Tty, &sp->Spreg, &sp->Spreg2)) { sp->Sclass = (config.exe == EX_WIN64) ? SCshadowreg : SCfastpar; sp->Sfl = (sp->Sclass == SCshadowreg) ? FLpara : FLfast; } } } if (func->fbody) { block *b; Blockx bx; localgot = NULL; Statement *sbody = func->fbody; memset(&bx,0,sizeof(bx)); bx.startblock = block_calloc(); bx.curblock = bx.startblock; bx.funcsym = s; bx.scope_index = -1; bx.classdec = cd; bx.member = func; bx.module = getModule(); irs.blx = &bx; /* If profiling, insert call to the profiler here. * _c_trace_pro(char* funcname); */ if (global.params.trace) { dt_t *dt = NULL; char *id = s->Sident; size_t len = strlen(id); dtnbytes(&dt, len + 1, id); Symbol *sfuncname = symbol_generate(SCstatic,type_fake(TYchar)); sfuncname->Sdt = dt; sfuncname->Sfl = FLdata; out_readonly(sfuncname); outdata(sfuncname); elem *efuncname = el_ptr(sfuncname); elem *eparam = el_params(efuncname, el_long(TYsize_t, len), NULL); elem *e = el_bin(OPcall, TYvoid, el_var(rtlsym[RTLSYM_TRACE_CPRO]), eparam); block_appendexp(bx.curblock, e); } #if DMDV2 buildClosure(&irs); #endif #if 0 if (func->isSynchronized()) { if (cd) { elem *esync; if (func->isStatic()) { // monitor is in ClassInfo esync = el_ptr(cd->toSymbol()); } else { // 'this' is the monitor esync = el_var(sthis); } if (func->isStatic() || sbody->usesEH() || !(config.flags2 & CFG2seh)) { // BUG: what if frequire or fensure uses EH? sbody = new SynchronizedStatement(func->loc, esync, sbody); } else { #if TARGET_WINDOS if (config.flags2 & CFG2seh) { /* The "jmonitor" uses an optimized exception handling frame * which is a little shorter than the more general EH frame. * It isn't strictly necessary. */ s->Sfunc->Fflags3 |= Fjmonitor; } #endif el_free(esync); } } else { error("synchronized function %s must be a member of a class", func->toChars()); } } #elif TARGET_WINDOS if (func->isSynchronized() && cd && config.flags2 & CFG2seh && !func->isStatic() && !sbody->usesEH()) { /* The "jmonitor" hack uses an optimized exception handling frame * which is a little shorter than the more general EH frame. */ s->Sfunc->Fflags3 |= Fjmonitor; } #endif sbody->toIR(&irs); bx.curblock->BC = BCret; f->Fstartblock = bx.startblock; // einit = el_combine(einit,bx.init); if (isCtorDeclaration()) { assert(sthis); for (b = f->Fstartblock; b; b = b->Bnext) { if (b->BC == BCret) { b->BC = BCretexp; b->Belem = el_combine(b->Belem, el_var(sthis)); } } } } // If static constructor #if DMDV2 if (isSharedStaticCtorDeclaration()) // must come first because it derives from StaticCtorDeclaration { ssharedctors.push(s); } else #endif if (isStaticCtorDeclaration()) { sctors.push(s); } // If static destructor #if DMDV2 if (isSharedStaticDtorDeclaration()) // must come first because it derives from StaticDtorDeclaration { SharedStaticDtorDeclaration *f = isSharedStaticDtorDeclaration(); assert(f); if (f->vgate) { /* Increment destructor's vgate at construction time */ esharedctorgates.push(f); } sshareddtors.shift(s); } else #endif if (isStaticDtorDeclaration()) { StaticDtorDeclaration *f = isStaticDtorDeclaration(); assert(f); if (f->vgate) { /* Increment destructor's vgate at construction time */ ectorgates.push(f); } sdtors.shift(s); } // If unit test if (isUnitTestDeclaration()) { stests.push(s); } if (global.errors) return; writefunc(s); if (isExport()) objmod->export_symbol(s, Para.offset); for (size_t i = 0; i < irs.deferToObj->dim; i++) { Dsymbol *s = (*irs.deferToObj)[i]; FuncDeclaration *fd = s->isFuncDeclaration(); if (fd) { FuncDeclaration *fdp = fd->toParent2()->isFuncDeclaration(); if (fdp && fdp->semanticRun < PASSobj) { /* Bugzilla 7595 * FuncDeclaration::buildClosure() relies on nested functions * being toObjFile'd after the outer function. Otherwise, the * v->offset's for the closure variables are wrong. * So, defer fd until after fdp is done. */ fdp->deferred.push(fd); continue; } } s->toObjFile(0); } for (size_t i = 0; i < deferred.dim; i++) { FuncDeclaration *fd = deferred[i]; fd->toObjFile(0); } #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS // A hack to get a pointer to this function put in the .dtors segment if (ident && memcmp(ident->toChars(), "_STD", 4) == 0) objmod->staticdtor(s); #endif #if DMDV2 if (irs.startaddress) { //printf("Setting start address\n"); objmod->startaddress(irs.startaddress); } #endif }