void Dsymbol::error(Loc loc, const char *format, ...) { if (!global.gag) { char *p = loc.toChars(); if (!*p) p = locToChars(); if (*p) fprintf(stdmsg, "%s: ", p); mem.free(p); fprintf(stdmsg, "%s %s ", kind(), toPrettyChars()); va_list ap; va_start(ap, format); vfprintf(stdmsg, format, ap); va_end(ap); fprintf(stdmsg, "\n"); fflush(stdmsg); } global.errors++; //fatal(); }
void Dsymbol::error(const char *format, ...) { //printf("Dsymbol::error()\n"); if (!global.gag) { char *p = locToChars(); if (*p) fprintf(stdmsg, "%s: ", p); mem.free(p); fprintf(stdmsg, "Error: "); if (isAnonymous()) fprintf(stdmsg, "%s ", kind()); else fprintf(stdmsg, "%s %s ", kind(), toPrettyChars()); va_list ap; va_start(ap, format); vfprintf(stdmsg, format, ap); va_end(ap); fprintf(stdmsg, "\n"); fflush(stdmsg); } global.errors++; //fatal(); }
void Dsymbol::error(Loc loc, const char *format, ...) { va_list ap; va_start(ap, format); ::verror(loc, format, ap, kind(), toPrettyChars()); va_end(ap); }
void Dsymbol::deprecation(const char *format, ...) { va_list ap; va_start(ap, format); ::vdeprecation(getLoc(), format, ap, kind(), toPrettyChars()); va_end(ap); }
void TypedefDeclaration::toDebug() { //printf("TypedefDeclaration::toDebug('%s')\n", toChars()); assert(config.fulltypes >= CV4); // If it is a member, it is handled by cvMember() if (!isMember()) { if (basetype->ty == Ttuple) return; const char *id = toPrettyChars(); idx_t typidx = cv4_typidx(basetype->toCtype()); if (config.fulltypes == CV8) cv8_udt(id, typidx); else { unsigned len = strlen(id); unsigned char *debsym = (unsigned char *) alloca(39 + IDOHD + len); // Output a 'user-defined type' for the tag name TOWORD(debsym + 2,S_UDT); TOIDX(debsym + 4,typidx); unsigned length = 2 + 2 + cgcv.sz_idx; length += cv_namestring(debsym + length,id); TOWORD(debsym,length - 2); assert(length <= 40 + len); objmod->write_bytes(SegData[DEBSYM],length,debsym); } } }
void Dsymbol::verror(Loc loc, const char *format, va_list ap) { if (!global.gag) { char *p = loc.toChars(); if (!*p) p = locToChars(); if (*p) fprintf(stdmsg, "%s: ", p); mem.free(p); fprintf(stdmsg, "Error: "); fprintf(stdmsg, "%s %s ", kind(), toPrettyChars()); vfprintf(stdmsg, format, ap); fprintf(stdmsg, "\n"); fflush(stdmsg); //halt(); } else { global.gaggedErrors++; } global.errors++; //fatal(); }
void EnumDeclaration::toDebug() { //printf("EnumDeclaration::toDebug('%s')\n", toChars()); assert(config.fulltypes >= CV4); // If it is a member, it is handled by cvMember() if (!isMember()) { unsigned length; const char *id = toPrettyChars(); idx_t typidx = cv4_Denum(this); unsigned len = strlen(id); unsigned char *debsym = (unsigned char *) alloca(39 + IDOHD + len); // Output a 'user-defined type' for the tag name TOWORD(debsym + 2,S_UDT); TOIDX(debsym + 4,typidx); length = 2 + 2 + cgcv.sz_idx; length += cv_namestring(debsym + length,id); TOWORD(debsym,length - 2); assert(length <= 40 + len); obj_write_bytes(SegData[DEBSYM],length,debsym); } }
void Dsymbol::error(const char *format, ...) { //printf("Dsymbol::error()\n"); if (!loc.filename) // avoid bug 5861. { Module *m = getModule(); if (m && m->srcfile) loc.filename = m->srcfile->toChars(); } va_list ap; va_start(ap, format); verror(loc, format, ap, kind(), toPrettyChars()); va_end(ap); }
void FuncDeclaration::inlineScan() { InlineScanState iss; #if LOG printf("FuncDeclaration::inlineScan('%s')\n", toPrettyChars()); #endif memset(&iss, 0, sizeof(iss)); iss.fd = this; if (fbody && !naked) { inlineNest++; fbody = fbody->inlineScan(&iss); inlineNest--; } }
void Module::jsonProperties(JsonOut *json) { #if 0 Dsymbol::jsonProperties(json); if (md && md->packages) { json->propertyStart("package"); json->arrayStart(); for (size_t i = 0; i < md->packages->dim; i++) { Identifier *pid = (*md->packages)[i]; json->item(pid->toChars()); } json->arrayEnd(); } json->property("prettyName", toPrettyChars()); #endif }
Symbol *VarDeclaration::toSymbol() { //printf("VarDeclaration::toSymbol(%s)\n", toChars()); //if (needThis()) *(char*)0=0; assert(!needThis()); if (!csym) { TYPE *t; const char *id; if (isDataseg()) id = mangle(); else id = ident->toChars(); Symbol *s = symbol_calloc(id); s->Salignment = alignment; if (storage_class & (STCout | STCref)) { // should be TYref, but problems in back end t = type_pointer(type->toCtype()); } else if (storage_class & STClazy) { if (config.exe == EX_WIN64 && isParameter()) t = type_fake(TYnptr); else t = type_fake(TYdelegate); // Tdelegate as C type t->Tcount++; } else if (isParameter()) { if (config.exe == EX_WIN64 && type->size(Loc()) > REGSIZE) { // should be TYref, but problems in back end t = type_pointer(type->toCtype()); } else { t = type->toCParamtype(); t->Tcount++; } } else { t = type->toCtype(); t->Tcount++; } if (isDataseg()) { if (isThreadlocal()) { /* Thread local storage */ TYPE *ts = t; ts->Tcount++; // make sure a different t is allocated type_setty(&t, t->Tty | mTYthread); ts->Tcount--; if (global.params.vtls) { char *p = loc.toChars(); fprintf(stderr, "%s: %s is thread local\n", p ? p : "", toChars()); if (p) mem.free(p); } } s->Sclass = SCextern; s->Sfl = FLextern; slist_add(s); /* if it's global or static, then it needs to have a qualified but unmangled name. * This gives some explanation of the separation in treating name mangling. * It applies to PDB format, but should apply to CV as PDB derives from CV. * http://msdn.microsoft.com/en-us/library/ff553493(VS.85).aspx */ s->prettyIdent = toPrettyChars(); } else { s->Sclass = SCauto; s->Sfl = FLauto; if (nestedrefs.dim) { /* Symbol is accessed by a nested function. Make sure * it is not put in a register, and that the optimizer * assumes it is modified across function calls and pointer * dereferences. */ //printf("\tnested ref, not register\n"); type_setcv(&t, t->Tty | mTYvolatile); } } if (ident == Id::va_argsave) /* __va_argsave is set outside of the realm of the optimizer, * so we tell the optimizer to leave it alone */ type_setcv(&t, t->Tty | mTYvolatile); mangle_t m = 0; switch (linkage) { case LINKwindows: m = mTYman_std; break; case LINKpascal: m = mTYman_pas; break; case LINKc: m = mTYman_c; break; case LINKd: m = mTYman_d; break; case LINKcpp: { m = mTYman_cpp; s->Sflags = SFLpublic; Dsymbol *parent = toParent(); ClassDeclaration *cd = parent->isClassDeclaration(); if (cd) { ::type *tc = cd->type->toCtype(); s->Sscope = tc->Tnext->Ttag; } StructDeclaration *sd = parent->isStructDeclaration(); if (sd) { ::type *ts = sd->type->toCtype(); s->Sscope = ts->Ttag; } break; } default: printf("linkage = %d\n", linkage); assert(0); } type_setmangle(&t, m); s->Stype = t; csym = s; } return csym; }
void ClassDeclaration::toDebug() { idx_t typidx = 0; //printf("ClassDeclaration::toDebug('%s')\n", toChars()); assert(config.fulltypes >= CV4); if (isAnonymous()) return /*0*/; if (typidx) // if reference already generated return /*typidx*/; // use already existing reference targ_size_t size; unsigned property = 0; if (!members) { size = 0; property |= 0x80; // forward reference } else size = structsize; if (parent->isAggregateDeclaration()) // if class is nested property |= 8; if (ctor || dtors.dim) property |= 2; // class has ctors and/or dtors // if (st->Sopoverload) // property |= 4; // class has overloaded operators // if (st->Scastoverload) // property |= 0x40; // class has casting methods // if (st->Sopeq && !(st->Sopeq->Sfunc->Fflags & Fnodebug)) // property |= 0x20; // class has overloaded assignment #if DMDV1 const char *id = toPrettyChars(); #else const char *id = isCPPinterface() ? ident->toChars() : toPrettyChars(); #endif unsigned leaf = config.fulltypes == CV8 ? LF_CLASS_V3 : LF_CLASS; unsigned numidx = (leaf == LF_CLASS_V3) ? 18 : 12; unsigned len = numidx + cv4_numericbytes(size); debtyp_t *d = debtyp_alloc(len + cv_stringbytes(id)); cv4_storenumeric(d->data + numidx,size); len += cv_namestring(d->data + len,id); idx_t vshapeidx = 0; if (1) { size_t n = vtbl.dim; // number of virtual functions if (n) { // 4 bits per descriptor debtyp_t *vshape = debtyp_alloc(4 + (n + 1) / 2); TOWORD(vshape->data,LF_VTSHAPE); TOWORD(vshape->data + 2,n); n = 0; unsigned char descriptor = 0; for (size_t i = 0; i < vtbl.dim; i++) { FuncDeclaration *fd = (FuncDeclaration *)vtbl[i]; //if (intsize == 4) descriptor |= 5; vshape->data[4 + n / 2] = descriptor; descriptor <<= 4; n++; } vshapeidx = cv_debtyp(vshape); } } if (leaf == LF_CLASS) { TOWORD(d->data + 8,0); // dList TOWORD(d->data + 10,vshapeidx); } else if (leaf == LF_CLASS_V3) { TOLONG(d->data + 10,0); // dList TOLONG(d->data + 14,vshapeidx); } TOWORD(d->data,leaf); // Assign a number to prevent infinite recursion if a struct member // references the same struct. unsigned length_save = d->length; d->length = 0; // so cv_debtyp() will allocate new typidx = cv_debtyp(d); d->length = length_save; // restore length if (!members) // if reference only { if (leaf == LF_CLASS_V3) { TOWORD(d->data + 2,0); // count: number of fields is 0 TOLONG(d->data + 6,0); // field list is 0 TOWORD(d->data + 4,property); } else { TOWORD(d->data + 2,0); // count: number of fields is 0 TOWORD(d->data + 4,0); // field list is 0 TOWORD(d->data + 6,property); } return /*typidx*/; } // Compute the number of fields (nfields), and the length of the fieldlist record (fnamelen) CvMemberCount mc; mc.nfields = 0; mc.fnamelen = 2; /* Adding in the base classes causes VS 2010 debugger to refuse to display any * of the fields. I have not been able to determine why. * (Could it be because the base class is "forward referenced"?) * It does work with VS 2012. */ bool addInBaseClasses = true; if (addInBaseClasses) { // Add in base classes for (size_t i = 0; i < baseclasses->dim; i++) { BaseClass *bc = (*baseclasses)[i]; mc.nfields++; unsigned elementlen = 4 + cgcv.sz_idx + cv4_numericbytes(bc->offset); elementlen = cv_align(NULL, elementlen); mc.fnamelen += elementlen; } } for (size_t i = 0; i < members->dim; i++) { Dsymbol *s = (*members)[i]; s->apply(&cv_mem_count, &mc); } unsigned nfields = mc.nfields; unsigned fnamelen = mc.fnamelen; int count = nfields; TOWORD(d->data + 2,count); // Generate fieldlist type record debtyp_t *dt = debtyp_alloc(fnamelen); unsigned char *p = dt->data; // And fill it in TOWORD(p,config.fulltypes == CV8 ? LF_FIELDLIST_V2 : LF_FIELDLIST); p += 2; if (addInBaseClasses) { // Add in base classes for (size_t i = 0; i < baseclasses->dim; i++) { BaseClass *bc = (*baseclasses)[i]; idx_t typidx = cv4_typidx(bc->base->type->toCtype()->Tnext); unsigned attribute = PROTtoATTR(bc->protection); unsigned elementlen; switch (config.fulltypes) { case CV8: TOWORD(p, LF_BCLASS_V2); TOWORD(p + 2,attribute); TOLONG(p + 4,typidx); elementlen = 8; break; case CV4: TOWORD(p, LF_BCLASS); TOWORD(p + 2,typidx); TOWORD(p + 4,attribute); elementlen = 6; break; } cv4_storenumeric(p + elementlen, bc->offset); elementlen += cv4_numericbytes(bc->offset); elementlen = cv_align(p + elementlen, elementlen); p += elementlen; } } for (size_t i = 0; i < members->dim; i++) { Dsymbol *s = (*members)[i]; s->apply(&cv_mem_p, &p); } //dbg_printf("fnamelen = %d, p-dt->data = %d\n",fnamelen,p-dt->data); assert(p - dt->data == fnamelen); idx_t fieldlist = cv_debtyp(dt); TOWORD(d->data + 2,count); if (config.fulltypes == CV8) { TOWORD(d->data + 4,property); TOLONG(d->data + 6,fieldlist); } else { TOWORD(d->data + 4,fieldlist); TOWORD(d->data + 6,property); } // cv4_outsym(s); if (config.fulltypes == CV8) cv8_udt(id, typidx); else { size_t idlen = strlen(id); unsigned char *debsym = (unsigned char *) alloca(39 + IDOHD + idlen); // Output a 'user-defined type' for the tag name TOWORD(debsym + 2,S_UDT); TOIDX(debsym + 4,typidx); unsigned length = 2 + 2 + cgcv.sz_idx; length += cv_namestring(debsym + length,id); TOWORD(debsym,length - 2); assert(length <= 40 + idlen); objmod->write_bytes(SegData[DEBSYM],length,debsym); } // return typidx; }
void StructDeclaration::toDebug() { idx_t typidx = 0; //printf("StructDeclaration::toDebug('%s')\n", toChars()); assert(config.fulltypes >= CV4); if (isAnonymous()) return /*0*/; if (typidx) // if reference already generated return /*typidx*/; // use already existing reference targ_size_t size; unsigned property = 0; if (!members) { size = 0; property |= 0x80; // forward reference } else size = structsize; if (parent->isAggregateDeclaration()) // if class is nested property |= 8; // if (st->Sctor || st->Sdtor) // property |= 2; // class has ctors and/or dtors // if (st->Sopoverload) // property |= 4; // class has overloaded operators // if (st->Scastoverload) // property |= 0x40; // class has casting methods // if (st->Sopeq && !(st->Sopeq->Sfunc->Fflags & Fnodebug)) // property |= 0x20; // class has overloaded assignment const char *id = toPrettyChars(); unsigned leaf = isUnionDeclaration() ? LF_UNION : LF_STRUCTURE; if (config.fulltypes == CV8) leaf = leaf == LF_UNION ? LF_UNION_V3 : LF_STRUCTURE_V3; unsigned numidx; switch (leaf) { case LF_UNION: numidx = 8; break; case LF_UNION_V3: numidx = 10; break; case LF_STRUCTURE: numidx = 12; break; case LF_STRUCTURE_V3: numidx = 18; break; } unsigned len = numidx + cv4_numericbytes(size); debtyp_t *d = debtyp_alloc(len + cv_stringbytes(id)); cv4_storenumeric(d->data + numidx,size); len += cv_namestring(d->data + len,id); if (leaf == LF_STRUCTURE) { TOWORD(d->data + 8,0); // dList TOWORD(d->data + 10,0); // vshape is 0 (no virtual functions) } else if (leaf == LF_STRUCTURE_V3) { TOLONG(d->data + 10,0); // dList TOLONG(d->data + 14,0); // vshape is 0 (no virtual functions) } TOWORD(d->data,leaf); // Assign a number to prevent infinite recursion if a struct member // references the same struct. unsigned length_save = d->length; d->length = 0; // so cv_debtyp() will allocate new typidx = cv_debtyp(d); d->length = length_save; // restore length if (!members) // if reference only { if (config.fulltypes == CV8) { TOWORD(d->data + 2,0); // count: number of fields is 0 TOLONG(d->data + 6,0); // field list is 0 TOWORD(d->data + 4,property); } else { TOWORD(d->data + 2,0); // count: number of fields is 0 TOWORD(d->data + 4,0); // field list is 0 TOWORD(d->data + 6,property); } return /*typidx*/; } // Compute the number of fields (nfields), and the length of the fieldlist record (fnamelen) CvMemberCount mc; mc.nfields = 0; mc.fnamelen = 2; for (size_t i = 0; i < members->dim; i++) { Dsymbol *s = (*members)[i]; s->apply(&cv_mem_count, &mc); } unsigned nfields = mc.nfields; unsigned fnamelen = mc.fnamelen; int count = nfields; // COUNT field in LF_CLASS // Generate fieldlist type record debtyp_t *dt = debtyp_alloc(fnamelen); unsigned char *p = dt->data; // And fill it in TOWORD(p,config.fulltypes == CV8 ? LF_FIELDLIST_V2 : LF_FIELDLIST); p += 2; for (size_t i = 0; i < members->dim; i++) { Dsymbol *s = (*members)[i]; s->apply(&cv_mem_p, &p); } //dbg_printf("fnamelen = %d, p-dt->data = %d\n",fnamelen,p-dt->data); assert(p - dt->data == fnamelen); idx_t fieldlist = cv_debtyp(dt); TOWORD(d->data + 2,count); if (config.fulltypes == CV8) { TOWORD(d->data + 4,property); TOLONG(d->data + 6,fieldlist); } else { TOWORD(d->data + 4,fieldlist); TOWORD(d->data + 6,property); } // cv4_outsym(s); if (config.fulltypes == CV8) cv8_udt(id, typidx); else { size_t idlen = strlen(id); unsigned char *debsym = (unsigned char *) alloca(39 + IDOHD + idlen); // Output a 'user-defined type' for the tag name TOWORD(debsym + 2,S_UDT); TOIDX(debsym + 4,typidx); unsigned length = 2 + 2 + cgcv.sz_idx; length += cv_namestring(debsym + length,id); TOWORD(debsym,length - 2); assert(length <= 40 + idlen); objmod->write_bytes(SegData[DEBSYM],length,debsym); } // return typidx; }
void Module::parse() { //printf("Module::parse()\n"); char *srcname = srcfile->name->toChars(); //printf("Module::parse(srcname = '%s')\n", srcname); unsigned char *buf = srcfile->buffer; size_t buflen = srcfile->len; if (buflen >= 2) { /* Convert all non-UTF-8 formats to UTF-8. * BOM : http://www.unicode.org/faq/utf_bom.html * 00 00 FE FF UTF-32BE, big-endian * FF FE 00 00 UTF-32LE, little-endian * FE FF UTF-16BE, big-endian * FF FE UTF-16LE, little-endian * EF BB BF UTF-8 */ unsigned le; unsigned bom = 1; // assume there's a BOM if (buf[0] == 0xFF && buf[1] == 0xFE) { if (buflen >= 4 && buf[2] == 0 && buf[3] == 0) { // UTF-32LE le = 1; Lutf32: OutBuffer dbuf; unsigned *pu = (unsigned *)(buf); unsigned *pumax = &pu[buflen / 4]; if (buflen & 3) { error("odd length of UTF-32 char source %u", buflen); fatal(); } dbuf.reserve(buflen / 4); for (pu += bom; pu < pumax; pu++) { unsigned u; u = le ? readlongLE(pu) : readlongBE(pu); if (u & ~0x7F) { if (u > 0x10FFFF) { error("UTF-32 value %08x greater than 0x10FFFF", u); fatal(); } dbuf.writeUTF8(u); } else dbuf.writeByte(u); } dbuf.writeByte(0); // add 0 as sentinel for scanner buflen = dbuf.offset - 1; // don't include sentinel in count buf = (unsigned char *) dbuf.extractData(); } else { // UTF-16LE (X86) // Convert it to UTF-8 le = 1; Lutf16: OutBuffer dbuf; unsigned short *pu = (unsigned short *)(buf); unsigned short *pumax = &pu[buflen / 2]; if (buflen & 1) { error("odd length of UTF-16 char source %u", buflen); fatal(); } dbuf.reserve(buflen / 2); for (pu += bom; pu < pumax; pu++) { unsigned u; u = le ? readwordLE(pu) : readwordBE(pu); if (u & ~0x7F) { if (u >= 0xD800 && u <= 0xDBFF) { unsigned u2; if (++pu > pumax) { error("surrogate UTF-16 high value %04x at EOF", u); fatal(); } u2 = le ? readwordLE(pu) : readwordBE(pu); if (u2 < 0xDC00 || u2 > 0xDFFF) { error("surrogate UTF-16 low value %04x out of range", u2); fatal(); } u = (u - 0xD7C0) << 10; u |= (u2 - 0xDC00); } else if (u >= 0xDC00 && u <= 0xDFFF) { error("unpaired surrogate UTF-16 value %04x", u); fatal(); } else if (u == 0xFFFE || u == 0xFFFF) { error("illegal UTF-16 value %04x", u); fatal(); } dbuf.writeUTF8(u); } else dbuf.writeByte(u); } dbuf.writeByte(0); // add 0 as sentinel for scanner buflen = dbuf.offset - 1; // don't include sentinel in count buf = (unsigned char *) dbuf.extractData(); } } else if (buf[0] == 0xFE && buf[1] == 0xFF) { // UTF-16BE le = 0; goto Lutf16; } else if (buflen >= 4 && buf[0] == 0 && buf[1] == 0 && buf[2] == 0xFE && buf[3] == 0xFF) { // UTF-32BE le = 0; goto Lutf32; } else if (buflen >= 3 && buf[0] == 0xEF && buf[1] == 0xBB && buf[2] == 0xBF) { // UTF-8 buf += 3; buflen -= 3; } else { /* There is no BOM. Make use of Arcane Jill's insight that * the first char of D source must be ASCII to * figure out the encoding. */ bom = 0; if (buflen >= 4) { if (buf[1] == 0 && buf[2] == 0 && buf[3] == 0) { // UTF-32LE le = 1; goto Lutf32; } else if (buf[0] == 0 && buf[1] == 0 && buf[2] == 0) { // UTF-32BE le = 0; goto Lutf32; } } if (buflen >= 2) { if (buf[1] == 0) { // UTF-16LE le = 1; goto Lutf16; } else if (buf[0] == 0) { // UTF-16BE le = 0; goto Lutf16; } } // It's UTF-8 if (buf[0] >= 0x80) { error("source file must start with BOM or ASCII character, not \\x%02X", buf[0]); fatal(); } } } #ifdef IN_GCC // dump utf-8 encoded source if (global.params.dump_source) { // %% srcname could contain a path ... d_gcc_dump_source(srcname, "utf-8", buf, buflen); } #endif /* If it starts with the string "Ddoc", then it's a documentation * source file. */ if (buflen >= 4 && memcmp(buf, "Ddoc", 4) == 0) { comment = buf + 4; isDocFile = 1; if (!docfile) setDocfile(); return; } Parser p(this, buf, buflen, docfile != NULL); p.nextToken(); members = p.parseModule(); if (srcfile->ref == 0) ::free(srcfile->buffer); srcfile->buffer = NULL; srcfile->len = 0; md = p.md; numlines = p.loc.linnum; DsymbolTable *dst; if (md) { this->ident = md->id; this->safe = md->safe; Package *ppack = NULL; dst = Package::resolve(md->packages, &this->parent, &ppack); if (ppack && ppack->isModule()) { error(loc, "package name '%s' in file %s conflicts with usage as a module name in file %s", ppack->toChars(), srcname, ppack->isModule()->srcfile->toChars()); dst = modules; } } else { dst = modules; /* Check to see if module name is a valid identifier */ if (!Lexer::isValidIdentifier(this->ident->toChars())) error("has non-identifier characters in filename, use module declaration instead"); } // Update global list of modules if (!dst->insert(this)) { Dsymbol *prev = dst->lookup(ident); assert(prev); Module *mprev = prev->isModule(); if (mprev) { if (strcmp(srcname, mprev->srcfile->toChars()) == 0) error(loc, "from file %s must be imported as module '%s'", srcname, toPrettyChars()); else error(loc, "from file %s conflicts with another module %s from file %s", srcname, mprev->toChars(), mprev->srcfile->toChars()); } else { Package *pkg = prev->isPackage(); assert(pkg); error(pkg->loc, "from file %s conflicts with package name %s", srcname, pkg->toChars()); } } else { amodules.push(this); } }
void Module::genobjfile(bool multiobj) { //EEcontext *ee = env->getEEcontext(); //printf("Module::genobjfile(multiobj = %d) %s\n", multiobj, toChars()); if (ident == Id::entrypoint) { bool v = global.params.verbose; global.params.verbose = false; for (size_t i = 0; i < members->dim; i++) { Dsymbol *member = (*members)[i]; //printf("toObjFile %s %s\n", member->kind(), member->toChars()); member->toObjFile(global.params.multiobj); } global.params.verbose = v; return; } 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 = toSymbol(m); //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(this), 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"); ssharedctor = callFuncsAndGates(this, &ssharedctors, (StaticDtorDeclarations *)&esharedctorgates, "__modsharedctor"); sshareddtor = callFuncsAndGates(this, &sshareddtors, NULL, "__modshareddtor"); 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(); genhelpers(false); objmod->termfile(); }
void Module::genmoduleinfo() { //printf("Module::genmoduleinfo() %s\n", toChars()); if (! Module::moduleinfo) { ObjectNotFound(Id::ModuleInfo); } Symbol *msym = toSymbol(this); ////////////////////////////////////////////// csym->Sclass = SCglobal; csym->Sfl = FLdata; dt_t *dt = NULL; ClassDeclarations aclasses; //printf("members->dim = %d\n", members->dim); for (size_t i = 0; i < members->dim; i++) { Dsymbol *member = (*members)[i]; //printf("\tmember '%s'\n", member->toChars()); member->addLocalClass(&aclasses); } // importedModules[] size_t aimports_dim = aimports.dim; for (size_t i = 0; i < aimports.dim; i++) { Module *m = aimports[i]; if (!m->needmoduleinfo) aimports_dim--; } FuncDeclaration *sgetmembers = 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 (!needmoduleinfo) flags |= MIstandalone; if (sctor) flags |= MItlsctor; if (sdtor) flags |= MItlsdtor; if (ssharedctor) flags |= MIctor; if (sshareddtor) flags |= MIdtor; if (sgetmembers) flags |= MIxgetMembers; if (sictor) flags |= MIictor; if (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, sctor, 0, TYnptr); if (flags & MItlsdtor) dtxoff(&dt, sdtor, 0, TYnptr); if (flags & MIctor) dtxoff(&dt, ssharedctor, 0, TYnptr); if (flags & MIdtor) dtxoff(&dt, sshareddtor, 0, TYnptr); if (flags & MIxgetMembers) dtxoff(&dt, toSymbol(sgetmembers), 0, TYnptr); if (flags & MIictor) dtxoff(&dt, sictor, 0, TYnptr); if (flags & MIunitTest) dtxoff(&dt, stest, 0, TYnptr); if (flags & MIimportedModules) { dtsize_t(&dt, aimports_dim); for (size_t i = 0; i < aimports.dim; i++) { Module *m = aimports[i]; if (m->needmoduleinfo) { Symbol *s = toSymbol(m); /* 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 nameoffset = dt_size(dt); const char *name = toPrettyChars(); namelen = strlen(name); dtnbytes(&dt, namelen + 1, name); //printf("nameoffset = x%x\n", nameoffset); } csym->Sdt = dt; // Cannot be CONST because the startup code sets flag bits in it outdata(csym); ////////////////////////////////////////////// objmod->moduleinfo(msym); }
llvm::Module* Module::genLLVMModule(llvm::LLVMContext& context) { bool logenabled = Logger::enabled(); if (llvmForceLogging && !logenabled) { Logger::enable(); } IF_LOG Logger::println("Generating module: %s", (md ? md->toChars() : toChars())); LOG_SCOPE; if (global.params.verbose_cg) printf("codegen: %s (%s)\n", toPrettyChars(), srcfile->toChars()); if (global.errors) { Logger::println("Aborting because of errors"); fatal(); } // name the module #if 1 // Temporary workaround for http://llvm.org/bugs/show_bug.cgi?id=11479 – // just use the source file name, as it is unlikely to collide with a // symbol name used somewhere in the module. llvm::StringRef mname(srcfile->toChars()); #else llvm::StringRef mname(toChars()); if (md != 0) mname = md->toChars(); #endif // create a new ir state // TODO look at making the instance static and moving most functionality into IrModule where it belongs IRState ir(new llvm::Module(mname, context)); gIR = &ir; ir.dmodule = this; // reset all IR data stored in Dsymbols IrDsymbol::resetAll(); // set target triple ir.module->setTargetTriple(global.params.targetTriple.str()); // set final data layout ir.module->setDataLayout(gDataLayout->getStringRepresentation()); IF_LOG Logger::cout() << "Final data layout: " << ir.module->getDataLayout() << '\n'; // allocate the target abi gABI = TargetABI::getTarget(); // handle invalid 'objectø module if (!ClassDeclaration::object) { error("is missing 'class Object'"); fatal(); } LLVM_D_InitRuntime(); codegenModule(this); gIR = NULL; if (llvmForceLogging && !logenabled) { Logger::disable(); } return ir.module; }
void StructDeclaration::toDebug() { unsigned leaf; unsigned property; unsigned nfields; unsigned fnamelen; const char *id; targ_size_t size; unsigned numidx; debtyp_t *d,*dt; unsigned len; int i; int count; // COUNT field in LF_CLASS unsigned char *p; idx_t typidx = 0; //printf("StructDeclaration::toDebug('%s')\n", toChars()); assert(config.fulltypes >= CV4); if (isAnonymous()) return /*0*/; if (typidx) // if reference already generated return /*typidx*/; // use already existing reference property = 0; if (!members) { size = 0; property |= 0x80; // forward reference } else size = structsize; if (parent->isAggregateDeclaration()) // if class is nested property |= 8; // if (st->Sctor || st->Sdtor) // property |= 2; // class has ctors and/or dtors // if (st->Sopoverload) // property |= 4; // class has overloaded operators // if (st->Scastoverload) // property |= 0x40; // class has casting methods // if (st->Sopeq && !(st->Sopeq->Sfunc->Fflags & Fnodebug)) // property |= 0x20; // class has overloaded assignment id = toPrettyChars(); numidx = isUnionDeclaration() ? 8 : 12; len = numidx + cv4_numericbytes(size); d = debtyp_alloc(len + cv_stringbytes(id)); cv4_storenumeric(d->data + numidx,size); len += cv_namestring(d->data + len,id); leaf = isUnionDeclaration() ? LF_UNION : LF_STRUCTURE; if (!isUnionDeclaration()) { TOWORD(d->data + 8,0); // dList TOWORD(d->data + 10,0); // vshape is 0 (no virtual functions) } TOWORD(d->data,leaf); // Assign a number to prevent infinite recursion if a struct member // references the same struct. d->length = 0; // so cv_debtyp() will allocate new typidx = cv_debtyp(d); d->length = len; // restore length if (!members) // if reference only { TOWORD(d->data + 2,0); // count: number of fields is 0 TOWORD(d->data + 4,0); // field list is 0 TOWORD(d->data + 6,property); return /*typidx*/; } // Compute the number of fields, and the length of the fieldlist record nfields = 0; fnamelen = 2; count = nfields; for (i = 0; i < members->dim; i++) { Dsymbol *s = (Dsymbol *)members->data[i]; int nwritten; nwritten = s->cvMember(NULL); if (nwritten) { fnamelen += nwritten; nfields++; count++; } } TOWORD(d->data + 2,count); TOWORD(d->data + 6,property); // Generate fieldlist type record dt = debtyp_alloc(fnamelen); p = dt->data; // And fill it in TOWORD(p,LF_FIELDLIST); p += 2; for (i = 0; i < members->dim; i++) { Dsymbol *s = (Dsymbol *)members->data[i]; p += s->cvMember(p); } //dbg_printf("fnamelen = %d, p-dt->data = %d\n",fnamelen,p-dt->data); assert(p - dt->data == fnamelen); TOWORD(d->data + 4,cv_debtyp(dt)); // cv4_outsym(s); unsigned char *debsym; unsigned length; len = strlen(id); debsym = (unsigned char *) alloca(39 + IDOHD + len); // Output a 'user-defined type' for the tag name TOWORD(debsym + 2,S_UDT); TOIDX(debsym + 4,typidx); length = 2 + 2 + cgcv.sz_idx; length += cv_namestring(debsym + length,id); TOWORD(debsym,length - 2); assert(length <= 40 + len); obj_write_bytes(SegData[DEBSYM],length,debsym); // return typidx; }
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(); }
// Put out instance of ModuleInfo for this Module void Module::genmoduleinfo() { // resolve ModuleInfo if (!moduleinfo) { error("object.d is missing the ModuleInfo struct"); fatal(); } // check for patch else { unsigned sizeof_ModuleInfo = 16 * Target::ptrsize; if (sizeof_ModuleInfo != moduleinfo->structsize) { error("object.d ModuleInfo class is incorrect"); fatal(); } } // use the RTTIBuilder RTTIBuilder b(moduleinfo); // some types LLType* moduleinfoTy = moduleinfo->type->irtype->getLLType(); LLType* classinfoTy = ClassDeclaration::classinfo->type->irtype->getLLType(); // importedModules[] std::vector<LLConstant*> importInits; LLConstant* importedModules = 0; llvm::ArrayType* importedModulesTy = 0; for (size_t i = 0; i < aimports.dim; i++) { Module *m = static_cast<Module *>(aimports.data[i]); if (!m->needModuleInfo() || m == this) continue; // declare the imported module info std::string m_name("_D"); m_name.append(m->mangle()); m_name.append("12__ModuleInfoZ"); llvm::GlobalVariable* m_gvar = gIR->module->getGlobalVariable(m_name); if (!m_gvar) m_gvar = new llvm::GlobalVariable(*gIR->module, moduleinfoTy, false, llvm::GlobalValue::ExternalLinkage, NULL, m_name); importInits.push_back(m_gvar); } // has import array? if (!importInits.empty()) { importedModulesTy = llvm::ArrayType::get(getPtrToType(moduleinfoTy), importInits.size()); importedModules = LLConstantArray::get(importedModulesTy, importInits); } // localClasses[] LLConstant* localClasses = 0; llvm::ArrayType* localClassesTy = 0; ClassDeclarations aclasses; //printf("members->dim = %d\n", members->dim); for (size_t i = 0; i < members->dim; i++) { Dsymbol *member; member = static_cast<Dsymbol *>(members->data[i]); //printf("\tmember '%s'\n", member->toChars()); member->addLocalClass(&aclasses); } // fill inits std::vector<LLConstant*> classInits; for (size_t i = 0; i < aclasses.dim; i++) { ClassDeclaration* cd = static_cast<ClassDeclaration*>(aclasses.data[i]); cd->codegen(Type::sir); if (cd->isInterfaceDeclaration()) { Logger::println("skipping interface '%s' in moduleinfo", cd->toPrettyChars()); continue; } else if (cd->sizeok != 1) { Logger::println("skipping opaque class declaration '%s' in moduleinfo", cd->toPrettyChars()); continue; } Logger::println("class: %s", cd->toPrettyChars()); LLConstant *c = DtoBitCast(cd->ir.irAggr->getClassInfoSymbol(), classinfoTy); classInits.push_back(c); } // has class array? if (!classInits.empty()) { localClassesTy = llvm::ArrayType::get(classinfoTy, classInits.size()); localClasses = LLConstantArray::get(localClassesTy, classInits); } // These must match the values in druntime/src/object_.d #define MIstandalone 4 #define MItlsctor 8 #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 MInew 0x80000000 // it's the "new" layout llvm::Function* fsharedctor = build_module_shared_ctor(); llvm::Function* fshareddtor = build_module_shared_dtor(); llvm::Function* funittest = build_module_unittest(); llvm::Function* fctor = build_module_ctor(); llvm::Function* fdtor = build_module_dtor(); unsigned flags = MInew; if (fctor) flags |= MItlsctor; if (fdtor) flags |= MItlsdtor; if (fsharedctor) flags |= MIctor; if (fshareddtor) flags |= MIdtor; #if 0 if (fgetmembers) flags |= MIxgetMembers; if (fictor) flags |= MIictor; #endif if (funittest) flags |= MIunitTest; if (importedModules) flags |= MIimportedModules; if (localClasses) flags |= MIlocalClasses; if (!needmoduleinfo) flags |= MIstandalone; b.push_uint(flags); // flags b.push_uint(0); // index if (fctor) b.push(fctor); if (fdtor) b.push(fdtor); if (fsharedctor) b.push(fsharedctor); if (fshareddtor) b.push(fshareddtor); #if 0 if (fgetmembers) b.push(fgetmembers); if (fictor) b.push(fictor); #endif if (funittest) b.push(funittest); if (importedModules) { b.push_size(importInits.size()); b.push(importedModules); } if (localClasses) { b.push_size(classInits.size()); b.push(localClasses); } // Put out module name as a 0-terminated string. const char *name = toPrettyChars(); const size_t len = strlen(name) + 1; llvm::IntegerType *it = llvm::IntegerType::getInt8Ty(gIR->context()); llvm::ArrayType *at = llvm::ArrayType::get(it, len); b.push(toConstantArray(it, at, name, len, false)); // create and set initializer b.finalize(moduleInfoType, moduleInfoSymbol()); // build the modulereference and ctor for registering it LLFunction* mictor = build_module_reference_and_ctor(moduleInfoSymbol()); AppendFunctionToLLVMGlobalCtorsDtors(mictor, 65535, true); }
llvm::Module* Module::genLLVMModule(llvm::LLVMContext& context, Ir* sir) { bool logenabled = Logger::enabled(); if (llvmForceLogging && !logenabled) { Logger::enable(); } Logger::println("Generating module: %s", (md ? md->toChars() : toChars())); LOG_SCOPE; if (global.params.verbose_cg) printf("codegen: %s (%s)\n", toPrettyChars(), srcfile->toChars()); assert(!global.errors); // name the module #if 1 // Temporary workaround for http://llvm.org/bugs/show_bug.cgi?id=11479 – // just use the source file name, as it is unlikely to collide with a // symbol name used somewhere in the module. llvm::StringRef mname(srcfile->toChars()); #else llvm::StringRef mname(toChars()); if (md != 0) mname = md->toChars(); #endif // create a new ir state // TODO look at making the instance static and moving most functionality into IrModule where it belongs IRState ir(new llvm::Module(mname, context)); gIR = &ir; ir.dmodule = this; // reset all IR data stored in Dsymbols IrDsymbol::resetAll(); sir->setState(&ir); // set target triple ir.module->setTargetTriple(global.params.targetTriple.str()); // set final data layout ir.module->setDataLayout(gDataLayout->getStringRepresentation()); if (Logger::enabled()) Logger::cout() << "Final data layout: " << ir.module->getDataLayout() << '\n'; // allocate the target abi gABI = TargetABI::getTarget(); // debug info DtoDwarfCompileUnit(this); // handle invalid 'objectø module if (!ClassDeclaration::object) { error("is missing 'class Object'"); fatal(); } if (!ClassDeclaration::classinfo) { error("is missing 'class ClassInfo'"); fatal(); } LLVM_D_InitRuntime(); // process module members for (unsigned k=0; k < members->dim; k++) { Dsymbol* dsym = static_cast<Dsymbol*>(members->data[k]); assert(dsym); dsym->codegen(sir); } // emit function bodies sir->emitFunctionBodies(); // for singleobj-compilation, fully emit all seen template instances if (global.params.singleObj) { while (!ir.seenTemplateInstances.empty()) { IRState::TemplateInstanceSet::iterator it, end = ir.seenTemplateInstances.end(); for (it = ir.seenTemplateInstances.begin(); it != end; ++it) (*it)->codegen(sir); ir.seenTemplateInstances.clear(); // emit any newly added function bodies sir->emitFunctionBodies(); } } // finilize debug info DtoDwarfModuleEnd(); // generate ModuleInfo genmoduleinfo(); // verify the llvm verifyModule(*ir.module); gIR = NULL; if (llvmForceLogging && !logenabled) { Logger::disable(); } sir->setState(NULL); return ir.module; }
void InterfaceDeclaration::toObjFile(int multiobj) { enum_SC scclass; //printf("InterfaceDeclaration::toObjFile('%s')\n", toChars()); if (type->ty == Terror) { error("had semantic errors when compiling"); return; } if (!members) return; if (global.params.symdebug) toDebug(this); scclass = SCglobal; if (isInstantiated()) scclass = SCcomdat; // Put out the members for (size_t i = 0; i < members->dim; i++) { Dsymbol *member = (*members)[i]; member->toObjFile(0); } // Generate C symbols toSymbol(this); ////////////////////////////////////////////// // Put out the TypeInfo type->genTypeInfo(NULL); type->vtinfo->toObjFile(multiobj); ////////////////////////////////////////////// // Put out the ClassInfo csym->Sclass = scclass; 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, Type::typeinfoclass->toVtblSymbol(), 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 = toPrettyChars(); size_t namelen = strlen(name); dtsize_t(&dt, namelen); dtabytes(&dt, TYnptr, 0, namelen + 1, name); // vtbl[] dtsize_t(&dt, 0); dtsize_t(&dt, 0); // (*vtblInterfaces)[] unsigned offset; dtsize_t(&dt, vtblInterfaces->dim); if (vtblInterfaces->dim) { offset = global.params.isLP64 ? CLASSINFO_SIZE_64 : CLASSINFO_SIZE; // must be ClassInfo.size if (Type::typeinfoclass) { if (Type::typeinfoclass->structsize != offset) { error("mismatch between dmd and object.d or object.di found. Check installation and import paths with -v compiler switch."); fatal(); } } dtxoff(&dt, csym, offset, TYnptr); // (*) } else { offset = 0; dtsize_t(&dt, 0); } // base assert(!baseClass); dtsize_t(&dt, 0); // dtor dtsize_t(&dt, 0); // invariant dtsize_t(&dt, 0); // flags ClassFlags::Type flags = ClassFlags::hasOffTi | ClassFlags::hasTypeInfo; if (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 (getRTInfo) getRTInfo->toDt(&dt); else dtsize_t(&dt, 0); // no pointers //dtxoff(&dt, toSymbol(type->vtinfo), 0, TYnptr); // typeinfo ////////////////////////////////////////////// // Put out (*vtblInterfaces)[]. Must immediately follow csym, because // of the fixup (*) offset += vtblInterfaces->dim * (4 * Target::ptrsize); for (size_t i = 0; i < vtblInterfaces->dim; i++) { BaseClass *b = (*vtblInterfaces)[i]; ClassDeclaration *id = b->base; // ClassInfo dtxoff(&dt, toSymbol(id), 0, TYnptr); // vtbl[] dtsize_t(&dt, 0); dtsize_t(&dt, 0); // this offset dtsize_t(&dt, b->offset); } csym->Sdt = dt; out_readonly(csym); outdata(csym); if (isExport()) objmod->export_symbol(csym,0); }
Symbol *FuncDeclaration::toSymbol() { if (!csym) { Symbol *s; TYPE *t; const char *id; #if 0 id = ident->toChars(); #else id = mangle(); #endif //printf("FuncDeclaration::toSymbol(%s %s)\n", kind(), toChars()); //printf("\tid = '%s'\n", id); //printf("\ttype = %s\n", type->toChars()); s = symbol_calloc(id); slist_add(s); { s->prettyIdent = toPrettyChars(); s->Sclass = SCglobal; symbol_func(s); func_t *f = s->Sfunc; if (isVirtual() && vtblIndex != -1) f->Fflags |= Fvirtual; else if (isMember2() && isStatic()) f->Fflags |= Fstatic; f->Fstartline.Slinnum = loc.linnum; f->Fstartline.Sfilename = (char *)loc.filename; if (endloc.linnum) { f->Fendline.Slinnum = endloc.linnum; f->Fendline.Sfilename = (char *)endloc.filename; } else { f->Fendline.Slinnum = loc.linnum; f->Fendline.Sfilename = (char *)loc.filename; } t = type->toCtype(); } mangle_t msave = t->Tmangle; if (isMain()) { t->Tty = TYnfunc; t->Tmangle = mTYman_c; } else { switch (linkage) { case LINKwindows: t->Tmangle = mTYman_std; break; case LINKpascal: t->Tty = TYnpfunc; t->Tmangle = mTYman_pas; break; case LINKc: t->Tmangle = mTYman_c; break; case LINKd: t->Tmangle = mTYman_d; break; case LINKcpp: { t->Tmangle = mTYman_cpp; if (isThis() && !global.params.is64bit && global.params.isWindows) t->Tty = TYmfunc; s->Sflags |= SFLpublic; Dsymbol *parent = toParent(); ClassDeclaration *cd = parent->isClassDeclaration(); if (cd) { ::type *tc = cd->type->toCtype(); s->Sscope = tc->Tnext->Ttag; } StructDeclaration *sd = parent->isStructDeclaration(); if (sd) { ::type *ts = sd->type->toCtype(); s->Sscope = ts->Ttag; } break; } default: printf("linkage = %d\n", linkage); assert(0); } } if (msave) assert(msave == t->Tmangle); //printf("Tty = %x, mangle = x%x\n", t->Tty, t->Tmangle); t->Tcount++; s->Stype = t; //s->Sfielddef = this; csym = s; } return csym; }
int FuncDeclaration::canInline(int hasthis, int hdrscan, int statementsToo) { InlineCostState ics; int cost; #define CANINLINE_LOG 0 #if CANINLINE_LOG printf("FuncDeclaration::canInline(hasthis = %d, statementsToo = %d, '%s')\n", hasthis, statementsToo, toPrettyChars()); #endif if (needThis() && !hasthis) return 0; if (inlineNest || (semanticRun < PASSsemantic3 && !hdrscan)) { #if CANINLINE_LOG printf("\t1: no, inlineNest = %d, semanticRun = %d\n", inlineNest, semanticRun); #endif return 0; } #if 1 switch (statementsToo ? inlineStatusStmt : inlineStatusExp) { case ILSyes: #if CANINLINE_LOG printf("\t1: yes %s\n", toChars()); #endif return 1; case ILSno: #if CANINLINE_LOG printf("\t1: no %s\n", toChars()); #endif return 0; case ILSuninitialized: break; default: assert(0); } #endif if (type) { assert(type->ty == Tfunction); TypeFunction *tf = (TypeFunction *)type; if (tf->varargs == 1) // no variadic parameter lists goto Lno; /* Don't inline a function that returns non-void, but has * no return expression. * No statement inlining for non-voids. */ if (tf->next && tf->next->ty != Tvoid && (!(hasReturnExp & 1) || statementsToo) && !hdrscan) goto Lno; } // cannot inline constructor calls because we need to convert: // return; // to: // return this; if ( !fbody || ident == Id::ensure || // ensure() has magic properties the inliner loses (ident == Id::require && // require() has magic properties too toParent()->isFuncDeclaration() && // see bug 7699 toParent()->isFuncDeclaration()->needThis()) || !hdrscan && ( isSynchronized() || isImportedSymbol() || hasNestedFrameRefs() || // no nested references to this frame (isVirtual() && !isFinalFunc()) )) { goto Lno; } #if 0 /* If any parameters are Tsarray's (which are passed by reference) * or out parameters (also passed by reference), don't do inlining. */ if (parameters) { for (size_t i = 0; i < parameters->dim; i++) { VarDeclaration *v = (*parameters)[i]; if (v->type->toBasetype()->ty == Tsarray) goto Lno; } } #endif memset(&ics, 0, sizeof(ics)); ics.hasthis = hasthis; ics.fd = this; ics.hdrscan = hdrscan; cost = fbody->inlineCost(&ics); #if CANINLINE_LOG printf("cost = %d for %s\n", cost, toChars()); #endif if (tooCostly(cost)) goto Lno; if (!statementsToo && cost > COST_MAX) goto Lno; if (!hdrscan) { // Don't modify inlineStatus for header content scan if (statementsToo) inlineStatusStmt = ILSyes; else inlineStatusExp = ILSyes; inlineScan(); // Don't scan recursively for header content scan if (inlineStatusExp == ILSuninitialized) { // Need to redo cost computation, as some statements or expressions have been inlined memset(&ics, 0, sizeof(ics)); ics.hasthis = hasthis; ics.fd = this; ics.hdrscan = hdrscan; cost = fbody->inlineCost(&ics); #if CANINLINE_LOG printf("recomputed cost = %d for %s\n", cost, toChars()); #endif if (tooCostly(cost)) goto Lno; if (!statementsToo && cost > COST_MAX) goto Lno; if (statementsToo) inlineStatusStmt = ILSyes; else inlineStatusExp = ILSyes; } } #if CANINLINE_LOG printf("\t2: yes %s\n", toChars()); #endif return 1; Lno: if (!hdrscan) // Don't modify inlineStatus for header content scan { if (statementsToo) inlineStatusStmt = ILSno; else inlineStatusExp = ILSno; } #if CANINLINE_LOG printf("\t2: no %s\n", toChars()); #endif return 0; }
void Module::parse() { //printf("Module::parse()\n"); char *srcname = srcfile->name->toChars(); //printf("Module::parse(srcname = '%s')\n", srcname); utf8_t *buf = (utf8_t *)srcfile->buffer; size_t buflen = srcfile->len; if (buflen >= 2) { /* Convert all non-UTF-8 formats to UTF-8. * BOM : http://www.unicode.org/faq/utf_bom.html * 00 00 FE FF UTF-32BE, big-endian * FF FE 00 00 UTF-32LE, little-endian * FE FF UTF-16BE, big-endian * FF FE UTF-16LE, little-endian * EF BB BF UTF-8 */ unsigned le; unsigned bom = 1; // assume there's a BOM if (buf[0] == 0xFF && buf[1] == 0xFE) { if (buflen >= 4 && buf[2] == 0 && buf[3] == 0) { // UTF-32LE le = 1; Lutf32: OutBuffer dbuf; unsigned *pu = (unsigned *)(buf); unsigned *pumax = &pu[buflen / 4]; if (buflen & 3) { error("odd length of UTF-32 char source %u", buflen); fatal(); } dbuf.reserve(buflen / 4); for (pu += bom; pu < pumax; pu++) { unsigned u; u = le ? readlongLE(pu) : readlongBE(pu); if (u & ~0x7F) { if (u > 0x10FFFF) { error("UTF-32 value %08x greater than 0x10FFFF", u); fatal(); } dbuf.writeUTF8(u); } else dbuf.writeByte(u); } dbuf.writeByte(0); // add 0 as sentinel for scanner buflen = dbuf.offset - 1; // don't include sentinel in count buf = (utf8_t *) dbuf.extractData(); } else { // UTF-16LE (X86) // Convert it to UTF-8 le = 1; Lutf16: OutBuffer dbuf; unsigned short *pu = (unsigned short *)(buf); unsigned short *pumax = &pu[buflen / 2]; if (buflen & 1) { error("odd length of UTF-16 char source %u", buflen); fatal(); } dbuf.reserve(buflen / 2); for (pu += bom; pu < pumax; pu++) { unsigned u; u = le ? readwordLE(pu) : readwordBE(pu); if (u & ~0x7F) { if (u >= 0xD800 && u <= 0xDBFF) { unsigned u2; if (++pu > pumax) { error("surrogate UTF-16 high value %04x at EOF", u); fatal(); } u2 = le ? readwordLE(pu) : readwordBE(pu); if (u2 < 0xDC00 || u2 > 0xDFFF) { error("surrogate UTF-16 low value %04x out of range", u2); fatal(); } u = (u - 0xD7C0) << 10; u |= (u2 - 0xDC00); } else if (u >= 0xDC00 && u <= 0xDFFF) { error("unpaired surrogate UTF-16 value %04x", u); fatal(); } else if (u == 0xFFFE || u == 0xFFFF) { error("illegal UTF-16 value %04x", u); fatal(); } dbuf.writeUTF8(u); } else dbuf.writeByte(u); } dbuf.writeByte(0); // add 0 as sentinel for scanner buflen = dbuf.offset - 1; // don't include sentinel in count buf = (utf8_t *) dbuf.extractData(); } } else if (buf[0] == 0xFE && buf[1] == 0xFF) { // UTF-16BE le = 0; goto Lutf16; } else if (buflen >= 4 && buf[0] == 0 && buf[1] == 0 && buf[2] == 0xFE && buf[3] == 0xFF) { // UTF-32BE le = 0; goto Lutf32; } else if (buflen >= 3 && buf[0] == 0xEF && buf[1] == 0xBB && buf[2] == 0xBF) { // UTF-8 buf += 3; buflen -= 3; } else { /* There is no BOM. Make use of Arcane Jill's insight that * the first char of D source must be ASCII to * figure out the encoding. */ bom = 0; if (buflen >= 4) { if (buf[1] == 0 && buf[2] == 0 && buf[3] == 0) { // UTF-32LE le = 1; goto Lutf32; } else if (buf[0] == 0 && buf[1] == 0 && buf[2] == 0) { // UTF-32BE le = 0; goto Lutf32; } } if (buflen >= 2) { if (buf[1] == 0) { // UTF-16LE le = 1; goto Lutf16; } else if (buf[0] == 0) { // UTF-16BE le = 0; goto Lutf16; } } // It's UTF-8 if (buf[0] >= 0x80) { error("source file must start with BOM or ASCII character, not \\x%02X", buf[0]); fatal(); } } } /* If it starts with the string "Ddoc", then it's a documentation * source file. */ if (buflen >= 4 && memcmp(buf, "Ddoc", 4) == 0) { comment = buf + 4; isDocFile = 1; if (!docfile) setDocfile(); return; } { Parser p(this, buf, buflen, docfile != NULL); p.nextToken(); members = p.parseModule(); md = p.md; numlines = p.scanloc.linnum; } if (srcfile->ref == 0) ::free(srcfile->buffer); srcfile->buffer = NULL; srcfile->len = 0; /* The symbol table into which the module is to be inserted. */ DsymbolTable *dst; if (md) { /* A ModuleDeclaration, md, was provided. * The ModuleDeclaration sets the packages this module appears in, and * the name of this module. */ this->ident = md->id; this->safe = md->safe; Package *ppack = NULL; dst = Package::resolve(md->packages, &this->parent, &ppack); assert(dst); Module *m = ppack ? ppack->isModule() : NULL; if (m && strcmp(m->srcfile->name->name(), "package.d") != 0) { ::error(md->loc, "package name '%s' conflicts with usage as a module name in file %s", ppack->toPrettyChars(), m->srcfile->toChars()); } } else { /* The name of the module is set to the source file name. * There are no packages. */ dst = modules; // and so this module goes into global module symbol table /* Check to see if module name is a valid identifier */ if (!Lexer::isValidIdentifier(this->ident->toChars())) error("has non-identifier characters in filename, use module declaration instead"); } // Insert module into the symbol table Dsymbol *s = this; bool isPackageMod = strcmp(srcfile->name->name(), "package.d") == 0; if (isPackageMod) { /* If the source tree is as follows: * pkg/ * +- package.d * +- common.d * the 'pkg' will be incorporated to the internal package tree in two ways: * import pkg; * and: * import pkg.common; * * If both are used in one compilation, 'pkg' as a module (== pkg/package.d) * and a package name 'pkg' will conflict each other. * * To avoid the conflict: * 1. If preceding package name insertion had occurred by Package::resolve, * later package.d loading will change Package::isPkgMod to PKGmodule and set Package::mod. * 2. Otherwise, 'package.d' wrapped by 'Package' is inserted to the internal tree in here. */ Package *p = new Package(ident); p->parent = this->parent; p->isPkgMod = PKGmodule; p->mod = this; p->symtab = new DsymbolTable(); s = p; } if (!dst->insert(s)) { /* It conflicts with a name that is already in the symbol table. * Figure out what went wrong, and issue error message. */ Dsymbol *prev = dst->lookup(ident); assert(prev); if (Module *mprev = prev->isModule()) { if (strcmp(srcname, mprev->srcfile->toChars()) == 0) error(loc, "from file %s must be imported as module '%s'", srcname, toPrettyChars()); else error(loc, "from file %s conflicts with another module %s from file %s", srcname, mprev->toChars(), mprev->srcfile->toChars()); } else if (Package *pkg = prev->isPackage()) { if (pkg->isPkgMod == PKGunknown && isPackageMod) { /* If the previous inserted Package is not yet determined as package.d, * link it to the actual module. */ pkg->isPkgMod = PKGmodule; pkg->mod = this; } else error(pkg->loc, "from file %s conflicts with package name %s", srcname, pkg->toChars()); } else assert(global.errors); } else { // Add to global array of all modules amodules.push(this); } }
void ClassDeclaration::toObjFile(int multiobj) { unsigned offset; Symbol *sinit; enum_SC scclass; //printf("ClassDeclaration::toObjFile('%s')\n", toChars()); if (type->ty == Terror) { error("had semantic errors when compiling"); return; } if (!members) return; if (multiobj && !hasStaticCtorOrDtor()) { obj_append(this); return; } if (global.params.symdebug) toDebug(this); assert(!scope); // semantic() should have been run to completion scclass = SCglobal; if (isInstantiated()) scclass = SCcomdat; // Put out the members for (size_t i = 0; i < members->dim; i++) { Dsymbol *member = (*members)[i]; /* There might be static ctors in the members, and they cannot * be put in separate obj files. */ member->toObjFile(multiobj); } // Generate C symbols toSymbol(this); toVtblSymbol(); sinit = toInitializer(); ////////////////////////////////////////////// // Generate static initializer sinit->Sclass = scclass; sinit->Sfl = FLdata; ClassDeclaration_toDt(this, &sinit->Sdt); out_readonly(sinit); outdata(sinit); ////////////////////////////////////////////// // Put out the TypeInfo type->genTypeInfo(NULL); //type->vtinfo->toObjFile(multiobj); ////////////////////////////////////////////// // Put out the ClassInfo csym->Sclass = scclass; 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 classinfo_size = global.params.isLP64 ? CLASSINFO_SIZE_64 : CLASSINFO_SIZE; // must be ClassInfo.size offset = classinfo_size; if (Type::typeinfoclass) { if (Type::typeinfoclass->structsize != classinfo_size) { #ifdef DEBUG printf("CLASSINFO_SIZE = x%x, Type::typeinfoclass->structsize = x%x\n", offset, Type::typeinfoclass->structsize); #endif 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, Type::typeinfoclass->toVtblSymbol(), 0, TYnptr); // vtbl for ClassInfo else dtsize_t(&dt, 0); // BUG: should be an assert() dtsize_t(&dt, 0); // monitor // initializer[] assert(structsize >= 8 || (cpp && structsize >= 4)); dtsize_t(&dt, structsize); // size dtxoff(&dt, sinit, 0, TYnptr); // initializer // name[] const char *name = ident->toChars(); size_t namelen = strlen(name); if (!(namelen > 9 && memcmp(name, "TypeInfo_", 9) == 0)) { name = toPrettyChars(); namelen = strlen(name); } dtsize_t(&dt, namelen); dtabytes(&dt, TYnptr, 0, namelen + 1, name); // vtbl[] dtsize_t(&dt, vtbl.dim); dtxoff(&dt, vtblsym, 0, TYnptr); // interfaces[] dtsize_t(&dt, vtblInterfaces->dim); if (vtblInterfaces->dim) dtxoff(&dt, csym, offset, TYnptr); // (*) else dtsize_t(&dt, 0); // base if (baseClass) dtxoff(&dt, toSymbol(baseClass), 0, TYnptr); else dtsize_t(&dt, 0); // destructor if (dtor) dtxoff(&dt, toSymbol(dtor), 0, TYnptr); else dtsize_t(&dt, 0); // invariant if (inv) dtxoff(&dt, toSymbol(inv), 0, TYnptr); else dtsize_t(&dt, 0); // flags ClassFlags::Type flags = ClassFlags::hasOffTi; if (isCOMclass()) flags |= ClassFlags::isCOMclass; if (isCPPclass()) flags |= ClassFlags::isCPPclass; flags |= ClassFlags::hasGetMembers; flags |= ClassFlags::hasTypeInfo; if (ctor) flags |= ClassFlags::hasCtor; if (isabstract) flags |= ClassFlags::isAbstract; for (ClassDeclaration *cd = this; cd; cd = cd->baseClass) { if (cd->members) { for (size_t i = 0; i < cd->members->dim; i++) { Dsymbol *sm = (*cd->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 (aggDelete) dtxoff(&dt, toSymbol(aggDelete), 0, TYnptr); else dtsize_t(&dt, 0); // offTi[] dtsize_t(&dt, 0); dtsize_t(&dt, 0); // null for now, fix later // defaultConstructor if (defaultCtor) dtxoff(&dt, toSymbol(defaultCtor), 0, TYnptr); else dtsize_t(&dt, 0); // xgetRTInfo if (getRTInfo) getRTInfo->toDt(&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 += vtblInterfaces->dim * (4 * Target::ptrsize); for (size_t i = 0; i < vtblInterfaces->dim; i++) { BaseClass *b = (*vtblInterfaces)[i]; ClassDeclaration *id = b->base; /* The layout is: * struct Interface * { * ClassInfo *interface; * void *[] vtbl; * size_t offset; * } */ // Fill in vtbl[] b->fillVtbl(this, &b->vtbl, 1); dtxoff(&dt, toSymbol(id), 0, TYnptr); // ClassInfo // vtbl[] dtsize_t(&dt, id->vtbl.dim); dtxoff(&dt, 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 < vtblInterfaces->dim; i++) { BaseClass *b = (*vtblInterfaces)[i]; ClassDeclaration *id = b->base; //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, csym, classinfo_size + 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, fd->toThunkSymbol(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 *cd; FuncDeclarations bvtbl; for (cd = this->baseClass; cd; cd = cd->baseClass) { for (size_t k = 0; k < cd->vtblInterfaces->dim; k++) { BaseClass *bs = (*cd->vtblInterfaces)[k]; if (bs->fillVtbl(this, &bvtbl, 0)) { //printf("\toverriding vtbl[] for %s\n", bs->base->toChars()); ClassDeclaration *id = bs->base; 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(cd), classinfo_size + k * (4 * Target::ptrsize), TYnptr); j = 1; } for (; j < id->vtbl.dim; j++) { FuncDeclaration *fd; assert(j < bvtbl.dim); fd = bvtbl[j]; if (fd) dtxoff(&dt, fd->toThunkSymbol(bs->offset), 0, TYnptr); else dtsize_t(&dt, 0); } } } } csym->Sdt = dt; // ClassInfo cannot be const data, because we use the monitor on it outdata(csym); if (isExport()) objmod->export_symbol(csym,0); ////////////////////////////////////////////// // Put out the vtbl[] //printf("putting out %s.vtbl[]\n", toChars()); dt = NULL; if (vtblOffset()) dtxoff(&dt, csym, 0, TYnptr); // first entry is ClassInfo reference for (size_t i = vtblOffset(); i < vtbl.dim; i++) { FuncDeclaration *fd = vtbl[i]->isFuncDeclaration(); //printf("\tvtbl[%d] = %p\n", i, fd); if (fd && (fd->fbody || !isAbstract())) { // Ensure function has a return value (Bugzilla 4869) fd->functionSemantic(); Symbol *s = toSymbol(fd); if (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 < vtbl.dim; j++) { if (j == i) continue; FuncDeclaration *fd2 = 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) deprecation("use of %s%s hidden by %s is deprecated. Use 'alias %s.%s %s;' to introduce base class overload set.", fd->toPrettyChars(), Parameter::argsTypesToChars(tf->parameters, tf->varargs), toChars(), fd->parent->toChars(), fd->toChars(), fd->toChars()); else deprecation("use of %s hidden by %s is deprecated", fd->toPrettyChars(), toChars()); s = rtlsym[RTLSYM_DHIDDENFUNC]; break; } } } dtxoff(&dt, s, 0, TYnptr); } else dtsize_t(&dt, 0); } vtblsym->Sdt = dt; vtblsym->Sclass = scclass; vtblsym->Sfl = FLdata; out_readonly(vtblsym); outdata(vtblsym); if (isExport()) objmod->export_symbol(vtblsym,0); }
void ClassDeclaration::toDebug() { unsigned leaf; unsigned property; unsigned nfields; unsigned fnamelen; const char *id; targ_size_t size; unsigned numidx; debtyp_t *d,*dt; unsigned len; int i; int count; // COUNT field in LF_CLASS unsigned char *p; idx_t typidx = 0; //printf("ClassDeclaration::toDebug('%s')\n", toChars()); assert(config.fulltypes >= CV4); if (isAnonymous()) return /*0*/; if (typidx) // if reference already generated return /*typidx*/; // use already existing reference property = 0; if (!members) { size = 0; property |= 0x80; // forward reference } else size = structsize; if (parent->isAggregateDeclaration()) // if class is nested property |= 8; if (ctor || dtors.dim) property |= 2; // class has ctors and/or dtors // if (st->Sopoverload) // property |= 4; // class has overloaded operators // if (st->Scastoverload) // property |= 0x40; // class has casting methods // if (st->Sopeq && !(st->Sopeq->Sfunc->Fflags & Fnodebug)) // property |= 0x20; // class has overloaded assignment id = toPrettyChars(); numidx = isUnionDeclaration() ? 8 : 12; len = numidx + cv4_numericbytes(size); d = debtyp_alloc(len + cv_stringbytes(id)); cv4_storenumeric(d->data + numidx,size); len += cv_namestring(d->data + len,id); leaf = LF_CLASS; TOWORD(d->data + 8,0); // dList if (1) { debtyp_t *vshape; unsigned n; unsigned char descriptor; n = vtbl.dim; // number of virtual functions if (n == 0) { TOWORD(d->data + 10,0); // vshape is 0 } else { int i; vshape = debtyp_alloc(4 + (n + 1) / 2); TOWORD(vshape->data,LF_VTSHAPE); TOWORD(vshape->data + 2,1); n = 0; descriptor = 0; for (i = 0; i < vtbl.dim; i++) { FuncDeclaration *fd = (FuncDeclaration *)vtbl.data[i]; tym_t ty; //if (intsize == 4) descriptor |= 5; vshape->data[4 + n / 2] = descriptor; descriptor <<= 4; n++; } TOWORD(d->data + 10,cv_debtyp(vshape)); // vshape } } else TOWORD(d->data + 10,0); // vshape is 0 (no virtual functions) TOWORD(d->data,leaf); // Assign a number to prevent infinite recursion if a struct member // references the same struct. d->length = 0; // so cv_debtyp() will allocate new typidx = cv_debtyp(d); d->length = len; // restore length if (!members) // if reference only { TOWORD(d->data + 2,0); // count: number of fields is 0 TOWORD(d->data + 4,0); // field list is 0 TOWORD(d->data + 6,property); return /*typidx*/; } // Compute the number of fields, and the length of the fieldlist record nfields = 0; fnamelen = 2; // Add in base classes for (i = 0; i < baseclasses.dim; i++) { BaseClass *bc = (BaseClass *)baseclasses.data[i]; nfields++; fnamelen += 6 + cv4_numericbytes(bc->offset); } count = nfields; for (i = 0; i < members->dim; i++) { Dsymbol *s = (Dsymbol *)members->data[i]; int nwritten; nwritten = s->cvMember(NULL); if (nwritten) { fnamelen += nwritten; nfields++; count++; } } TOWORD(d->data + 2,count); TOWORD(d->data + 6,property); // Generate fieldlist type record dt = debtyp_alloc(fnamelen); p = dt->data; // And fill it in TOWORD(p,LF_FIELDLIST); p += 2; // Add in base classes for (i = 0; i < baseclasses.dim; i++) { BaseClass *bc = (BaseClass *)baseclasses.data[i]; idx_t typidx; unsigned attribute; typidx = cv4_typidx(bc->base->type->toCtype()->Tnext); attribute = PROTtoATTR(bc->protection); TOWORD(p,LF_BCLASS); TOWORD(p + 2,typidx); TOWORD(p + 4,attribute); p += 6; cv4_storenumeric(p, bc->offset); p += cv4_numericbytes(bc->offset); } for (i = 0; i < members->dim; i++) { Dsymbol *s = (Dsymbol *)members->data[i]; p += s->cvMember(p); } //dbg_printf("fnamelen = %d, p-dt->data = %d\n",fnamelen,p-dt->data); assert(p - dt->data == fnamelen); TOWORD(d->data + 4,cv_debtyp(dt)); // cv4_outsym(s); unsigned char *debsym; unsigned length; len = strlen(id); debsym = (unsigned char *) alloca(39 + IDOHD + len); // Output a 'user-defined type' for the tag name TOWORD(debsym + 2,S_UDT); TOIDX(debsym + 4,typidx); length = 2 + 2 + cgcv.sz_idx; length += cv_namestring(debsym + length,id); TOWORD(debsym,length - 2); assert(length <= 40 + len); obj_write_bytes(SegData[DEBSYM],length,debsym); // return typidx; }
Symbol *FuncDeclaration::toSymbol() { if (!csym) { Symbol *s; TYPE *t; const char *id; #if 0 id = ident->toChars(); #else id = mangle(); #endif //printf("FuncDeclaration::toSymbol(%s %s)\n", kind(), toChars()); //printf("\tid = '%s'\n", id); //printf("\ttype = %s\n", type->toChars()); s = symbol_calloc(id); slist_add(s); { s->prettyIdent = toPrettyChars(); s->Sclass = SCglobal; symbol_func(s); func_t *f = s->Sfunc; if (isVirtual()) f->Fflags |= Fvirtual; else if (isMember2()) f->Fflags |= Fstatic; f->Fstartline.Slinnum = loc.linnum; f->Fstartline.Sfilename = (char *)loc.filename; if (endloc.linnum) { f->Fendline.Slinnum = endloc.linnum; f->Fendline.Sfilename = (char *)endloc.filename; } else { f->Fendline.Slinnum = loc.linnum; f->Fendline.Sfilename = (char *)loc.filename; } t = type->toCtype(); } mangle_t msave = t->Tmangle; if (isMain()) { t->Tty = TYnfunc; t->Tmangle = mTYman_c; } else { switch (linkage) { case LINKwindows: t->Tmangle = mTYman_std; break; case LINKpascal: t->Tty = TYnpfunc; t->Tmangle = mTYman_pas; break; case LINKc: t->Tmangle = mTYman_c; break; case LINKd: t->Tmangle = mTYman_d; break; case LINKcpp: t->Tmangle = mTYman_cpp; break; default: printf("linkage = %d\n", linkage); assert(0); } } if (msave) assert(msave == t->Tmangle); //printf("Tty = %x, mangle = x%x\n", t->Tty, t->Tmangle); t->Tcount++; s->Stype = t; //s->Sfielddef = this; csym = s; } return csym; }
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(); }
llvm::Module* Module::genLLVMModule(llvm::LLVMContext& context) { bool logenabled = Logger::enabled(); if (llvmForceLogging && !logenabled) { Logger::enable(); } IF_LOG Logger::println("Generating module: %s", (md ? md->toChars() : toChars())); LOG_SCOPE; if (global.params.verbose_cg) printf("codegen: %s (%s)\n", toPrettyChars(), srcfile->toChars()); if (global.errors) { Logger::println("Aborting because of errors"); fatal(); } // name the module #if 1 // Temporary workaround for http://llvm.org/bugs/show_bug.cgi?id=11479 – // just use the source file name, as it is unlikely to collide with a // symbol name used somewhere in the module. llvm::StringRef mname(srcfile->toChars()); #else llvm::StringRef mname(toChars()); if (md != 0) mname = md->toChars(); #endif // create a new ir state // TODO look at making the instance static and moving most functionality into IrModule where it belongs IRState ir(new llvm::Module(mname, context)); gIR = &ir; ir.dmodule = this; // reset all IR data stored in Dsymbols IrDsymbol::resetAll(); // set target triple ir.module->setTargetTriple(global.params.targetTriple.str()); // set final data layout ir.module->setDataLayout(gDataLayout->getStringRepresentation()); IF_LOG Logger::cout() << "Final data layout: " << ir.module->getDataLayout() << '\n'; // allocate the target abi gABI = TargetABI::getTarget(); // debug info gIR->DBuilder.EmitCompileUnit(this); // handle invalid 'objectø module if (!ClassDeclaration::object) { error("is missing 'class Object'"); fatal(); } LLVM_D_InitRuntime(); // process module members for (unsigned k=0; k < members->dim; k++) { Dsymbol* dsym = static_cast<Dsymbol*>(members->data[k]); assert(dsym); Declaration_codegen(dsym); } // finalize debug info gIR->DBuilder.EmitModuleEnd(); // generate ModuleInfo genmoduleinfo(); build_llvm_used_array(&ir); #if LDC_LLVM_VER >= 303 // Add the linker options metadata flag. ir.module->addModuleFlag(llvm::Module::AppendUnique, "Linker Options", llvm::MDNode::get(ir.context(), ir.LinkerMetadataArgs)); #endif #if LDC_LLVM_VER >= 304 // Emit ldc version as llvm.ident metadata. llvm::NamedMDNode *IdentMetadata = ir.module->getOrInsertNamedMetadata("llvm.ident"); std::string Version("ldc version "); Version.append(global.ldc_version); llvm::Value *IdentNode[] = { llvm::MDString::get(ir.context(), Version) }; IdentMetadata->addOperand(llvm::MDNode::get(ir.context(), IdentNode)); #endif // verify the llvm verifyModule(*ir.module); gIR = NULL; if (llvmForceLogging && !logenabled) { Logger::disable(); } return ir.module; }