view src/share/tools/MakeDeps/Database.java @ 1334:193a468093fa hs17-b15

6955813: Fix incorrect Oracle rebranding headers from 6941466 Summary: Redo the header changes to fix new copyright notice style Reviewed-by: ohair
author trims
date Wed, 26 May 2010 00:30:39 -0700
parents 885e7f460925
children
line wrap: on
line source

/*
 * Copyright (c) 1999, 2009, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.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 HashMap<String,String> platformDepFiles;
  private long threshold;
  private int nOuterFiles;
  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);
    platformDepFiles = new HashMap<String,String>();

    threshold = t;
    nOuterFiles = 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());

              // Record the implicit include of this file so that the
              // dependencies for precompiled headers can mention it.
              platformDepFiles.put(newIncluder, includer);

              // 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() +
            "\"");
      }
    }
    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 dependent 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();
    }

    // write Precompiled_Files = ...
    gd.println("Precompiled_Files = \\");
    for (Iterator iter = grandInclude.iterator(); iter.hasNext(); ) {
      FileList list = (FileList) iter.next();
      if (list.getCount() >= threshold) {
        gd.println(list.getName() + " \\");
        String platformDep = platformDepFiles.get(list.getName());
        if (platformDep != null) {
          // make sure changes to the platform dependent file will
          // cause regeneration of the pch file.
          gd.println(platformDep + " \\");
        }
      }
    }
    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()
            && 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);
  }
}