duke@435: /* duke@435: * Copyright 1999-2005 Sun Microsystems, Inc. All Rights Reserved. duke@435: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. duke@435: * duke@435: * This code is free software; you can redistribute it and/or modify it duke@435: * under the terms of the GNU General Public License version 2 only, as duke@435: * published by the Free Software Foundation. duke@435: * duke@435: * This code is distributed in the hope that it will be useful, but WITHOUT duke@435: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or duke@435: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License duke@435: * version 2 for more details (a copy is included in the LICENSE file that duke@435: * accompanied this code). duke@435: * duke@435: * You should have received a copy of the GNU General Public License version duke@435: * 2 along with this work; if not, write to the Free Software Foundation, duke@435: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. duke@435: * duke@435: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, duke@435: * CA 95054 USA or visit www.sun.com if you need additional information or duke@435: * have any questions. duke@435: * duke@435: */ duke@435: duke@435: import java.io.*; duke@435: import java.util.*; duke@435: duke@435: public class Database { duke@435: private MacroDefinitions macros; duke@435: // allFiles is kept in lexicographically sorted order. See get(). duke@435: private FileList allFiles; duke@435: // files that have implicit dependency on platform files duke@435: // e.g. os.hpp: os_.hpp os_.hpp but only duke@435: // recorded if the platform file was seen. duke@435: private FileList platformFiles; duke@435: private FileList outerFiles; duke@435: private FileList indivIncludes; duke@435: private FileList grandInclude; // the results for the grand include file never@648: private HashMap platformDepFiles; duke@435: private long threshold; duke@435: private int nOuterFiles; duke@435: private int nPrecompiledFiles; duke@435: private boolean missingOk; duke@435: private Platform plat; duke@435: /** These allow you to specify files not in the include database duke@435: which are prepended and appended to the file list, allowing duke@435: you to have well-known functions at the start and end of the duke@435: text segment (allows us to find out in a portable fashion duke@435: whether the current PC is in VM code or not upon a crash) */ duke@435: private String firstFile; duke@435: private String lastFile; duke@435: duke@435: public Database(Platform plat, long t) { duke@435: this.plat = plat; duke@435: macros = new MacroDefinitions(); duke@435: allFiles = new FileList("allFiles", plat); duke@435: platformFiles = new FileList("platformFiles", plat); duke@435: outerFiles = new FileList("outerFiles", plat); duke@435: indivIncludes = new FileList("IndivIncludes", plat); duke@435: grandInclude = new FileList(plat.getGIFileTemplate().nameOfList(), plat); never@648: platformDepFiles = new HashMap(); duke@435: duke@435: threshold = t; duke@435: nOuterFiles = 0; duke@435: nPrecompiledFiles = 0; duke@435: missingOk = false; duke@435: firstFile = null; duke@435: lastFile = null; duke@435: }; duke@435: duke@435: public FileList getAllFiles() { duke@435: return allFiles; duke@435: } duke@435: duke@435: public Iterator getMacros() { duke@435: return macros.getMacros(); duke@435: } duke@435: duke@435: public void canBeMissing() { duke@435: missingOk = true; duke@435: } duke@435: duke@435: public boolean hfileIsInGrandInclude(FileList hfile, FileList cfile) { duke@435: return ((hfile.getCount() >= threshold) && (cfile.getUseGrandInclude())); duke@435: } duke@435: duke@435: /** These allow you to specify files not in the include database duke@435: which are prepended and appended to the file list, allowing duke@435: you to have well-known functions at the start and end of the duke@435: text segment (allows us to find out in a portable fashion duke@435: whether the current PC is in VM code or not upon a crash) */ duke@435: public void setFirstFile(String fileName) { duke@435: firstFile = fileName; duke@435: } duke@435: duke@435: public void setLastFile(String fileName) { duke@435: lastFile = fileName; duke@435: } duke@435: duke@435: public void get(String platFileName, String dbFileName) duke@435: throws FileFormatException, IOException, FileNotFoundException { duke@435: macros.readFrom(platFileName, missingOk); duke@435: duke@435: BufferedReader reader = null; duke@435: try { duke@435: reader = new BufferedReader(new FileReader(dbFileName)); duke@435: } catch (FileNotFoundException e) { duke@435: if (missingOk) { duke@435: return; duke@435: } else { duke@435: throw(e); duke@435: } duke@435: } duke@435: System.out.println("\treading database: " + dbFileName); duke@435: String line; duke@435: int lineNo = 0; duke@435: do { duke@435: line = reader.readLine(); duke@435: lineNo++; duke@435: if (line != null) { duke@435: StreamTokenizer tokenizer = duke@435: new StreamTokenizer(new StringReader(line)); duke@435: tokenizer.slashSlashComments(true); duke@435: tokenizer.wordChars('_', '_'); duke@435: tokenizer.wordChars('<', '>'); duke@435: // NOTE: if we didn't have to do this line by line, duke@435: // we could trivially recognize C-style comments as duke@435: // well. duke@435: // tokenizer.slashStarComments(true); duke@435: int numTok = 0; duke@435: int res; duke@435: String unexpandedIncluder = null; duke@435: String unexpandedIncludee = null; duke@435: do { duke@435: res = tokenizer.nextToken(); duke@435: if (res != StreamTokenizer.TT_EOF) { duke@435: if (numTok == 0) { duke@435: unexpandedIncluder = tokenizer.sval; duke@435: } else if (numTok == 1) { duke@435: unexpandedIncludee = tokenizer.sval; duke@435: } else { duke@435: throw new FileFormatException( duke@435: "invalid line: \"" + line + duke@435: "\". Error position: line " + lineNo duke@435: ); duke@435: } duke@435: numTok++; duke@435: } duke@435: } while (res != StreamTokenizer.TT_EOF); duke@435: duke@435: if ((numTok != 0) && (numTok != 2)) { duke@435: throw new FileFormatException( duke@435: "invalid line: \"" + line + duke@435: "\". Error position: line " + lineNo duke@435: ); duke@435: } duke@435: duke@435: if (numTok == 2) { duke@435: // Non-empty line duke@435: String includer = macros.expand(unexpandedIncluder); duke@435: String includee = macros.expand(unexpandedIncludee); duke@435: duke@435: if (includee.equals(plat.generatePlatformDependentInclude())) { duke@435: MacroDefinitions localExpander = macros.copy(); duke@435: MacroDefinitions localExpander2 = macros.copy(); duke@435: localExpander.setAllMacroBodiesTo("pd"); duke@435: localExpander2.setAllMacroBodiesTo(""); duke@435: duke@435: // unexpanded_includer e.g. thread_.hpp duke@435: // thread_solaris_i486.hpp -> _thread_pd.hpp.incl duke@435: duke@435: FileName pdName = duke@435: plat.getInclFileTemplate().copyStem( duke@435: localExpander.expand(unexpandedIncluder) duke@435: ); duke@435: duke@435: // derive generic name from platform specific name duke@435: // e.g. os_.hpp => os.hpp. We enforce the duke@435: // restriction (imperfectly) noted in includeDB_core duke@435: // that platform specific files will have an underscore duke@435: // preceding the macro invocation. duke@435: duke@435: // First expand macro as null string. duke@435: duke@435: String newIncluder_temp = duke@435: localExpander2.expand(unexpandedIncluder); duke@435: duke@435: // Now find "_." and remove the underscore. duke@435: duke@435: String newIncluder = ""; duke@435: duke@435: int len = newIncluder_temp.length(); duke@435: int count = 0; duke@435: duke@435: for ( int i = 0; i < len - 1 ; i++ ) { duke@435: if (newIncluder_temp.charAt(i) == '_' && newIncluder_temp.charAt(i+1) == '.') { duke@435: count++; duke@435: } else { duke@435: newIncluder += newIncluder_temp.charAt(i); duke@435: } duke@435: } duke@435: newIncluder += newIncluder_temp.charAt(len-1); duke@435: duke@435: if (count != 1) { duke@435: throw new FileFormatException( duke@435: "Unexpected filename format for platform dependent file.\nline: \"" + line + duke@435: "\".\nError position: line " + lineNo duke@435: ); duke@435: } duke@435: duke@435: FileList p = allFiles.listForFile(includer); duke@435: p.setPlatformDependentInclude(pdName.dirPreStemSuff()); duke@435: never@648: // Record the implicit include of this file so that the never@648: // dependencies for precompiled headers can mention it. never@648: platformDepFiles.put(newIncluder, includer); never@648: duke@435: // Add an implicit dependency on platform duke@435: // specific file for the generic file duke@435: duke@435: p = platformFiles.listForFile(newIncluder); duke@435: duke@435: // if this list is empty then this is 1st duke@435: // occurance of a platform dependent file and duke@435: // we need a new version of the include file. duke@435: // Otherwise we just append to the current duke@435: // file. duke@435: duke@435: PrintWriter pdFile = duke@435: new PrintWriter( duke@435: new FileWriter(pdName.dirPreStemSuff(), duke@435: !p.isEmpty()) duke@435: ); duke@435: pdFile.println("# include \"" + includer + "\""); duke@435: pdFile.close(); duke@435: duke@435: // Add the platform specific file to the list duke@435: // for this generic file. duke@435: duke@435: FileList q = allFiles.listForFile(includer); duke@435: p.addIfAbsent(q); duke@435: } else { duke@435: FileList p = allFiles.listForFile(includer); duke@435: if (isOuterFile(includer)) duke@435: outerFiles.addIfAbsent(p); duke@435: duke@435: if (includee.equals(plat.noGrandInclude())) { duke@435: p.setUseGrandInclude(false); duke@435: } else { duke@435: FileList q = allFiles.listForFile(includee); duke@435: p.addIfAbsent(q); duke@435: } duke@435: } duke@435: } duke@435: } duke@435: } while (line != null); duke@435: reader.close(); duke@435: duke@435: // Keep allFiles in well-known order so we can easily determine duke@435: // whether the known files are the same duke@435: allFiles.sortByName(); duke@435: duke@435: // Add first and last files differently to prevent a mistake duke@435: // in ordering in the include databases from breaking the duke@435: // error reporting in the VM. duke@435: if (firstFile != null) { duke@435: FileList p = allFiles.listForFile(firstFile); duke@435: allFiles.setFirstFile(p); duke@435: outerFiles.setFirstFile(p); duke@435: } duke@435: duke@435: if (lastFile != null) { duke@435: FileList p = allFiles.listForFile(lastFile); duke@435: allFiles.setLastFile(p); duke@435: outerFiles.setLastFile(p); duke@435: } duke@435: } duke@435: duke@435: public void compute() { duke@435: System.out.println("\tcomputing closures\n"); duke@435: // build both indiv and grand results duke@435: for (Iterator iter = outerFiles.iterator(); iter.hasNext(); ) { duke@435: indivIncludes.add(((FileList) iter.next()).doCFile()); duke@435: ++nOuterFiles; duke@435: } duke@435: duke@435: if (!plat.haveGrandInclude()) duke@435: return; // nothing in grand include duke@435: duke@435: // count how many times each include is included & add em to grand duke@435: for (Iterator iter = indivIncludes.iterator(); iter.hasNext(); ) { duke@435: FileList indivInclude = (FileList) iter.next(); duke@435: if (!indivInclude.getUseGrandInclude()) { duke@435: continue; // do not bump count if my files cannot be duke@435: // in grand include duke@435: } duke@435: indivInclude.doFiles(grandInclude); // put em on duke@435: // grand_include list duke@435: for (Iterator incListIter = indivInclude.iterator(); duke@435: incListIter.hasNext(); ) { duke@435: ((FileList) incListIter.next()).incrementCount(); duke@435: } duke@435: } duke@435: } duke@435: duke@435: // Not sure this is necessary in Java duke@435: public void verify() { duke@435: for (Iterator iter = indivIncludes.iterator(); iter.hasNext(); ) { duke@435: if (iter.next() == null) { duke@435: plat.abort(); duke@435: } duke@435: } duke@435: } duke@435: duke@435: public void put() throws IOException { duke@435: writeIndividualIncludes(); duke@435: duke@435: if (plat.haveGrandInclude()) duke@435: writeGrandInclude(); duke@435: duke@435: writeGrandUnixMakefile(); duke@435: } duke@435: duke@435: private void writeIndividualIncludes() throws IOException { duke@435: System.out.println("\twriting individual include files\n"); duke@435: duke@435: for (Iterator iter = indivIncludes.iterator(); iter.hasNext(); ) { duke@435: FileList list = (FileList) iter.next(); duke@435: System.out.println("\tcreating " + list.getName()); duke@435: list.putInclFile(this); duke@435: } duke@435: } duke@435: duke@435: private void writeGrandInclude() throws IOException { duke@435: System.out.println("\twriting grand include file\n"); duke@435: PrintWriter inclFile = duke@435: new PrintWriter(new FileWriter(plat.getGIFileTemplate().dirPreStemSuff())); duke@435: plat.writeGIPragma(inclFile); duke@435: for (Iterator iter = grandInclude.iterator(); iter.hasNext(); ) { duke@435: FileList list = (FileList) iter.next(); duke@435: if (list.getCount() >= threshold) { duke@435: inclFile.println("# include \"" + duke@435: plat.getGIFileTemplate().getInvDir() + duke@435: list.getName() + duke@435: "\""); duke@435: nPrecompiledFiles += 1; duke@435: } duke@435: } duke@435: inclFile.println(); duke@435: inclFile.close(); duke@435: } duke@435: duke@435: private void writeGrandUnixMakefile() throws IOException { duke@435: if (!plat.writeDeps()) duke@435: return; duke@435: duke@435: System.out.println("\twriting dependencies file\n"); duke@435: PrintWriter gd = duke@435: new PrintWriter(new FileWriter( duke@435: plat.getGDFileTemplate().dirPreStemSuff()) duke@435: ); duke@435: gd.println("# generated by makeDeps"); duke@435: gd.println(); duke@435: duke@435: duke@435: // HACK ALERT. The compilation of ad_ files is very slow. duke@435: // We want to start compiling them as early as possible. The compilation twisti@1040: // order on unix is dependent on the order we emit files here. duke@435: // By sorting the output before emitting it, we expect duke@435: // that ad_ will be compiled early. duke@435: boolean shouldSortObjFiles = true; duke@435: duke@435: if (shouldSortObjFiles) { duke@435: ArrayList sortList = new ArrayList(); duke@435: duke@435: // We need to preserve the ordering of the first and last items duke@435: // in outerFiles. duke@435: int size = outerFiles.size() - 1; duke@435: String firstName = removeSuffixFrom(((FileList)outerFiles.get(0)).getName()); duke@435: String lastName = removeSuffixFrom(((FileList)outerFiles.get(size)).getName()); duke@435: duke@435: for (int i=1; i 0) { duke@435: // write Precompiled_Files = ... duke@435: gd.println("Precompiled_Files = \\"); duke@435: for (Iterator iter = grandInclude.iterator(); iter.hasNext(); ) { duke@435: FileList list = (FileList) iter.next(); duke@435: gd.println(list.getName() + " \\"); never@648: String platformDep = platformDepFiles.get(list.getName()); never@648: if (platformDep != null) { never@648: // make sure changes to the platform dependent file will never@648: // cause regeneration of the pch file. never@648: gd.println(platformDep + " \\"); never@648: } duke@435: } duke@435: gd.println(); duke@435: gd.println(); duke@435: } duke@435: duke@435: gd.println("DTraced_Files = \\"); duke@435: for (Iterator iter = outerFiles.iterator(); iter.hasNext(); ) { duke@435: FileList anOuterFile = (FileList) iter.next(); duke@435: duke@435: if (anOuterFile.hasListForFile("dtrace.hpp")) { duke@435: String stemName = removeSuffixFrom(anOuterFile.getName()); duke@435: gd.println(stemName + plat.objFileSuffix() + " \\"); duke@435: } duke@435: } duke@435: gd.println(); duke@435: gd.println(); duke@435: duke@435: { duke@435: // write each dependency duke@435: duke@435: for (Iterator iter = indivIncludes.iterator(); iter.hasNext(); ) { duke@435: duke@435: FileList anII = (FileList) iter.next(); duke@435: duke@435: String stemName = removeSuffixFrom(anII.getName()); duke@435: String inclFileName = duke@435: plat.getInclFileTemplate().copyStem(anII.getName()). duke@435: preStemSuff(); duke@435: duke@435: gd.println(stemName + plat.objFileSuffix() + " " + duke@435: stemName + plat.asmFileSuffix() + ": \\"); duke@435: duke@435: printDependentOn(gd, anII.getName()); duke@435: // this gets the include file that includes all that duke@435: // this file needs (first level) since nested includes duke@435: // are skipped to avoid cycles. duke@435: printDependentOn(gd, inclFileName); duke@435: duke@435: if ( plat.haveGrandInclude() ) { duke@435: printDependentOn(gd, duke@435: plat.getGIFileTemplate().preStemSuff()); duke@435: } duke@435: duke@435: for (Iterator iiIter = anII.iterator(); iiIter.hasNext(); ) { duke@435: FileList hfile = (FileList) iiIter.next(); duke@435: if (!hfileIsInGrandInclude(hfile, anII) || duke@435: plat.writeDependenciesOnHFilesFromGI()) { duke@435: printDependentOn(gd, hfile.getName()); duke@435: } duke@435: if (platformFiles.hasListForFile(hfile.getName())) { duke@435: FileList p = duke@435: platformFiles.listForFile(hfile.getName());; duke@435: for (Iterator hiIter = p.iterator(); duke@435: hiIter.hasNext(); ) { duke@435: FileList hi2 = (FileList) hiIter.next(); duke@435: if (!hfileIsInGrandInclude(hi2, p)) { duke@435: printDependentOn(gd, hi2.getName()); duke@435: } duke@435: } duke@435: } duke@435: } duke@435: duke@435: if (plat.includeGIDependencies() duke@435: && nPrecompiledFiles > 0 duke@435: && anII.getUseGrandInclude()) { duke@435: gd.println(" $(Precompiled_Files) \\"); duke@435: } duke@435: gd.println(); duke@435: gd.println(); duke@435: } duke@435: } duke@435: duke@435: gd.close(); duke@435: } duke@435: duke@435: public void putDiffs(Database previous) throws IOException { duke@435: System.out.println("\tupdating output files\n"); duke@435: duke@435: if (!indivIncludes.compareLists(previous.indivIncludes) duke@435: || !grandInclude.compareLists(previous.grandInclude)) { duke@435: System.out.println("The order of .c or .s has changed, or " + duke@435: "the grand include file has changed."); duke@435: put(); duke@435: return; duke@435: } duke@435: duke@435: Iterator curIter = indivIncludes.iterator(); duke@435: Iterator prevIter = previous.indivIncludes.iterator(); duke@435: duke@435: try { duke@435: while (curIter.hasNext()) { duke@435: FileList newCFileList = (FileList) curIter.next(); duke@435: FileList prevCFileList = (FileList) prevIter.next(); duke@435: if (!newCFileList.compareLists(prevCFileList)) { duke@435: System.out.println("\tupdating " + newCFileList.getName()); duke@435: newCFileList.putInclFile(this); duke@435: } duke@435: } duke@435: } duke@435: catch (Exception e) { duke@435: throw new InternalError("assertion failure: cur and prev " + duke@435: "database lists changed unexpectedly."); duke@435: } duke@435: duke@435: writeGrandUnixMakefile(); duke@435: } duke@435: duke@435: private void printDependentOn(PrintWriter gd, String name) { duke@435: gd.print(" "); duke@435: gd.print(plat.dependentPrefix() + name); duke@435: } duke@435: duke@435: private boolean isOuterFile(String s) { duke@435: int len = s.length(); duke@435: String[] suffixes = plat.outerSuffixes(); duke@435: for (int i = 0; i < suffixes.length; i++) { duke@435: String suffix = suffixes[i]; duke@435: int suffLen = suffix.length(); duke@435: if ((len >= suffLen) && duke@435: (plat.fileNameStringEquality(s.substring(len - suffLen), duke@435: suffix))) { duke@435: return true; duke@435: } duke@435: } duke@435: return false; duke@435: } duke@435: duke@435: private String removeSuffixFrom(String s) { duke@435: int idx = s.lastIndexOf('.'); duke@435: if (idx <= 0) duke@435: plat.abort(); duke@435: return s.substring(0, idx); duke@435: } duke@435: }