blob: c26ef1d6fc3b3ca37ddfd5d4d7a933f6051ecb30 [file] [log] [blame]
/*
* 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);
}
}