Mercurial > projects > ddmd
view dmd/Module.d @ 99:903b95002d4e
Id and Macro are quite experimental currently
author | Trass3r |
---|---|
date | Tue, 31 Aug 2010 04:04:33 +0200 |
parents | acd69f84627e |
children | e28b18c23469 |
line wrap: on
line source
module dmd.Module; import dmd.Package; import dmd.DsymbolTable; import dmd.backend.TYM; import dmd.Array; import dmd.StaticDtorDeclaration; import dmd.Scope; import dmd.Id; import dmd.Import; import dmd.ClassDeclaration; import dmd.ModuleDeclaration; import dmd.File; import dmd.Identifier; import dmd.Json; import dmd.Dsymbol; import dmd.ModuleInfoDeclaration; import dmd.FuncDeclaration; import dmd.Loc; import dmd.Macro; import dmd.Escape; import dmd.OutBuffer; import dmd.HdrGenState; import dmd.ArrayTypes; import dmd.FileName; import dmd.Global; import dmd.Parser; import dmd.Lexer; import dmd.Util; import dmd.String; import dmd.ScopeDsymbol; import dmd.Type; import dmd.backend.TYPE; import dmd.backend.Cstate; import dmd.backend.OPER; import dmd.backend.REG; import dmd.backend.Symbol; import dmd.backend.elem; import dmd.backend.mTYman; import dmd.backend.Util; import dmd.backend.SC; import dmd.backend.FL; import dmd.backend.SFL; import dmd.backend.TF; import dmd.backend.RTLSYM; import dmd.backend.BC; import dmd.backend.block; import dmd.backend.targ_types; import dmd.backend.dt_t; import dmd.backend.TYM; import dmd.backend.Util; import dmd.backend.Classsym; import dmd.backend.glue; import dmd.backend.LIST; import dmd.codegen.Util; import core.stdc.string; import core.stdc.stdlib; import core.memory; uint readwordLE(ushort* p) { version (__I86__) { return *p; } else { return ((cast(ubyte*)p)[1] << 8) | (cast(ubyte*)p)[0]; } } uint readwordBE(ushort* p) { return ((cast(ubyte*)p)[0] << 8) | (cast(ubyte*)p)[1]; } uint readlongLE(uint* p) { version (__I86__) { return *p; } else { return (cast(ubyte*)p)[0] | ((cast(ubyte*)p)[1] << 8) | ((cast(ubyte*)p)[2] << 16) | ((cast(ubyte*)p)[3] << 24); } } uint readlongBE(uint* p) { return (cast(ubyte*)p)[3] | ((cast(ubyte*)p)[2] << 8) | ((cast(ubyte*)p)[1] << 16) | ((cast(ubyte*)p)[0] << 24); } /* Segments */ enum Segment { CODE = 1, /* code segment */ DATA = 2, /* initialized data */ CDATA = 3, /* constant data */ UDATA = 4, /* uninitialized data */ UNKNOWN = -1, /* unknown segment */ } struct seg_data { int SDseg; // omf file segment index targ_size_t SDoffset; // starting offset for data bool isfarseg; int seg; // segment number int lnameidx; // lname idx of segment name int classidx; // lname idx of class name uint attr; // segment attribute targ_size_t origsize; // original size int seek; // seek position in output file } extern (C) extern __gshared seg_data** SegData; ref targ_size_t Offset(Segment seg) { return SegData[seg].SDoffset; } ref targ_size_t Doffset() { return SegData[Segment.DATA].SDoffset; } ref targ_size_t CDoffset() { return SegData[Segment.CDATA].SDoffset; } ref targ_size_t UDoffset() { return SegData[Segment.UDATA].SDoffset; } enum CF { CFes = 1, // generate an ES: segment override for this instr CFjmp16 = 2, // need 16 bit jump offset (long branch) CFtarg = 4, // this code is the target of a jump CFseg = 8, // get segment of immediate value CFoff = 0x10, // get offset of immediate value CFss = 0x20, // generate an SS: segment override (not with // CFes at the same time, though!) CFpsw = 0x40, // we need the flags result after this instruction CFopsize = 0x80, // prefix with operand size CFaddrsize = 0x100, // prefix with address size CFds = 0x200, // need DS override (not with es, ss, or cs ) CFcs = 0x400, // need CS override CFfs = 0x800, // need FS override CFgs = (CFcs | CFfs), // need GS override CFwait = 0x1000, // If I32 it indicates when to output a WAIT CFselfrel = 0x2000, // if self-relative CFunambig = 0x4000, // indicates cannot be accessed by other addressing // modes CFtarg2 = 0x8000, // like CFtarg, but we can't optimize this away CFvolatile = 0x10000, // volatile reference, do not schedule CFclassinit = 0x20000, // class init code CFSEG = (CFes | CFss | CFds | CFcs | CFfs | CFgs), CFPREFIX = (CFSEG | CFopsize | CFaddrsize), } class Module : Package { static Module rootModule; static DsymbolTable modules; // symbol table of all modules static Array amodules; // array of all modules static Array deferred; // deferred Dsymbol's needing semantic() run on them static uint dprogress; // progress resolving the deferred list static void init() { modules = new DsymbolTable(); amodules = new Array(); deferred = new Array(); } static ClassDeclaration moduleinfo; string arg; // original argument name ModuleDeclaration md; // if !null, the contents of the ModuleDeclaration declaration File srcfile; // input source file File objfile; // output .obj file File hdrfile; // 'header' file File symfile; // output symbol file File docfile; // output documentation file uint errors; // if any errors in file uint numlines; // number of lines in source file int isHtml; // if it is an HTML file int isDocFile; // if it is a documentation input file, not D source int needmoduleinfo; /// TODO: change to bool version (IN_GCC) { int strictlyneedmoduleinfo; } int selfimports; // 0: don't know, 1: does not, 2: does int selfImports() // returns !=0 if module imports itself { assert(false); } int insearch; Identifier searchCacheIdent; Dsymbol searchCacheSymbol; // cached value of search int searchCacheFlags; // cached flags int semanticstarted; // has semantic() been started? int semanticRun; // has semantic() been done? int root; // != 0 if this is a 'root' module, // i.e. a module that will be taken all the // way to an object file Module importedFrom; // module from command line we're imported from, // i.e. a module that will be taken all the // way to an object file Array decldefs; // top level declarations for this Module Array aimports; // all imported modules ModuleInfoDeclaration vmoduleinfo; uint debuglevel; // debug level Array debugids; // debug identifiers Array debugidsNot; // forward referenced debug identifiers uint versionlevel; // version level Array versionids; // version identifiers Array versionidsNot; // forward referenced version identifiers Macro macrotable; // document comment macros Escape escapetable; // document comment escapes bool safe; // TRUE if module is marked as 'safe' this(string filename, Identifier ident, int doDocComment, int doHdrGen) { super(ident); FileName objfilename; aimports = new Array(); //writef("Module.Module(filename = '%s', ident = '%s')\n", filename, ident.toChars()); this.arg = filename; FileName srcfilename = FileName.defaultExt(filename, global.mars_ext); if (!srcfilename.equalsExt(global.mars_ext) && !srcfilename.equalsExt(global.hdr_ext) && !srcfilename.equalsExt("dd")) { if (srcfilename.equalsExt("html") || srcfilename.equalsExt("htm") || srcfilename.equalsExt("xhtml")) { if (!global.params.useDeprecated) error("html source files is deprecated %s", srcfilename.toChars()); isHtml = 1; } else { error("source file name '%s' must have .%s extension", srcfilename.toChars(), global.mars_ext); fatal(); } } string argobj; if (global.params.objname) argobj = global.params.objname; else if (global.params.preservePaths) argobj = filename; else argobj = FileName.name(filename); if (!FileName.absolute(argobj)) { argobj = FileName.combine(global.params.objdir, argobj); } if (global.params.objname) objfilename = new FileName(argobj); else objfilename = FileName.forceExt(argobj, global.obj_ext); FileName symfilename = FileName.forceExt(filename, global.sym_ext); srcfile = new File(srcfilename); if (doDocComment) { setDocfile(); } if (doHdrGen) { setHdrfile(); } objfile = new File(objfilename); symfile = new File(symfilename); } static Module load(Loc loc, Array packages, Identifier ident) { Module m; string filename; //writef("Module.load(ident = '%s')\n", ident.toChars()); // Build module filename by turning: // foo.bar.baz // into: // foo\bar\baz filename = ident.toChars(); if (packages && packages.dim) { scope OutBuffer buf = new OutBuffer(); int i; for (i = 0; i < packages.dim; i++) { Identifier pid = cast(Identifier)packages.data[i]; buf.writestring(pid.toChars()); version (_WIN32) { buf.writeByte('\\'); } else { buf.writeByte('/'); } } buf.writestring(filename); filename = buf.extractString(); } m = new Module(filename, ident, 0, 0); m.loc = loc; /* Search along global.path for .di file, then .d file. */ string result = null; FileName fdi = FileName.forceExt(filename, global.hdr_ext); FileName fd = FileName.forceExt(filename, global.mars_ext); string sdi = fdi.toChars(); string sd = fd.toChars(); if (FileName.exists(sdi)) { result = sdi; } else if (FileName.exists(sd)) { result = sd; } else if (FileName.absolute(filename)) { ; } else { foreach (p; global.path) { string n = FileName.combine(p, sdi); if (FileName.exists(n)) { result = n; break; } n = FileName.combine(p, sd); if (FileName.exists(n)) { result = n; break; } } } if (result) m.srcfile = new File(result); if (global.params.verbose) { writef("import "); if (packages) { for (size_t i = 0; i < packages.dim; i++) { Identifier pid = cast(Identifier)packages.data[i]; writef("%s.", pid.toChars()); } } writef("%s\t(%s)\n", ident.toChars(), m.srcfile.toChars()); } m.read(loc); m.parse(); version (IN_GCC) { d_gcc_magic_module(m); } return m; } override void toCBuffer(OutBuffer buf, HdrGenState* hgs) { assert(false); } override void toJsonBuffer(OutBuffer buf) { buf.writestring("{\n"); if (md) JsonProperty(buf, Pname, md.toChars()); JsonProperty(buf, Pkind, kind()); JsonProperty(buf, Pfile, srcfile.toChars()); if (comment) JsonProperty(buf, Pcomment, comment); JsonString(buf, Pmembers); buf.writestring(" : [\n"); size_t offset = buf.offset; foreach (Dsymbol s; members) { if (offset != buf.offset) { buf.writestring(",\n"); offset = buf.offset; } s.toJsonBuffer(buf); } JsonRemoveComma(buf); buf.writestring("]\n"); buf.writestring("}\n"); } override string kind() { return "module"; } void setDocfile() // set docfile member { assert(false); } void read(Loc loc) // read file { //writef("Module.read('%s') file '%s'\n", toChars(), srcfile.toChars()); if (srcfile.read()) { error(loc, "cannot read file '%s'", srcfile.toChars()); fatal(); } } version (IN_GCC) { void parse(bool dump_source = false) // syntactic parse { assert(false); } } else { void parse() // syntactic parse { uint le; uint bom; //printf("Module.parse()\n"); string srcname = srcfile.name.toChars(); //printf("Module.parse(srcname = '%s')\n", srcname); ubyte* buf = srcfile.buffer; uint 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 */ 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 = new OutBuffer(); uint* pu = cast(uint*)buf; uint* 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++) { uint 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 = cast(ubyte*) dbuf.extractData(); } else { // UTF-16LE (X86) // Convert it to UTF-8 le = 1; Lutf16: OutBuffer dbuf = new OutBuffer(); ushort* pu = cast(ushort*)(buf); ushort *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++) { uint u = le ? readwordLE(pu) : readwordBE(pu); if (u & ~0x7F) { if (u >= 0xD800 && u <= 0xDBFF) { uint 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 = cast(ubyte*) 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(); } } } version (IN_GCC) { // dump utf-8 encoded source if (dump_source) { // %% srcname could contain a path ... d_gcc_dump_source(srcname, "utf-8", buf, buflen); } } /* If it starts with the string "Ddoc", then it's a documentation * source file. */ if (buflen >= 4 && memcmp(buf, "Ddoc".ptr, 4) == 0) { comment = cast(string) ((buf + 4)[0 .. buflen]); isDocFile = 1; if (!docfile) setDocfile(); return; } if (isHtml) { assert(false); ///OutBuffer dbuf = new OutBuffer(); ///Html h = new Html(srcname, buf, buflen); ///h.extractCode(dbuf); ///buf = dbuf.data; ///buflen = dbuf.offset; version (IN_GCC) { // dump extracted source ///if (dump_source) /// d_gcc_dump_source(srcname, "d.utf-8", buf, buflen); } } auto p = new Parser(this, buf, buflen, docfile !is null); p.nextToken(); members = p.parseModule(); md = p.md; numlines = p.loc.linnum; DsymbolTable dst; if (md !is null) { this.ident = md.id; this.safe = md.safe; dst = super.resolve(md.packages, &this.parent, null); } 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)) { if (md) error(loc, "is in multiple packages %s", md.toChars()); else error(loc, "is in multiple defined"); } else { amodules.push(cast(void*)this); } } } override void importAll(Scope prevsc) { //writef("+Module.importAll(this = %p, '%s'): parent = %p\n", this, toChars(), parent); if (scope_ !is null) return; // already done /* Note that modules get their own scope, from scratch. * This is so regardless of where in the syntax a module * gets imported, it is unaffected by context. * Ignore prevsc. */ Scope sc = Scope.createGlobal(this); // create root scope // Add import of "object" if this module isn't "object" if (ident != Id.object) { if (members.dim == 0 || members[0].ident != Id.object) { Import im = new Import(Loc(), null, Id.object, null, 0); members.shift(im); } } if (!symtab) { // Add all symbols into module's symbol table symtab = new DsymbolTable(); foreach (Dsymbol s; members) s.addMember(null, sc.scopesym, 1); } // anything else should be run after addMember, so version/debug symbols are defined /* Set scope for the symbols so that if we forward reference * a symbol, it can possibly be resolved on the spot. * If this works out well, it can be extended to all modules * before any semantic() on any of them. */ setScope(sc); // remember module scope for semantic foreach (Dsymbol s; members) s.setScope(sc); foreach (Dsymbol s; members) s.importAll(sc); sc = sc.pop(); sc.pop(); // 2 pops because Scope::createGlobal() created 2 } void semantic() // semantic analysis { if (semanticstarted) return; //printf("+Module.semantic(this = %p, '%s'): parent = %p\n", this, toChars(), parent); semanticstarted = 1; // Note that modules get their own scope, from scratch. // This is so regardless of where in the syntax a module // gets imported, it is unaffected by context. Scope sc = scope_; // // see if already got one from importAll() if (!sc) { writef("test2\n"); Scope.createGlobal(this); // create root scope } //writef("Module = %p, linkage = %d\n", sc.scopesym, sc.linkage); static if (false) { // Add import of "object" if this module isn't "object" if (ident !is Id.object) { auto im = new Import(Loc(0), null, Id.object, null, 0); members.shift(im); } // Add all symbols into module's symbol table symtab = new DsymbolTable(); foreach(s; members) { s.addMember(null, sc.scopesym, true); } /* Set scope for the symbols so that if we forward reference * a symbol, it can possibly be resolved on the spot. * If this works out well, it can be extended to all modules * before any semantic() on any of them. */ foreach(Dsymbol s; members) s.setScope(sc); } // Pass 1 semantic routines: do public side of the definition foreach (Dsymbol s; members) { //writef("\tModule('%s'): '%s'.semantic()\n", toChars(), s.toChars()); s.semantic(sc); runDeferredSemantic(); } if (!scope_) { sc = sc.pop(); sc.pop(); // 2 pops because Scope.createGlobal() created 2 } semanticRun = semanticstarted; //printf("-Module.semantic(this = %p, '%s'): parent = %p\n", this, toChars(), parent); } void semantic2() // pass 2 semantic analysis { if (deferred.dim) { for (int i = 0; i < deferred.dim; i++) { Dsymbol sd = cast(Dsymbol)deferred.data[i]; sd.error("unable to resolve forward reference in definition"); } return; } //printf("Module.semantic2('%s'): parent = %p\n", toChars(), parent); if (semanticstarted >= 2) return; assert(semanticstarted == 1); semanticstarted = 2; // Note that modules get their own scope, from scratch. // This is so regardless of where in the syntax a module // gets imported, it is unaffected by context. Scope sc = Scope.createGlobal(this); // create root scope //printf("Module = %p\n", sc.scopesym); // Pass 2 semantic routines: do initializers and function bodies foreach(Dsymbol s; members) s.semantic2(sc); sc = sc.pop(); sc.pop(); semanticRun = semanticstarted; //printf("-Module.semantic2('%s'): parent = %p\n", toChars(), parent); } void semantic3() // pass 3 semantic analysis { //printf("Module.semantic3('%s'): parent = %p\n", toChars(), parent); if (semanticstarted >= 3) return; assert(semanticstarted == 2); semanticstarted = 3; // Note that modules get their own scope, from scratch. // This is so regardless of where in the syntax a module // gets imported, it is unaffected by context. Scope sc = Scope.createGlobal(this); // create root scope //printf("Module = %p\n", sc.scopesym); // Pass 3 semantic routines: do initializers and function bodies foreach(Dsymbol s; members) { //printf("Module %s: %s.semantic3()\n", toChars(), s.toChars()); s.semantic3(sc); } sc = sc.pop(); sc.pop(); semanticRun = semanticstarted; } override void inlineScan() // scan for functions to inline { if (semanticstarted >= 4) return; assert(semanticstarted == 3); semanticstarted = 4; // Note that modules get their own scope, from scratch. // This is so regardless of where in the syntax a module // gets imported, it is unaffected by context. //printf("Module = %p\n", sc.scopesym); foreach(Dsymbol s; members) { //if (global.params.verbose) //printf("inline scan symbol %s\n", s.toChars()); s.inlineScan(); } semanticRun = semanticstarted; } void setHdrfile() // set hdrfile member { FileName hdrfilename; string arghdr; if (global.params.hdrname) arghdr = global.params.hdrname; else if (global.params.preservePaths) arghdr = arg; else arghdr = FileName.name(arg); if (!FileName.absolute(arghdr)) { //FileName.ensurePathExists(global.params.hdrdir); arghdr = FileName.combine(global.params.hdrdir, arghdr); } if (global.params.hdrname) hdrfilename = new FileName(arghdr); else hdrfilename = FileName.forceExt(arghdr, global.hdr_ext); if (hdrfilename.str == srcfile.name.str) { error("Source file and 'header' file have same name '%s'", srcfile.name.str); fatal(); } hdrfile = new File(hdrfilename); } version (_DH) { void genhdrfile() // generate D import file { assert(false); } } /************************************** * Generate .obj file for Module. */ void genobjfile(int multiobj) { //EEcontext *ee = env.getEEcontext(); //printf("Module.genobjfile(multiobj = %d) %s\n", multiobj, toChars()); lastmname = srcfile.toChars(); /// global mutation obj_initfile(toStringz(lastmname), null, toStringz(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 = cast(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); static if (false) { /* This should work, but causes optlink to fail in common/newlib.asm */ objextdef(s.Sident); } else { version (ELFOBJ_OR_MACHOBJ) {///ELFOBJ || MACHOBJ int nbytes = reftoident(Segment.DATA, Offset(Segment.DATA), s, 0, CF.CFoff); Offset(Segment.DATA) += nbytes; } else { int nbytes = reftoident(Segment.DATA, Doffset, s, 0, CF.CFoff); Doffset() += nbytes; } } } } } if (global.params.cov) { /* Create coverage identifier: * private uint[numlines] __coverage; */ cov = symbol_calloc("__coverage"); cov.Stype = type_fake(TYM.TYint); cov.Stype.Tmangle = mTYman.mTYman_c; cov.Stype.Tcount++; cov.Sclass = SC.SCstatic; cov.Sfl = FL.FLdata; version (ELFOBJ_OR_MACHOBJ) { cov.Sseg = Segment.UDATA; } dtnzeros(&cov.Sdt, 4 * numlines); outdata(cov); slist_add(cov); covb = cast(uint*)GC.calloc(((numlines + 32) / 32) * (*covb).sizeof); } foreach(Dsymbol member; members) member.toObjFile(multiobj); if (global.params.cov) { /* Generate * bit[numlines] __bcoverage; */ Symbol* bcov = symbol_calloc("__bcoverage"); bcov.Stype = type_fake(TYM.TYuint); bcov.Stype.Tcount++; bcov.Sclass = SC.SCstatic; bcov.Sfl = FL.FLdata; version (ELFOBJ_OR_MACHOBJ) { bcov.Sseg = Segment.DATA; } dtnbytes(&bcov.Sdt, (numlines + 32) / 32 * (*covb).sizeof, cast(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(TYM.TYnfunc); t.Tflags |= TF.TFprototype | TF.TFfixed; t.Tmangle = mTYman.mTYman_c; t.Tnext = tsvoid; tsvoid.Tcount++; sictor = toSymbolX("__modictor", SC.SCglobal, t, "FZv"); cstate.CSpsymtab = &sictor.Sfunc.Flocsym; localgot = ictorlocalgot; elem* e; e = el_params(el_ptr(cov), el_long(TYM.TYuint, numlines), el_ptr(bcov), el_long(TYM.TYuint, numlines), toEfilename(), null); e = el_bin(OPER.OPcall, TYM.TYvoid, el_var(rtlsym[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(TYM.TYnfunc); t.Tflags |= TF.TFprototype | TF.TFfixed; t.Tmangle = mTYman.mTYman_c; t.Tnext = tsvoid; tsvoid.Tcount++; static string moddeco = "FZv"; if (eictor) { localgot = ictorlocalgot; block* b = block_calloc(); b.BC = BC.BCret; b.Belem = eictor; sictor.Sfunc.Fstartblock = b; writefunc(sictor); } if (ector || ectorgates.dim) { localgot = null; sctor = toSymbolX("__modctor", SC.SCglobal, t, moddeco); cstate.CSpsymtab = &sctor.Sfunc.Flocsym; for (int i = 0; i < ectorgates.dim; i++) { StaticDtorDeclaration f = cast(StaticDtorDeclaration)ectorgates.data[i]; Symbol* s = f.vgate.toSymbol(); elem* e = el_var(s); e = el_bin(OPER.OPaddass, TYM.TYint, e, el_long(TYM.TYint, 1)); ector = el_combine(ector, e); } block* b = block_calloc(); b.BC = BC.BCret; b.Belem = ector; sctor.Sfunc.Fstartblock = b; writefunc(sctor); version (STATICCTOR) { obj_staticctor(sctor, dtorcount, 1); } } if (edtor) { localgot = null; sdtor = toSymbolX("__moddtor", SC.SCglobal, t, moddeco); block* b = block_calloc(); b.BC = BC.BCret; b.Belem = edtor; sdtor.Sfunc.Fstartblock = b; writefunc(sdtor); } if (etest) { localgot = null; stest = toSymbolX("__modtest", SC.SCglobal, t, moddeco); block* b = block_calloc(); b.BC = 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".ptr); sp.Stype = type_fake(TYM.TYint); sp.Stype.Tcount++; sp.Sclass = SC.SCfastpar; sp.Spreg = REG.AX; sp.Sflags &= ~SFL.SFLspill; sp.Sfl = FL.FLpara; // FLauto? cstate.CSpsymtab = &ma.Sfunc.Flocsym; symbol_add(sp); elinnum = el_var(sp); } efilename = toEmodulename(); elem *e = el_var(rtlsym[i ? RTLSYM.RTLSYM_DARRAY : RTLSYM.RTLSYM_DASSERT]); e = el_bin(OPER.OPcall, TYM.TYvoid, e, el_param(elinnum, efilename)); block* b = block_calloc(); b.BC = BC.BCret; b.Belem = e; ma.Sfunc.Fstartblock = b; ma.Sclass = SC.SCglobal; ma.Sfl = 0; writefunc(ma); } } static if (true) { // Always generate module info, because of templates and -cov if (1 || needModuleInfo()) genmoduleinfo(); } obj_termfile(); } void gensymfile() { assert(false); } void gendocfile() { assert(false); } /********************************** * Determine if we need to generate an instance of ModuleInfo * for this Module. */ bool needModuleInfo() { // writef("needModuleInfo() %s, %d, %d\n", toChars(), needmoduleinfo, global.params.cov); return needmoduleinfo || global.params.cov; } override Dsymbol search(Loc loc, Identifier ident, int flags) { /* Since modules can be circularly referenced, * need to stop infinite recursive searches. * This is done with the cache. */ //printf("%s Module.search('%s', flags = %d) insearch = %d\n", toChars(), ident.toChars(), flags, insearch); Dsymbol s; if (insearch) s = null; else if (searchCacheIdent == ident && searchCacheFlags == flags) { s = searchCacheSymbol; //printf("%s Module.search('%s', flags = %d) insearch = %d searchCacheSymbol = %s\n", toChars(), ident.toChars(), flags, insearch, searchCacheSymbol ? searchCacheSymbol.toChars() : "null"); } else { insearch = 1; s = ScopeDsymbol.search(loc, ident, flags); insearch = 0; searchCacheIdent = ident; searchCacheSymbol = s; searchCacheFlags = flags; } return s; } void deleteObjFile() { if (global.params.obj) objfile.remove(); if (docfile) docfile.remove(); } override Dsymbol symtabInsert(Dsymbol s) { searchCacheIdent = null; // symbol is inserted, so invalidate cache return Package.symtabInsert(s); } /******************************************* * Can't run semantic on s now, try again later. */ void addDeferredSemantic(Dsymbol s) { // Don't add it if it is already there for (int i = 0; i < deferred.dim; i++) { Dsymbol sd = cast(Dsymbol)deferred.data[i]; if (sd == s) return; } //printf("Module::addDeferredSemantic('%s')\n", s.toChars()); deferred.push(cast(void*)s); } /****************************************** * Run semantic() on deferred symbols. */ void runDeferredSemantic() { size_t len; static int nested; if (nested) return; //if (deferred.dim) printf("+Module.runDeferredSemantic('%s'), len = %d\n", toChars(), deferred.dim); nested++; do { dprogress = 0; len = deferred.dim; if (!len) break; Dsymbol *todo; Dsymbol tmp; if (len == 1) { todo = &tmp; } else { version(Bug4054) todo = cast(Dsymbol*)GC.malloc(len * (Dsymbol*).sizeof); else todo = cast(Dsymbol*)alloca(len * (Dsymbol*).sizeof); assert(todo); } memcpy(todo, deferred.data, len * (Dsymbol*).sizeof); deferred.setDim(0); for (int i = 0; i < len; i++) { Dsymbol s = todo[i]; s.semantic(null); //printf("deferred: %s, parent = %s\n", s.toChars(), s.parent.toChars()); } //printf("\tdeferred.dim = %d, len = %d, dprogress = %d\n", deferred.dim, len, dprogress); } while (deferred.dim < len || dprogress); // while making progress nested--; //printf("-Module.runDeferredSemantic('%s'), len = %d\n", toChars(), deferred.dim); } /************************************ * Recursively look at every module this module imports, * return TRUE if it imports m. * Can be used to detect circular imports. */ bool imports(Module m) { // writef("%s Module::imports(%s)\n", toChars(), m.toChars()); int aimports_dim = aimports.dim; static if (false) { for (int i = 0; i < aimports.dim; i++) { Module mi = cast(Module)aimports.data[i]; writef("\t[%d] %s\n", i, mi.toChars()); } } for (int i = 0; i < aimports.dim; i++) { Module mi = cast(Module)aimports.data[i]; if (mi == m) return true; if (!mi.insearch) { mi.insearch = 1; bool r = mi.imports(m); if (r) return r; } } return false; } // Back end int doppelganger; // sub-module Symbol* cov; // private uint[] __coverage; uint* covb; // bit array of valid code line numbers Symbol* sictor; // module order independent constructor Symbol* sctor; // module constructor Symbol* sdtor; // module destructor Symbol* stest; // module unit test Symbol* sfilename; // symbol for filename Symbol* massert; // module assert function Symbol* toModuleAssert() // get module assert function { if (!massert) { type* t; t = type_alloc(TYjfunc); t.Tflags |= TFprototype | TFfixed; t.Tmangle = mTYman_d; t.Tnext = tsvoid; tsvoid.Tcount++; massert = toSymbolX("__assert", SCextern, t, "FiZv"); massert.Sfl = FLextern; massert.Sflags |= SFLnodebug; slist_add(massert); } return massert; } Symbol* marray; // module array bounds function Symbol* toModuleArray() // get module array bounds function { if (!marray) { type* t; t = type_alloc(TYjfunc); t.Tflags |= TFprototype | TFfixed; t.Tmangle = mTYman_d; t.Tnext = tsvoid; tsvoid.Tcount++; marray = toSymbolX("__array", SCextern, t, "Z"); marray.Sfl = FLextern; marray.Sflags |= SFLnodebug; slist_add(marray); } return marray; } static Symbol* gencritsec() { assert(false); } elem* toEfilename() { elem* efilename; if (!sfilename) { dt_t* dt = null; string id = srcfile.toChars(); int len = id.length; dtdword(&dt, len); dtabytes(&dt,TYnptr, 0, len + 1, toStringz(id)); sfilename = symbol_generate(SCstatic,type_fake(TYdarray)); sfilename.Sdt = dt; sfilename.Sfl = FLdata; version (ELFOBJ) { sfilename.Sseg = Segment.CDATA; } version (MACHOBJ) { // Because of PIC and CDATA being in the _TEXT segment, cannot // have pointers in CDATA sfilename.Sseg = Segment.DATA; } outdata(sfilename); } efilename = el_var(sfilename); return efilename; } /************************************** * Generate elem that is a pointer to the module file name. */ elem* toEmodulename() { elem *efilename; // Get filename if (needModuleInfo()) { /* Class ModuleInfo is defined in std.moduleinfo. * The first member is the name of it, char name[], * which will be at offset 8. */ Symbol* si = toSymbol(); static if (true) { // Use this instead so -fPIC will work efilename = el_ptr(si); efilename = el_bin(OPadd, TYnptr, efilename, el_long(TYuint, 8)); efilename = el_una(OPind, TYdarray, efilename); } else { efilename = el_var(si); efilename.Ety = TYdarray; efilename.EV.sp.Voffset += 8; } } else // generate our own filename { efilename = toEfilename(); } return efilename; } /************************************* * Create the "ModuleInfo" symbol */ override Symbol* toSymbol() { if (!csym) { Symbol* s; static Classsym* scc; if (!scc) { scc = fake_classsym(Id.ClassInfo); } s = toSymbolX("__ModuleInfo", SC.SCextern, scc.Stype, "Z"); s.Sfl = FL.FLextern; s.Sflags |= SFL.SFLnodebug; csym = s; slist_add(s); } return csym; } // Put out instance of ModuleInfo for this Module void genmoduleinfo() { //printf("Module.genmoduleinfo() %s\n", toChars()); Symbol* msym = toSymbol(); //dumpSymbol(msym); uint offset; version (DMDV2) { uint sizeof_ModuleInfo = 18 * PTRSIZE; } else { uint sizeof_ModuleInfo = 14 * PTRSIZE; } ////////////////////////////////////////////// csym.Sclass = SC.SCglobal; csym.Sfl = FL.FLdata; /* The layout is: { void **vptr; monitor_t monitor; char[] name; // class name ModuleInfo importedModules[]; ClassInfo localClasses[]; uint flags; // initialization state void *ctor; void *dtor; void *unitTest; const(MemberInfo[]) function(string) xgetMembers; // module getMembers() function void *ictor; void*[4] reserved; } */ dt_t* dt = null; if (moduleinfo) dtxoff(&dt, moduleinfo.toVtblSymbol(), 0, TYM.TYnptr); // vtbl for ModuleInfo else { //printf("moduleinfo is null\n"); dtdword(&dt, 0); // BUG: should be an assert() } dtdword(&dt, 0); // monitor // name[] string name = toPrettyChars(); size_t namelen = name.length; dtdword(&dt, namelen); dtabytes(&dt, TYM.TYnptr, 0, namelen + 1, toStringz(name)); ClassDeclarations aclasses = new ClassDeclarations(); //printf("members.dim = %d\n", members.dim); foreach(Dsymbol member; members) { //printf("\tmember '%s'\n", member.toChars()); member.addLocalClass(aclasses); } // importedModules[] int aimports_dim = aimports.dim; for (int i = 0; i < aimports.dim; i++) { Module m = cast(Module)aimports.data[i]; if (!m.needModuleInfo()) aimports_dim--; } dtdword(&dt, aimports_dim); if (aimports_dim) dtxoff(&dt, csym, sizeof_ModuleInfo, TYM.TYnptr); else dtdword(&dt, 0); // localClasses[] dtdword(&dt, aclasses.dim); if (aclasses.dim) dtxoff(&dt, csym, sizeof_ModuleInfo + aimports_dim * PTRSIZE, TYM.TYnptr); else dtdword(&dt, 0); if (needmoduleinfo) dtdword(&dt, 8|0); // flags (4 means MIstandalone) else dtdword(&dt, 8|4); // flags (4 means MIstandalone) if (sctor) dtxoff(&dt, sctor, 0, TYM.TYnptr); else dtdword(&dt, 0); if (sdtor) dtxoff(&dt, sdtor, 0, TYM.TYnptr); else dtdword(&dt, 0); if (stest) dtxoff(&dt, stest, 0, TYM.TYnptr); else dtdword(&dt, 0); /// version (DMDV2) { FuncDeclaration sgetmembers = findGetMembers(); if (sgetmembers) dtxoff(&dt, sgetmembers.toSymbol(), 0, TYM.TYnptr); else /// } dtdword(&dt, 0); // xgetMembers if (sictor) dtxoff(&dt, sictor, 0, TYM.TYnptr); else dtdword(&dt, 0); version (DMDV2) { // void*[4] reserved; dtdword(&dt, 0); dtdword(&dt, 0); dtdword(&dt, 0); dtdword(&dt, 0); } ////////////////////////////////////////////// for (int i = 0; i < aimports.dim; i++) { Module m = cast(Module)aimports.data[i]; if (m.needModuleInfo()) { Symbol* s = m.toSymbol(); /* 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. */ version (OMFOBJ) {// Optlink crashes with weak symbols at EIP 41AFE7, 402000 } else { s.Sflags |= SFL.SFLweak; } dtxoff(&dt, s, 0, TYM.TYnptr); } } for (int i = 0; i < aclasses.dim; i++) { ClassDeclaration cd = cast(ClassDeclaration)aclasses.data[i]; dtxoff(&dt, cd.toSymbol(), 0, TYM.TYnptr); } csym.Sdt = dt; version (ELFOBJ_OR_MACHOBJ) { // Cannot be CONST because the startup code sets flag bits in it csym.Sseg = Segment.DATA; } outdata(csym); ////////////////////////////////////////////// obj_moduleinfo(msym); } override Module isModule() { return this; } }