diff -r 000000000000 -r 959103a6100f src/share/classes/com/sun/tools/sjavac/BuildState.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/com/sun/tools/sjavac/BuildState.java Wed Apr 27 01:34:52 2016 +0800 @@ -0,0 +1,279 @@ +/* + * Copyright (c) 2012, 2013, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package com.sun.tools.sjavac; + +import java.io.File; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * The build state class captures the source code and generated artifacts + * from a build. There are usually two build states, the previous one (prev), + * loaded from the javac_state file, and the current one (now). + * + *

This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own + * risk. This code and its internal interfaces are subject to change + * or deletion without notice.

+ */ +public class BuildState { + private Map modules = new HashMap(); + private Map packages = new HashMap(); + private Map sources = new HashMap(); + private Map artifacts = new HashMap(); + // Map from package to a set of packages that depend on said package. + private Map> dependents = new HashMap>(); + + public Map modules() { return modules; } + public Map packages() { return packages; } + public Map sources() { return sources; } + public Map artifacts() { return artifacts; } + public Map> dependents() { return dependents; } + + /** + * Lookup a module from a name. Create the module if it does + * not exist yet. + */ + public Module lookupModule(String mod) { + Module m = modules.get(mod); + if (m == null) { + m = new Module(mod, "???"); + modules.put(mod, m); + } + return m; + } + + /** + * Find a module from a given package name. For example: + * The package name "base:java.lang" will fetch the module named "base". + * The package name ":java.net" will fetch the default module. + */ + Module findModuleFromPackageName(String pkg) { + int cp = pkg.indexOf(':'); + assert(cp != -1); + String mod = pkg.substring(0, cp); + return lookupModule(mod); + } + + /** + * Store references to all packages, sources and artifacts for all modules + * into the build state. I.e. flatten the module tree structure + * into global maps stored in the BuildState for easy access. + * + * @param m The set of modules. + */ + public void flattenPackagesSourcesAndArtifacts(Map m) { + modules = m; + // Extract all the found packages. + for (Module i : modules.values()) { + for (Map.Entry j : i.packages().entrySet()) { + Package p = packages.get(j.getKey()); + // Check that no two different packages are stored under same name. + assert(p == null || p == j.getValue()); + if (p == null) { + p = j.getValue(); + packages.put(j.getKey(),j.getValue()); + } + for (Map.Entry k : p.sources().entrySet()) { + Source s = sources.get(k.getKey()); + // Check that no two different sources are stored under same name. + assert(s == null || s == k.getValue()); + if (s == null) { + s = k.getValue(); + sources.put(k.getKey(), k.getValue()); + } + } + for (Map.Entry g : p.artifacts().entrySet()) { + File f = artifacts.get(g.getKey()); + // Check that no two artifacts are stored under the same file. + assert(f == null || f == g.getValue()); + if (f == null) { + f = g.getValue(); + artifacts.put(g.getKey(), g.getValue()); + } + } + } + } + } + + /** + * Store references to all artifacts found in the module tree into the maps + * stored in the build state. + * + * @param m The set of modules. + */ + public void flattenArtifacts(Map m) { + modules = m; + // Extract all the found packages. + for (Module i : modules.values()) { + for (Map.Entry j : i.packages().entrySet()) { + Package p = packages.get(j.getKey()); + // Check that no two different packages are stored under same name. + assert(p == null || p == j.getValue()); + p = j.getValue(); + packages.put(j.getKey(),j.getValue()); + for (Map.Entry g : p.artifacts().entrySet()) { + File f = artifacts.get(g.getKey()); + // Check that no two artifacts are stored under the same file. + assert(f == null || f == g.getValue()); + artifacts.put(g.getKey(), g.getValue()); + } + } + } + } + + /** + * Calculate the package dependents (ie the reverse of the dependencies). + */ + public void calculateDependents() { + dependents = new HashMap>(); + for (String s : packages.keySet()) { + Package p = packages.get(s); + for (String d : p.dependencies()) { + Set ss = dependents.get(d); + if (ss == null) { + ss = new HashSet(); + dependents.put(d, ss); + } + // Add the dependent information to the global dependent map. + ss.add(s); + Package dp = packages.get(d); + // Also add the dependent information to the package specific map. + // Normally, you do not compile java.lang et al. Therefore + // there are several packages that p depends upon that you + // do not have in your state database. This is perfectly fine. + if (dp != null) { + // But this package did exist in the state database. + dp.addDependent(p.name()); + } + } + } + } + + /** + * Verify that the setModules method above did the right thing when + * running through the module->package->source structure. + */ + public void checkInternalState(String msg, boolean linkedOnly, Map srcs) { + boolean baad = false; + Map original = new HashMap(); + Map calculated = new HashMap(); + + for (String s : sources.keySet()) { + Source ss = sources.get(s); + if (ss.isLinkedOnly() == linkedOnly) { + calculated.put(s,ss); + } + } + for (String s : srcs.keySet()) { + Source ss = srcs.get(s); + if (ss.isLinkedOnly() == linkedOnly) { + original.put(s,ss); + } + } + if (original.size() != calculated.size()) { + Log.error("INTERNAL ERROR "+msg+" original and calculated are not the same size!"); + baad = true; + } + if (!original.keySet().equals(calculated.keySet())) { + Log.error("INTERNAL ERROR "+msg+" original and calculated do not have the same domain!"); + baad = true; + } + if (!baad) { + for (String s : original.keySet()) { + Source s1 = original.get(s); + Source s2 = calculated.get(s); + if (s1 == null || s2 == null || !s1.equals(s2)) { + Log.error("INTERNAL ERROR "+msg+" original and calculated have differing elements for "+s); + } + baad = true; + } + } + if (baad) { + for (String s : original.keySet()) { + Source ss = original.get(s); + Source sss = calculated.get(s); + if (sss == null) { + Log.error("The file "+s+" does not exist in calculated tree of sources."); + } + } + for (String s : calculated.keySet()) { + Source ss = calculated.get(s); + Source sss = original.get(s); + if (sss == null) { + Log.error("The file "+s+" does not exist in original set of found sources."); + } + } + } + } + + /** + * Load a module from the javac state file. + */ + public Module loadModule(String l) { + Module m = Module.load(l); + modules.put(m.name(), m); + return m; + } + + /** + * Load a package from the javac state file. + */ + public Package loadPackage(Module lastModule, String l) { + Package p = Package.load(lastModule, l); + lastModule.addPackage(p); + packages.put(p.name(), p); + return p; + } + + /** + * Load a source from the javac state file. + */ + public Source loadSource(Package lastPackage, String l, boolean is_generated) { + Source s = Source.load(lastPackage, l, is_generated); + lastPackage.addSource(s); + sources.put(s.name(), s); + return s; + } + + /** + * During an incremental compile we need to copy the old javac state + * information about packages that were not recompiled. + */ + public void copyPackagesExcept(BuildState prev, Set recompiled, Set removed) { + for (String pkg : prev.packages().keySet()) { + // Do not copy recompiled or removed packages. + if (recompiled.contains(pkg) || removed.contains(pkg)) continue; + Module mnew = findModuleFromPackageName(pkg); + Package pprev = prev.packages().get(pkg); + mnew.addPackage(pprev); + // Do not forget to update the flattened data. + packages.put(pkg, pprev); + } + } +}