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