void StructDeclaration::toDt(dt_t **pdt) { if (zeroInit) { dtnzeros(pdt, structsize); return; } unsigned offset; dt_t *dt; dt_t *sdt = NULL; //printf("StructDeclaration::toDt(), this='%s'\n", toChars()); offset = 0; // Note equivalence of this loop to class's for (size_t i = 0; i < fields.dim; i++) { VarDeclaration *v = (VarDeclaration *)fields.data[i]; Initializer *init; //printf("\tfield '%s' voffset %d, offset = %d\n", v->toChars(), v->offset, offset); dt = NULL; init = v->init; if (init) { //printf("\t\thas initializer %s\n", init->toChars()); ExpInitializer *ei = init->isExpInitializer(); Type *tb = v->type->toBasetype(); if (ei && tb->ty == Tsarray) ((TypeSArray *)tb)->toDtElem(&dt, ei->exp); else dt = init->toDt(); } else if (v->offset >= offset) v->type->toDt(&dt); if (dt) { if (v->offset < offset) error("overlapping initialization for struct %s.%s", toChars(), v->toChars()); else { if (offset < v->offset) dtnzeros(&sdt, v->offset - offset); dtcat(&sdt, dt); offset = v->offset + v->type->size(); } } } if (offset < structsize) dtnzeros(&sdt, structsize - offset); #ifdef IN_GCC dtcontainer(pdt, type, sdt); #else dtcat(pdt, sdt); #endif dt_optimize(*pdt); }
void StructDeclaration::toDt(dt_t **pdt) { unsigned offset; unsigned i; dt_t *dt; //printf("StructDeclaration::toDt(), this='%s'\n", toChars()); offset = 0; // Note equivalence of this loop to class's for (i = 0; i < fields.dim; i++) { VarDeclaration *v = (VarDeclaration *)fields.data[i]; //printf("\tfield '%s' voffset %d, offset = %d\n", v->toChars(), v->offset, offset); dt = NULL; int sz; if (v->storage_class & STCref) { sz = PTRSIZE; if (v->offset >= offset) dtnzeros(&dt, sz); } else { sz = v->type->size(); Initializer *init = v->init; if (init) { //printf("\t\thas initializer %s\n", init->toChars()); ExpInitializer *ei = init->isExpInitializer(); Type *tb = v->type->toBasetype(); if (ei && tb->ty == Tsarray) ((TypeSArray *)tb)->toDtElem(&dt, ei->exp); else dt = init->toDt(); } else if (v->offset >= offset) v->type->toDt(&dt); } if (dt) { if (v->offset < offset) error("overlapping initialization for struct %s.%s", toChars(), v->toChars()); else { if (offset < v->offset) dtnzeros(pdt, v->offset - offset); dtcat(pdt, dt); offset = v->offset + sz; } } } if (offset < structsize) dtnzeros(pdt, structsize - offset); dt_optimize(*pdt); }
void init_common(symbol *s) { //printf("init_common('%s')\n", s->Sident); dtnzeros(&s->Sdt,type_size(s->Stype)); if (s->Sdt) s->Sdt->dt = DT_common; }
dt_t *VoidInitializer::toDt() { /* Void initializers are set to 0, just because we need something * to set them to in the static data segment. */ dt_t *dt = NULL; dtnzeros(&dt, type->size()); return dt; }
Symbol *Module::gencritsec() { Symbol *s; type *t; t = Type::tint32->toCtype(); s = symbol_name("critsec", SCstatic, t); s->Sfl = FLdata; /* Must match D_CRITICAL_SECTION in phobos/internal/critical.c */ dtnzeros(&s->Sdt, PTRSIZE + (I64 ? os_critsecsize64() : os_critsecsize32())); outdata(s); return s; }
Symbol *Module::gencritsec() { Symbol *s; type *t; t = Type::tint32->toCtype(); s = symbol_name("critsec", SCstatic, t); s->Sfl = FLdata; /* Must match D_CRITICAL_SECTION in phobos/internal/critical.c */ dtnzeros(&s->Sdt, PTRSIZE + os_critsecsize()); #if ELFOBJ || MACHOBJ // Burton s->Sseg = DATA; #endif outdata(s); return s; }
void ClassDeclaration::toDt2(dt_t **pdt, ClassDeclaration *cd) { unsigned offset; dt_t *dt; unsigned csymoffset; #define LOG 0 #if LOG printf("ClassDeclaration::toDt2(this = '%s', cd = '%s')\n", toChars(), cd->toChars()); #endif if (baseClass) { baseClass->toDt2(pdt, cd); offset = baseClass->structsize; } else { offset = PTRSIZE * 2; } // Note equivalence of this loop to struct's for (size_t i = 0; i < fields.dim; i++) { VarDeclaration *v = (VarDeclaration *)fields.data[i]; Initializer *init; //printf("\t\tv = '%s' v->offset = %2d, offset = %2d\n", v->toChars(), v->offset, offset); dt = NULL; init = v->init; if (init) { //printf("\t\t%s has initializer %s\n", v->toChars(), init->toChars()); ExpInitializer *ei = init->isExpInitializer(); Type *tb = v->type->toBasetype(); if (ei && tb->ty == Tsarray) ((TypeSArray *)tb)->toDtElem(&dt, ei->exp); else dt = init->toDt(); } else if (v->offset >= offset) { //printf("\t\tdefault initializer\n"); v->type->toDt(&dt); } if (dt) { if (v->offset < offset) error("duplicated union initialization for %s", v->toChars()); else { if (offset < v->offset) dtnzeros(pdt, v->offset - offset); dtcat(pdt, dt); offset = v->offset + v->type->size(); } } } // Interface vptr initializations toSymbol(); // define csym for (size_t i = 0; i < vtblInterfaces->dim; i++) { BaseClass *b = (BaseClass *)vtblInterfaces->data[i]; #if 1 || INTERFACE_VIRTUAL for (ClassDeclaration *cd2 = cd; 1; cd2 = cd2->baseClass) { assert(cd2); csymoffset = cd2->baseVtblOffset(b); if (csymoffset != ~0) { if (offset < b->offset) dtnzeros(pdt, b->offset - offset); dtxoff(pdt, cd2->toSymbol(), csymoffset, TYnptr); break; } } #else csymoffset = baseVtblOffset(b); assert(csymoffset != ~0); dtxoff(pdt, csym, csymoffset, TYnptr); #endif offset = b->offset + PTRSIZE; } if (offset < structsize) dtnzeros(pdt, structsize - offset); #undef LOG }
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 }
dt_t *ArrayInitializer::toDt() { //printf("ArrayInitializer::toDt('%s')\n", toChars()); Type *tb = type->toBasetype(); Type *tn = tb->next->toBasetype(); if (tn->ty == Tbit) return toDtBit(); Array dts; unsigned size; unsigned length; dt_t *dt; dt_t *d; dt_t **pdtend; //printf("\tdim = %d\n", dim); dts.setDim(dim); dts.zero(); size = tn->size(); length = 0; for (size_t i = 0; i < index.dim; i++) { Expression *idx; Initializer *val; idx = (Expression *)index.data[i]; if (idx) length = idx->toInteger(); //printf("\tindex[%d] = %p, length = %u, dim = %u\n", i, idx, length, dim); assert(length < dim); val = (Initializer *)value.data[i]; dt = val->toDt(); if (dts.data[length]) error(loc, "duplicate initializations for index %d", length); dts.data[length] = (void *)dt; length++; } Expression *edefault = tb->next->defaultInit(); #ifdef IN_GCC dt_t * sadefault = NULL; if (tn->ty == Tsarray) tn->toDt(& sadefault); else edefault->toDt(& sadefault); #else unsigned n = 1; for (Type *tbn = tn; tbn->ty == Tsarray; tbn = tbn->next->toBasetype()) { TypeSArray *tsa = (TypeSArray *)tbn; n *= tsa->dim->toInteger(); } #endif d = NULL; pdtend = &d; for (size_t i = 0; i < dim; i++) { dt = (dt_t *)dts.data[i]; #ifdef IN_GCC pdtend = dtcontainer(pdtend, NULL, dt ? dt : sadefault); #else if (dt) pdtend = dtcat(pdtend, dt); else { for (size_t j = 0; j < n; j++) pdtend = edefault->toDt(pdtend); } #endif } switch (tb->ty) { case Tsarray: { unsigned tadim; TypeSArray *ta = (TypeSArray *)tb; tadim = ta->dim->toInteger(); if (dim < tadim) { if (edefault->isBool(FALSE)) // pad out end of array // (ok for GDC as well) pdtend = dtnzeros(pdtend, size * (tadim - dim)); else { for (size_t i = dim; i < tadim; i++) #ifdef IN_GCC pdtend = dtcontainer(pdtend, NULL, sadefault); #else { for (size_t j = 0; j < n; j++) pdtend = edefault->toDt(pdtend); } #endif } } else if (dim > tadim) { #ifdef DEBUG printf("1: "); #endif error(loc, "too many initializers, %d, for array[%d]", dim, tadim); } #ifdef IN_GCC dt_t * cdt = NULL; dtcontainer(& cdt, type, d); d = cdt; #endif break; } case Tpointer: case Tarray: { // Create symbol, and then refer to it Symbol *s = static_sym(); s->Sdt = d; outdata(s); d = NULL; if (tb->ty == Tarray) dtsize_t(&d, dim); dtxoff(&d, s, 0, TYnptr); #ifdef IN_GCC dt_t * cdt; cdt = NULL; if (tb->ty == Tarray) { dtcontainer(& cdt, type, d); d = cdt; } #endif break; } default: assert(0); } return d; }
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); }
dt_t *ArrayInitializer::toDt() { //printf("ArrayInitializer::toDt('%s')\n", toChars()); Type *tb = type->toBasetype(); if (tb->ty == Tvector) tb = ((TypeVector *)tb)->basetype; Type *tn = tb->nextOf()->toBasetype(); Dts dts; unsigned size; unsigned length; dt_t *dt; dt_t *d; dt_t **pdtend; //printf("\tdim = %d\n", dim); dts.setDim(dim); dts.zero(); size = tn->size(); length = 0; for (size_t i = 0; i < index.dim; i++) { Expression *idx; Initializer *val; idx = index[i]; if (idx) length = idx->toInteger(); //printf("\tindex[%d] = %p, length = %u, dim = %u\n", i, idx, length, dim); assert(length < dim); val = value[i]; dt = val->toDt(); if (dts[length]) error(loc, "duplicate initializations for index %d", length); if (tn->ty == Tsarray) dt = createTsarrayDt(dt, tb->nextOf()); dts[length] = dt; length++; } Expression *edefault = tb->nextOf()->defaultInit(); #ifdef IN_GCC dt_t * sadefault = NULL; if (tn->ty == Tsarray) tn->toDt(& sadefault); else edefault->toDt(& sadefault); #else unsigned n = 1; for (Type *tbn = tn; tbn->ty == Tsarray; tbn = tbn->nextOf()->toBasetype()) { TypeSArray *tsa = (TypeSArray *)tbn; n *= tsa->dim->toInteger(); } #endif d = NULL; pdtend = &d; for (size_t i = 0; i < dim; i++) { dt = dts[i]; #ifdef IN_GCC pdtend = dtcontainer(pdtend, NULL, dt ? dt : sadefault); #else if (dt) pdtend = dtcat(pdtend, dt); else { for (size_t j = 0; j < n; j++) pdtend = edefault->toDt(pdtend); } #endif } switch (tb->ty) { case Tsarray: { unsigned tadim; TypeSArray *ta = (TypeSArray *)tb; tadim = ta->dim->toInteger(); if (dim < tadim) { #ifdef IN_GCC // Pad out the rest of the array with single elements. // Otherwise breaks -fsection-anchors on ARM when // backend calculates field positions for array members. for (size_t i = dim; i < tadim; i++) pdtend = dtcontainer(pdtend, NULL, sadefault); #else if (edefault->isBool(FALSE)) // pad out end of array pdtend = dtnzeros(pdtend, size * (tadim - dim)); else { for (size_t i = dim; i < tadim; i++) { for (size_t j = 0; j < n; j++) pdtend = edefault->toDt(pdtend); } } #endif } else if (dim > tadim) { error(loc, "too many initializers, %d, for array[%d]", dim, tadim); } #ifdef IN_GCC dt_t * cdt = NULL; dtcontainer(& cdt, type, d); d = cdt; #endif break; } case Tpointer: case Tarray: { // Create symbol, and then refer to it Symbol *s = static_sym(); s->Sdt = d; outdata(s); d = NULL; if (tb->ty == Tarray) dtsize_t(&d, dim); dtxoff(&d, s, 0, TYnptr); #ifdef IN_GCC dt_t * cdt; cdt = NULL; if (tb->ty == Tarray) { dtcontainer(& cdt, type, d); d = cdt; } #endif break; } default: assert(0); } return d; }
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(); }
dt_t *ArrayInitializer::toDt() { //printf("ArrayInitializer::toDt('%s')\n", toChars()); Type *tb = type->toBasetype(); Type *tn = tb->nextOf()->toBasetype(); Dts dts; unsigned size; unsigned length; unsigned i; dt_t *dt; dt_t *d; dt_t **pdtend; //printf("\tdim = %d\n", dim); dts.setDim(dim); dts.zero(); size = tn->size(); length = 0; for (i = 0; i < index.dim; i++) { Expression *idx; Initializer *val; idx = index.tdata()[i]; if (idx) length = idx->toInteger(); //printf("\tindex[%d] = %p, length = %u, dim = %u\n", i, idx, length, dim); assert(length < dim); val = value.tdata()[i]; dt = val->toDt(); if (dts.tdata()[length]) error(loc, "duplicate initializations for index %d", length); dts.tdata()[length] = dt; length++; } Expression *edefault = tb->nextOf()->defaultInit(); unsigned n = 1; for (Type *tbn = tn; tbn->ty == Tsarray; tbn = tbn->nextOf()->toBasetype()) { TypeSArray *tsa = (TypeSArray *)tbn; n *= tsa->dim->toInteger(); } d = NULL; pdtend = &d; for (i = 0; i < dim; i++) { dt = dts.tdata()[i]; if (dt) pdtend = dtcat(pdtend, dt); else { for (int j = 0; j < n; j++) pdtend = edefault->toDt(pdtend); } } switch (tb->ty) { case Tsarray: { unsigned tadim; TypeSArray *ta = (TypeSArray *)tb; tadim = ta->dim->toInteger(); if (dim < tadim) { if (edefault->isBool(FALSE)) // pad out end of array pdtend = dtnzeros(pdtend, size * (tadim - dim)); else { for (i = dim; i < tadim; i++) { for (int j = 0; j < n; j++) pdtend = edefault->toDt(pdtend); } } } else if (dim > tadim) { #ifdef DEBUG printf("1: "); #endif error(loc, "too many initializers, %d, for array[%d]", dim, tadim); } 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; }
symbol *except_gentables() { //printf("except_gentables()\n"); #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS symbol *s; int sz; // size so far dt_t **pdt; unsigned fsize; // target size of function pointer long spoff; block *b; int guarddim; int i; // BUG: alloca() changes the stack size, which is not reflected // in the fixed eh tables. assert(!usedalloca); s = symbol_generate(SCstatic,tsint); s->Sseg = UNKNOWN; symbol_keep(s); symbol_debug(s); fsize = 4; pdt = &s->Sdt; sz = 0; /* void* pointer to start of function unsigned offset of ESP from EBP unsigned offset from start of function to return code unsigned nguards; // dimension of guard[] { unsigned offset; // offset of start of guarded section unsigned endoffset; // ending offset of guarded section int last_index; // previous index (enclosing guarded section) unsigned catchoffset; // offset to catch block from symbol void *finally; // finally code to execute } guard[]; catchoffset: unsigned ncatches; // number of catch blocks { void *type; // symbol representing type unsigned bpoffset; // EBP offset of catch variable void *handler; // catch handler code } catch[]; */ #define GUARD_SIZE 5 // number of 4 byte values in one guard sz = 0; // Address of start of function symbol_debug(funcsym_p); pdt = dtxoff(pdt,funcsym_p,0,TYnptr); sz += fsize; //printf("ehtables: func = %s, offset = x%x, startblock->Boffset = x%x\n", funcsym_p->Sident, funcsym_p->Soffset, startblock->Boffset); // Get offset of ESP from EBP spoff = cod3_spoff(); pdt = dtdword(pdt,spoff); sz += 4; // Offset from start of function to return code pdt = dtdword(pdt,retoffset); sz += 4; // First, calculate starting catch offset guarddim = 0; // max dimension of guard[] for (b = startblock; b; b = b->Bnext) { if (b->BC == BC_try && b->Bscope_index >= guarddim) guarddim = b->Bscope_index + 1; // printf("b->BC = %2d, Bscope_index = %2d, last_index = %2d, offset = x%x\n", // b->BC, b->Bscope_index, b->Blast_index, b->Boffset); } pdt = dtdword(pdt,guarddim); sz += 4; unsigned catchoffset = sz + guarddim * (GUARD_SIZE * 4); // Generate guard[] i = 0; for (b = startblock; b; b = b->Bnext) { //printf("b = %p, b->Btry = %p, b->offset = %x\n", b, b->Btry, b->Boffset); if (b->BC == BC_try) { dt_t *dt; block *bhandler; int nsucc; unsigned endoffset; block *bn; assert(b->Bscope_index >= i); if (i < b->Bscope_index) { int fillsize = (b->Bscope_index - i) * (GUARD_SIZE * 4); pdt = dtnzeros(pdt, fillsize); sz += fillsize; } i = b->Bscope_index + 1; nsucc = list_nitems(b->Bsucc); pdt = dtdword(pdt,b->Boffset - startblock->Boffset); // offset to start of block // Compute ending offset for (bn = b->Bnext; 1; bn = bn->Bnext) { //printf("\tbn = %p, bn->Btry = %p, bn->offset = %x\n", bn, bn->Btry, bn->Boffset); assert(bn); if (bn->Btry == b->Btry) { endoffset = bn->Boffset - startblock->Boffset; break; } } pdt = dtdword(pdt,endoffset); // offset past end of guarded block pdt = dtdword(pdt,b->Blast_index); // parent index if (b->jcatchvar) // if try-catch { pdt = dtdword(pdt,catchoffset); pdt = dtdword(pdt,0); // no finally handler catchoffset += 4 + (nsucc - 1) * (3 * 4); } else // else try-finally { assert(nsucc == 2); pdt = dtdword(pdt,0); // no catch offset bhandler = list_block(list_next(b->Bsucc)); assert(bhandler->BC == BC_finally); // To successor of BC_finally block bhandler = list_block(bhandler->Bsucc); pdt = dtxoff(pdt,funcsym_p,bhandler->Boffset - startblock->Boffset, TYnptr); // finally handler address //pdt = dtcoff(pdt,bhandler->Boffset); // finally handler address } sz += GUARD_SIZE + 4; } } // Generate catch[] for (b = startblock; b; b = b->Bnext) { if (b->BC == BC_try) { block *bhandler; int nsucc; if (b->jcatchvar) // if try-catch { list_t bl; nsucc = list_nitems(b->Bsucc); pdt = dtdword(pdt,nsucc - 1); // # of catch blocks sz += 4; for (bl = list_next(b->Bsucc); bl; bl = list_next(bl)) { block *bcatch = list_block(bl); pdt = dtxoff(pdt,bcatch->Bcatchtype,0,TYjhandle); pdt = dtdword(pdt,cod3_bpoffset(b->jcatchvar)); // EBP offset pdt = dtxoff(pdt,funcsym_p,bcatch->Boffset - startblock->Boffset, TYnptr); // catch handler address //pdt = dtcoff(pdt,bcatch->Boffset); // catch handler address sz += 3 * 4; } } } } assert(sz != 0); outdata(s); // output the scope table obj_ehtables(funcsym_p,funcsym_p->Ssize,s); #endif return NULL; }
void except_fillInEHTable(symbol *s) { unsigned fsize = NPTRSIZE; // target size of function pointer dt_t **pdt = &s->Sdt; /* void* pointer to start of function (Windows) unsigned offset of ESP from EBP unsigned offset from start of function to return code unsigned nguards; // dimension of guard[] (Linux) Guard guard[]; // sorted such that the enclosing guarded sections come first catchoffset: unsigned ncatches; // number of catch blocks { void *type; // symbol representing type unsigned bpoffset; // EBP offset of catch variable void *handler; // catch handler code } catch[]; */ /* Be careful of this, as we need the sizeof Guard on the target, not * in the compiler. */ unsigned GUARD_SIZE; if (config.ehmethod == EH_DM) GUARD_SIZE = (I64 ? 3*8 : 5*4); else if (config.ehmethod == EH_WIN32) GUARD_SIZE = 3*4; else assert(0); int sz = 0; // Address of start of function if (config.ehmethod == EH_WIN32) { symbol_debug(funcsym_p); pdt = dtxoff(pdt,funcsym_p,0,TYnptr); sz += fsize; } //printf("ehtables: func = %s, offset = x%x, startblock->Boffset = x%x\n", funcsym_p->Sident, funcsym_p->Soffset, startblock->Boffset); // Get offset of ESP from EBP long spoff = cod3_spoff(); pdt = dtdword(pdt,spoff); sz += 4; // Offset from start of function to return code pdt = dtdword(pdt,retoffset); sz += 4; // First, calculate starting catch offset int guarddim = 0; // max dimension of guard[] int ndctors = 0; // number of ESCdctor's for (block *b = startblock; b; b = b->Bnext) { if (b->BC == BC_try && b->Bscope_index >= guarddim) guarddim = b->Bscope_index + 1; // printf("b->BC = %2d, Bscope_index = %2d, last_index = %2d, offset = x%x\n", // b->BC, b->Bscope_index, b->Blast_index, b->Boffset); if (usednteh & EHcleanup) for (code *c = b->Bcode; c; c = code_next(c)) { if (c->Iop == (ESCAPE | ESCddtor)) ndctors++; } } //printf("guarddim = %d, ndctors = %d\n", guarddim, ndctors); if (config.ehmethod == EH_DM) { pdt = dtsize_t(pdt,guarddim + ndctors); sz += NPTRSIZE; } unsigned catchoffset = sz + (guarddim + ndctors) * GUARD_SIZE; // Generate guard[] int i = 0; for (block *b = startblock; b; b = b->Bnext) { //printf("b = %p, b->Btry = %p, b->offset = %x\n", b, b->Btry, b->Boffset); if (b->BC == BC_try) { assert(b->Bscope_index >= i); if (i < b->Bscope_index) { int fillsize = (b->Bscope_index - i) * GUARD_SIZE; pdt = dtnzeros(pdt, fillsize); sz += fillsize; } i = b->Bscope_index + 1; int nsucc = b->numSucc(); if (config.ehmethod == EH_DM) { //printf("DHandlerInfo: offset = %x", (int)(b->Boffset - startblock->Boffset)); pdt = dtdword(pdt,b->Boffset - startblock->Boffset); // offset to start of block // Compute ending offset unsigned endoffset; for (block *bn = b->Bnext; 1; bn = bn->Bnext) { //printf("\tbn = %p, bn->Btry = %p, bn->offset = %x\n", bn, bn->Btry, bn->Boffset); assert(bn); if (bn->Btry == b->Btry) { endoffset = bn->Boffset - startblock->Boffset; break; } } //printf(" endoffset = %x, prev_index = %d\n", endoffset, b->Blast_index); pdt = dtdword(pdt,endoffset); // offset past end of guarded block } pdt = dtdword(pdt,b->Blast_index); // parent index if (b->jcatchvar) // if try-catch { assert(catchoffset); pdt = dtdword(pdt,catchoffset); pdt = dtsize_t(pdt,0); // no finally handler catchoffset += NPTRSIZE + (nsucc - 1) * (3 * NPTRSIZE); } else // else try-finally { assert(nsucc == 2); pdt = dtdword(pdt,0); // no catch offset block *bhandler = b->nthSucc(1); assert(bhandler->BC == BC_finally); // To successor of BC_finally block bhandler = bhandler->nthSucc(0); // finally handler address if (config.ehmethod == EH_DM) { assert(bhandler->Boffset > startblock->Boffset); pdt = dtsize_t(pdt,bhandler->Boffset - startblock->Boffset); // finally handler offset } else pdt = dtcoff(pdt,bhandler->Boffset); } sz += GUARD_SIZE; } } /* Append to guard[] the guard blocks for temporaries that are created and destroyed * within a single expression. These are marked by the special instruction pairs * (ESCAPE | ESCdctor) and (ESCAPE | ESCddtor). */ if (usednteh & EHcleanup) { #define STACKINC 16 int stackbuf[STACKINC]; int *stack = stackbuf; int stackmax = STACKINC; int scopeindex = guarddim; for (block *b = startblock; b; b = b->Bnext) { /* Set up stack of scope indices */ stack[0] = b->Btry ? b->Btry->Bscope_index : -1; int stacki = 1; unsigned boffset = b->Boffset; for (code *c = b->Bcode; c; c = code_next(c)) { if (c->Iop == (ESCAPE | ESCdctor)) { code *c2 = code_next(c); if (config.flags2 & CFG2seh) nteh_patchindex(c2, scopeindex); if (config.ehmethod == EH_DM) pdt = dtdword(pdt,boffset - startblock->Boffset); // guard offset // Find corresponding ddtor instruction int n = 0; unsigned eoffset = boffset; unsigned foffset; for (; 1; c2 = code_next(c2)) { // Bugzilla 13720: optimizer might elide the corresponding ddtor if (!c2) goto Lnodtor; if (c2->Iop == (ESCAPE | ESCddtor)) { if (n) n--; else { foffset = eoffset; code *cf = code_next(c2); if (config.flags2 & CFG2seh) { nteh_patchindex(cf, stack[stacki - 1]); foffset += calccodsize(cf); cf = code_next(cf); } foffset += calccodsize(cf); while (!cf->isJumpOP()) { cf = code_next(cf); foffset += calccodsize(cf); } // issue 9438 //cf = code_next(cf); //foffset += calccodsize(cf); if (config.ehmethod == EH_DM) pdt = dtdword(pdt,eoffset - startblock->Boffset); // guard offset break; } } else if (c2->Iop == (ESCAPE | ESCdctor)) { n++; } else eoffset += calccodsize(c2); } //printf("boffset = %x, eoffset = %x, foffset = %x\n", boffset, eoffset, foffset); pdt = dtdword(pdt,stack[stacki - 1]); // parent index pdt = dtdword(pdt,0); // no catch offset if (config.ehmethod == EH_DM) { assert(foffset > startblock->Boffset); pdt = dtsize_t(pdt,foffset - startblock->Boffset); // finally handler offset } else pdt = dtcoff(pdt,foffset); // finally handler address if (stacki == stackmax) { // stack[] is out of space; enlarge it int *pi = (int *)malloc((stackmax + STACKINC) * sizeof(int)); assert(pi); memcpy(pi, stack, stackmax * sizeof(int)); if (stack != stackbuf) free(stack); stack = pi; stackmax += STACKINC; } stack[stacki++] = scopeindex; ++scopeindex; sz += GUARD_SIZE; } else if (c->Iop == (ESCAPE | ESCddtor)) { stacki--; assert(stacki != 0); } Lnodtor: boffset += calccodsize(c); } } if (stack != stackbuf) free(stack); } // Generate catch[] for (block *b = startblock; b; b = b->Bnext) { if (b->BC == BC_try && b->jcatchvar) // if try-catch { int nsucc = b->numSucc(); pdt = dtsize_t(pdt,nsucc - 1); // # of catch blocks sz += NPTRSIZE; for (int i = 1; i < nsucc; ++i) { block *bcatch = b->nthSucc(i); pdt = dtxoff(pdt,bcatch->Bcatchtype,0,TYnptr); pdt = dtsize_t(pdt,cod3_bpoffset(b->jcatchvar)); // EBP offset // catch handler address if (config.ehmethod == EH_DM) { assert(bcatch->Boffset > startblock->Boffset); pdt = dtsize_t(pdt,bcatch->Boffset - startblock->Boffset); // catch handler offset } else pdt = dtcoff(pdt,bcatch->Boffset); sz += 3 * NPTRSIZE; } } } assert(sz != 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::toDt() { //printf("ArrayInitializer::toDt('%s')\n", toChars()); Type *tb = type->toBasetype(); if (tb->ty == Tvector) tb = ((TypeVector *)tb)->basetype; Type *tn = tb->nextOf()->toBasetype(); //printf("\tdim = %d\n", dim); Dts dts; dts.setDim(dim); dts.zero(); unsigned size = tn->size(); unsigned length = 0; for (size_t i = 0; i < index.dim; i++) { Expression *idx = index[i]; if (idx) length = idx->toInteger(); //printf("\tindex[%d] = %p, length = %u, dim = %u\n", i, idx, length, dim); assert(length < dim); Initializer *val = value[i]; dt_t *dt = val->toDt(); if (dts[length]) error(loc, "duplicate initializations for index %d", length); dts[length] = dt; length++; } Expression *edefault = tb->nextOf()->defaultInit(); size_t n = 1; for (Type *tbn = tn; tbn->ty == Tsarray; tbn = tbn->nextOf()->toBasetype()) { TypeSArray *tsa = (TypeSArray *)tbn; n *= tsa->dim->toInteger(); } dt_t *d = NULL; dt_t **pdtend = &d; for (size_t i = 0; i < dim; i++) { dt_t *dt = dts[i]; if (dt) pdtend = dtcat(pdtend, dt); else { for (size_t j = 0; j < n; j++) pdtend = edefault->toDt(pdtend); } } switch (tb->ty) { case Tsarray: { size_t tadim; TypeSArray *ta = (TypeSArray *)tb; tadim = ta->dim->toInteger(); if (dim < tadim) { if (edefault->isBool(false)) // pad out end of array pdtend = dtnzeros(pdtend, size * (tadim - dim)); else { for (size_t i = dim; i < tadim; i++) { for (size_t j = 0; j < n; j++) pdtend = edefault->toDt(pdtend); } } } else if (dim > tadim) { error(loc, "too many initializers, %d, for array[%d]", dim, tadim); } break; } case Tpointer: case Tarray: { dt_t *dtarray = d; d = NULL; if (tb->ty == Tarray) dtsize_t(&d, dim); dtdtoff(&d, dtarray, 0); break; } default: assert(0); } return d; }
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(); }
dt_t *StructInitializer::toDt() { Array dts; dt_t *dt; dt_t *d; dt_t **pdtend; unsigned offset; //printf("StructInitializer::toDt('%s')\n", toChars()); dts.setDim(ad->fields.dim); dts.zero(); for (size_t i = 0; i < vars.dim; i++) { VarDeclaration *v = (VarDeclaration *)vars.data[i]; Initializer *val = (Initializer *)value.data[i]; //printf("vars[%d] = %s\n", i, v->toChars()); for (size_t j = 0; 1; j++) { assert(j < dts.dim); //printf(" adfield[%d] = %s\n", j, ((VarDeclaration *)ad->fields.data[j])->toChars()); if ((VarDeclaration *)ad->fields.data[j] == v) { if (dts.data[j]) error(loc, "field %s of %s already initialized", v->toChars(), ad->toChars()); dts.data[j] = (void *)val->toDt(); break; } } } dt = NULL; pdtend = &dt; offset = 0; for (size_t j = 0; j < dts.dim; j++) { VarDeclaration *v = (VarDeclaration *)ad->fields.data[j]; d = (dt_t *)dts.data[j]; if (!d) { // An instance specific initializer was not provided. // Look to see if there's a default initializer from the // struct definition if (v->init) { d = v->init->toDt(); } else if (v->offset >= offset) { unsigned k; unsigned offset2 = v->offset + v->type->size(); // Make sure this field does not overlap any explicitly // initialized field. for (k = j + 1; 1; k++) { if (k == dts.dim) // didn't find any overlap { v->type->toDt(&d); break; } VarDeclaration *v2 = (VarDeclaration *)ad->fields.data[k]; if (v2->offset < offset2 && dts.data[k]) break; // overlap } } } if (d) { if (v->offset < offset) error(loc, "duplicate union initialization for %s", v->toChars()); else { size_t sz = dt_size(d); size_t vsz = v->type->size(); size_t voffset = v->offset; if (sz > vsz) { assert(v->type->ty == Tsarray && vsz == 0); error(loc, "zero length array %s has non-zero length initializer", v->toChars()); } unsigned dim = 1; for (Type *vt = v->type->toBasetype(); vt->ty == Tsarray; vt = vt->next->toBasetype()) { TypeSArray *tsa = (TypeSArray *)vt; dim *= tsa->dim->toInteger(); } //printf("sz = %d, dim = %d, vsz = %d\n", sz, dim, vsz); assert(sz == vsz || sz * dim <= vsz); for (size_t i = 0; i < dim; i++) { if (offset < voffset) pdtend = dtnzeros(pdtend, voffset - offset); if (!d) { if (v->init) d = v->init->toDt(); else v->type->toDt(&d); } pdtend = dtcat(pdtend, d); d = NULL; offset = voffset + sz; voffset += vsz / dim; if (sz == vsz) break; } } } } if (offset < ad->structsize) dtnzeros(pdtend, ad->structsize - offset); #ifdef IN_GCC dt_t * cdt = NULL; dtcontainer(&cdt, ad->type, dt); dt = cdt; #endif return dt; }
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 except_fillInEHTable(symbol *s) { unsigned fsize = NPTRSIZE; // target size of function pointer dt_t **pdt = &s->Sdt; /* void* pointer to start of function unsigned offset of ESP from EBP unsigned offset from start of function to return code unsigned nguards; // dimension of guard[] (Linux) Guard guard[]; catchoffset: unsigned ncatches; // number of catch blocks { void *type; // symbol representing type unsigned bpoffset; // EBP offset of catch variable void *handler; // catch handler code } catch[]; */ /* Be careful of this, as we need the sizeof Guard on the target, not * in the compiler. */ #if OUREH #define GUARD_SIZE (I64 ? 3*8 : 5*4) // sizeof(Guard) #else #define GUARD_SIZE (sizeof(Guard)) #endif int sz = 0; // Address of start of function symbol_debug(funcsym_p); pdt = dtxoff(pdt,funcsym_p,0,TYnptr); sz += fsize; //printf("ehtables: func = %s, offset = x%x, startblock->Boffset = x%x\n", funcsym_p->Sident, funcsym_p->Soffset, startblock->Boffset); // Get offset of ESP from EBP long spoff = cod3_spoff(); pdt = dtdword(pdt,spoff); sz += 4; // Offset from start of function to return code pdt = dtdword(pdt,retoffset); sz += 4; // First, calculate starting catch offset int guarddim = 0; // max dimension of guard[] for (block *b = startblock; b; b = b->Bnext) { if (b->BC == BC_try && b->Bscope_index >= guarddim) guarddim = b->Bscope_index + 1; // printf("b->BC = %2d, Bscope_index = %2d, last_index = %2d, offset = x%x\n", // b->BC, b->Bscope_index, b->Blast_index, b->Boffset); } #if OUREH pdt = dtsize_t(pdt,guarddim); sz += NPTRSIZE; #endif unsigned catchoffset = sz + guarddim * GUARD_SIZE; // Generate guard[] int i = 0; for (block *b = startblock; b; b = b->Bnext) { //printf("b = %p, b->Btry = %p, b->offset = %x\n", b, b->Btry, b->Boffset); if (b->BC == BC_try) { assert(b->Bscope_index >= i); if (i < b->Bscope_index) { int fillsize = (b->Bscope_index - i) * GUARD_SIZE; pdt = dtnzeros(pdt, fillsize); sz += fillsize; } i = b->Bscope_index + 1; int nsucc = list_nitems(b->Bsucc); #if OUREH //printf("DHandlerInfo: offset = %x", (int)(b->Boffset - startblock->Boffset)); pdt = dtdword(pdt,b->Boffset - startblock->Boffset); // offset to start of block // Compute ending offset unsigned endoffset; for (block *bn = b->Bnext; 1; bn = bn->Bnext) { //printf("\tbn = %p, bn->Btry = %p, bn->offset = %x\n", bn, bn->Btry, bn->Boffset); assert(bn); if (bn->Btry == b->Btry) { endoffset = bn->Boffset - startblock->Boffset; break; } } //printf(" endoffset = %x, prev_index = %d\n", endoffset, b->Blast_index); pdt = dtdword(pdt,endoffset); // offset past end of guarded block #endif pdt = dtdword(pdt,b->Blast_index); // parent index if (b->jcatchvar) // if try-catch { pdt = dtdword(pdt,catchoffset); pdt = dtsize_t(pdt,0); // no finally handler catchoffset += NPTRSIZE + (nsucc - 1) * (3 * NPTRSIZE); } else // else try-finally { assert(nsucc == 2); pdt = dtdword(pdt,0); // no catch offset block *bhandler = list_block(list_next(b->Bsucc)); assert(bhandler->BC == BC_finally); // To successor of BC_finally block bhandler = list_block(bhandler->Bsucc); #if OUREH pdt = dtxoff(pdt,funcsym_p,bhandler->Boffset - startblock->Boffset, TYnptr); // finally handler address #else pdt = dtcoff(pdt,bhandler->Boffset); // finally handler address #endif } sz += GUARD_SIZE; } } // Generate catch[] for (block *b = startblock; b; b = b->Bnext) { if (b->BC == BC_try) { block *bhandler; int nsucc; if (b->jcatchvar) // if try-catch { list_t bl; nsucc = list_nitems(b->Bsucc); pdt = dtsize_t(pdt,nsucc - 1); // # of catch blocks sz += NPTRSIZE; for (bl = list_next(b->Bsucc); bl; bl = list_next(bl)) { block *bcatch = list_block(bl); pdt = dtxoff(pdt,bcatch->Bcatchtype,0,TYjhandle); pdt = dtsize_t(pdt,cod3_bpoffset(b->jcatchvar)); // EBP offset #if OUREH pdt = dtxoff(pdt,funcsym_p,bcatch->Boffset - startblock->Boffset, TYnptr); // catch handler address #else pdt = dtcoff(pdt,bcatch->Boffset); // catch handler address #endif sz += 3 * NPTRSIZE; } } } } assert(sz != 0); }