Thu, 20 Jun 2013 08:45:43 +0100
8016613: javac should avoid source 8 only analysis when compiling for source 7
Reviewed-by: jjg
Contributed-by: maurizio.cimadamore@oracle.com
ohrstrom@1504 | 1 | /* |
ohrstrom@1504 | 2 | * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. |
ohrstrom@1504 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
ohrstrom@1504 | 4 | * |
ohrstrom@1504 | 5 | * This code is free software; you can redistribute it and/or modify it |
ohrstrom@1504 | 6 | * under the terms of the GNU General Public License version 2 only, as |
ohrstrom@1504 | 7 | * published by the Free Software Foundation. Oracle designates this |
ohrstrom@1504 | 8 | * particular file as subject to the "Classpath" exception as provided |
ohrstrom@1504 | 9 | * by Oracle in the LICENSE file that accompanied this code. |
ohrstrom@1504 | 10 | * |
ohrstrom@1504 | 11 | * This code is distributed in the hope that it will be useful, but WITHOUT |
ohrstrom@1504 | 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
ohrstrom@1504 | 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
ohrstrom@1504 | 14 | * version 2 for more details (a copy is included in the LICENSE file that |
ohrstrom@1504 | 15 | * accompanied this code). |
ohrstrom@1504 | 16 | * |
ohrstrom@1504 | 17 | * You should have received a copy of the GNU General Public License version |
ohrstrom@1504 | 18 | * 2 along with this work; if not, write to the Free Software Foundation, |
ohrstrom@1504 | 19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
ohrstrom@1504 | 20 | * |
ohrstrom@1504 | 21 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
ohrstrom@1504 | 22 | * or visit www.oracle.com if you need additional information or have any |
ohrstrom@1504 | 23 | * questions. |
ohrstrom@1504 | 24 | */ |
ohrstrom@1504 | 25 | |
ohrstrom@1504 | 26 | package com.sun.tools.sjavac; |
ohrstrom@1504 | 27 | |
ohrstrom@1504 | 28 | import java.io.File; |
ohrstrom@1504 | 29 | import java.net.URI; |
ohrstrom@1504 | 30 | import java.util.ArrayList; |
ohrstrom@1504 | 31 | import java.util.Collections; |
ohrstrom@1504 | 32 | import java.util.HashMap; |
ohrstrom@1504 | 33 | import java.util.HashSet; |
ohrstrom@1504 | 34 | import java.util.Iterator; |
ohrstrom@1504 | 35 | import java.util.List; |
ohrstrom@1504 | 36 | import java.util.Map; |
ohrstrom@1504 | 37 | import java.util.Set; |
ohrstrom@1504 | 38 | |
ohrstrom@1504 | 39 | /** |
ohrstrom@1504 | 40 | * The Package class maintains meta information about a package. |
ohrstrom@1504 | 41 | * For example its sources, dependents,its pubapi and its artifacts. |
ohrstrom@1504 | 42 | * |
ohrstrom@1504 | 43 | * It might look odd that we track dependents/pubapi/artifacts on |
ohrstrom@1504 | 44 | * a package level, but it makes sense since recompiling a full package |
ohrstrom@1504 | 45 | * takes as long as recompiling a single java file in that package, |
ohrstrom@1504 | 46 | * if you take into account the startup time of the jvm. |
ohrstrom@1504 | 47 | * |
ohrstrom@1504 | 48 | * Also the dependency information will be much smaller (good for the javac_state file size) |
ohrstrom@1504 | 49 | * and it simplifies tracking artifact generation, you do not always know from which |
ohrstrom@1504 | 50 | * source a class file was generated, but you always know which package it belongs to. |
ohrstrom@1504 | 51 | * |
ohrstrom@1504 | 52 | * It is also educational to see package dependencies triggering recompilation of |
ohrstrom@1504 | 53 | * other packages. Even though the recompilation was perhaps not necessary, |
ohrstrom@1504 | 54 | * the visible recompilation of the dependent packages indicates how much circular |
ohrstrom@1504 | 55 | * dependencies your code has. |
ohrstrom@1504 | 56 | * |
ohrstrom@1504 | 57 | * <p><b>This is NOT part of any supported API. |
ohrstrom@1504 | 58 | * If you write code that depends on this, you do so at your own |
ohrstrom@1504 | 59 | * risk. This code and its internal interfaces are subject to change |
ohrstrom@1504 | 60 | * or deletion without notice.</b></p> |
ohrstrom@1504 | 61 | */ |
ohrstrom@1504 | 62 | public class Package implements Comparable<Package> { |
ohrstrom@1504 | 63 | // The module this package belongs to. (There is a legacy module with an empty string name, |
ohrstrom@1504 | 64 | // used for all legacy sources.) |
ohrstrom@1504 | 65 | private Module mod; |
ohrstrom@1504 | 66 | // Name of this package, module:pkg |
ohrstrom@1504 | 67 | // ex1 jdk.base:java.lang |
ohrstrom@1504 | 68 | // ex2 :java.lang (when in legacy mode) |
ohrstrom@1504 | 69 | private String name; |
ohrstrom@1504 | 70 | // The directory path to the package. If the package belongs to a module, |
ohrstrom@1504 | 71 | // then that module's file system name is part of the path. |
ohrstrom@1504 | 72 | private String dirname; |
ohrstrom@1504 | 73 | // This package depends on these packages. |
ohrstrom@1504 | 74 | private Set<String> dependencies = new HashSet<String>(); |
ohrstrom@1504 | 75 | // This package has the following dependents, that depend on this package. |
ohrstrom@1504 | 76 | private Set<String> dependents = new HashSet<String>(); |
ohrstrom@1504 | 77 | // This is the public api of this package. |
ohrstrom@1504 | 78 | private List<String> pubapi = new ArrayList<String>(); |
ohrstrom@1504 | 79 | // Map from source file name to Source info object. |
ohrstrom@1504 | 80 | private Map<String,Source> sources = new HashMap<String,Source>(); |
ohrstrom@1504 | 81 | // This package generated these artifacts. |
ohrstrom@1504 | 82 | private Map<String,File> artifacts = new HashMap<String,File>(); |
ohrstrom@1504 | 83 | |
ohrstrom@1504 | 84 | public Package(Module m, String n) { |
ohrstrom@1504 | 85 | int c = n.indexOf(":"); |
ohrstrom@1504 | 86 | assert(c != -1); |
ohrstrom@1504 | 87 | String mn = n.substring(0,c); |
ohrstrom@1504 | 88 | assert(m.name().equals(m.name())); |
ohrstrom@1504 | 89 | name = n; |
ohrstrom@1504 | 90 | dirname = n.replace('.', File.separatorChar); |
ohrstrom@1504 | 91 | if (m.name().length() > 0) { |
ohrstrom@1504 | 92 | // There is a module here, prefix the module dir name to the path. |
ohrstrom@1504 | 93 | dirname = m.dirname()+File.separatorChar+dirname; |
ohrstrom@1504 | 94 | } |
ohrstrom@1504 | 95 | } |
ohrstrom@1504 | 96 | |
ohrstrom@1504 | 97 | public Module mod() { return mod; } |
ohrstrom@1504 | 98 | public String name() { return name; } |
ohrstrom@1504 | 99 | public String dirname() { return dirname; } |
ohrstrom@1504 | 100 | public Map<String,Source> sources() { return sources; } |
ohrstrom@1504 | 101 | public Map<String,File> artifacts() { return artifacts; } |
ohrstrom@1504 | 102 | public List<String> pubapi() { return pubapi; } |
ohrstrom@1504 | 103 | |
ohrstrom@1504 | 104 | public Set<String> dependencies() { return dependencies; } |
ohrstrom@1504 | 105 | public Set<String> dependents() { return dependents; } |
ohrstrom@1504 | 106 | |
ohrstrom@1504 | 107 | @Override |
ohrstrom@1504 | 108 | public boolean equals(Object o) { |
ohrstrom@1504 | 109 | return (o instanceof Package) && name.equals(((Package)o).name); |
ohrstrom@1504 | 110 | } |
ohrstrom@1504 | 111 | |
ohrstrom@1504 | 112 | @Override |
ohrstrom@1504 | 113 | public int hashCode() { |
ohrstrom@1504 | 114 | return name.hashCode(); |
ohrstrom@1504 | 115 | } |
ohrstrom@1504 | 116 | |
ohrstrom@1504 | 117 | @Override |
ohrstrom@1504 | 118 | public int compareTo(Package o) { |
ohrstrom@1504 | 119 | return name.compareTo(o.name); |
ohrstrom@1504 | 120 | } |
ohrstrom@1504 | 121 | |
ohrstrom@1504 | 122 | public void addSource(Source s) { |
ohrstrom@1504 | 123 | sources.put(s.file().getPath(), s); |
ohrstrom@1504 | 124 | } |
ohrstrom@1504 | 125 | |
ohrstrom@1504 | 126 | public void addDependency(String d) { |
ohrstrom@1504 | 127 | dependencies.add(d); |
ohrstrom@1504 | 128 | } |
ohrstrom@1504 | 129 | |
ohrstrom@1504 | 130 | public void addDependent(String d) { |
ohrstrom@1504 | 131 | dependents.add(d); |
ohrstrom@1504 | 132 | } |
ohrstrom@1504 | 133 | |
ohrstrom@1504 | 134 | public void addPubapi(String p) { |
ohrstrom@1504 | 135 | pubapi.add(p); |
ohrstrom@1504 | 136 | } |
ohrstrom@1504 | 137 | |
ohrstrom@1504 | 138 | /** |
ohrstrom@1504 | 139 | * Check if we have knowledge in the javac state that |
ohrstrom@1504 | 140 | * describe the results of compiling this package before. |
ohrstrom@1504 | 141 | */ |
ohrstrom@1504 | 142 | public boolean existsInJavacState() { |
ohrstrom@1504 | 143 | return artifacts.size() > 0 || pubapi.size() > 0; |
ohrstrom@1504 | 144 | } |
ohrstrom@1504 | 145 | |
ohrstrom@1504 | 146 | public static List<String> pubapiToList(String ps) |
ohrstrom@1504 | 147 | { |
ohrstrom@1504 | 148 | String[] lines = ps.split("\n"); |
ohrstrom@1504 | 149 | List<String> r = new ArrayList<String>(); |
ohrstrom@1504 | 150 | for (String l : lines) { |
ohrstrom@1504 | 151 | r.add(l); |
ohrstrom@1504 | 152 | } |
ohrstrom@1504 | 153 | return r; |
ohrstrom@1504 | 154 | } |
ohrstrom@1504 | 155 | |
ohrstrom@1504 | 156 | public boolean hasPubapiChanged(List<String> ps) { |
ohrstrom@1504 | 157 | Iterator<String> i = ps.iterator(); |
ohrstrom@1504 | 158 | Iterator<String> j = pubapi.iterator(); |
ohrstrom@1504 | 159 | int line = 0; |
ohrstrom@1504 | 160 | while (i.hasNext() && j.hasNext()) { |
ohrstrom@1504 | 161 | String is = i.next(); |
ohrstrom@1504 | 162 | String js = j.next(); |
ohrstrom@1504 | 163 | if (!is.equals(js)) { |
ohrstrom@1504 | 164 | Log.debug("Change in pubapi for package "+name+" line "+line); |
ohrstrom@1504 | 165 | Log.debug("Old: "+js); |
ohrstrom@1504 | 166 | Log.debug("New: "+is); |
ohrstrom@1504 | 167 | return true; |
ohrstrom@1504 | 168 | } |
ohrstrom@1504 | 169 | line++; |
ohrstrom@1504 | 170 | } |
ohrstrom@1504 | 171 | if ((i.hasNext() && !j.hasNext() ) || |
ohrstrom@1504 | 172 | (!i.hasNext() && j.hasNext())) { |
ohrstrom@1504 | 173 | Log.debug("Change in pubapi for package "+name); |
ohrstrom@1504 | 174 | if (i.hasNext()) { |
ohrstrom@1504 | 175 | Log.debug("New has more lines!"); |
ohrstrom@1504 | 176 | } else { |
ohrstrom@1504 | 177 | Log.debug("Old has more lines!"); |
ohrstrom@1504 | 178 | } |
ohrstrom@1504 | 179 | return true; |
ohrstrom@1504 | 180 | } |
ohrstrom@1504 | 181 | return false; |
ohrstrom@1504 | 182 | } |
ohrstrom@1504 | 183 | |
ohrstrom@1504 | 184 | public void setPubapi(List<String> ps) { |
ohrstrom@1504 | 185 | pubapi = ps; |
ohrstrom@1504 | 186 | } |
ohrstrom@1504 | 187 | |
ohrstrom@1504 | 188 | public void setDependencies(Set<String> ds) { |
ohrstrom@1504 | 189 | dependencies = ds; |
ohrstrom@1504 | 190 | } |
ohrstrom@1504 | 191 | |
ohrstrom@1504 | 192 | public void save(StringBuilder b) { |
ohrstrom@1504 | 193 | b.append("P ").append(name).append("\n"); |
ohrstrom@1504 | 194 | Source.saveSources(sources, b); |
ohrstrom@1504 | 195 | saveDependencies(b); |
ohrstrom@1504 | 196 | savePubapi(b); |
ohrstrom@1504 | 197 | saveArtifacts(b); |
ohrstrom@1504 | 198 | } |
ohrstrom@1504 | 199 | |
ohrstrom@1504 | 200 | static public Package load(Module module, String l) { |
ohrstrom@1504 | 201 | String name = l.substring(2); |
ohrstrom@1504 | 202 | return new Package(module, name); |
ohrstrom@1504 | 203 | } |
ohrstrom@1504 | 204 | |
ohrstrom@1504 | 205 | public void loadDependency(String l) { |
ohrstrom@1504 | 206 | String n = l.substring(2); |
ohrstrom@1504 | 207 | addDependency(n); |
ohrstrom@1504 | 208 | } |
ohrstrom@1504 | 209 | |
ohrstrom@1504 | 210 | public void loadPubapi(String l) { |
ohrstrom@1504 | 211 | String pi = l.substring(2); |
ohrstrom@1504 | 212 | addPubapi(pi); |
ohrstrom@1504 | 213 | } |
ohrstrom@1504 | 214 | |
ohrstrom@1504 | 215 | public void saveDependencies(StringBuilder b) { |
ohrstrom@1504 | 216 | List<String> sorted_dependencies = new ArrayList<String>(); |
ohrstrom@1504 | 217 | for (String key : dependencies) { |
ohrstrom@1504 | 218 | sorted_dependencies.add(key); |
ohrstrom@1504 | 219 | } |
ohrstrom@1504 | 220 | Collections.sort(sorted_dependencies); |
ohrstrom@1504 | 221 | for (String a : sorted_dependencies) { |
ohrstrom@1504 | 222 | b.append("D "+a+"\n"); |
ohrstrom@1504 | 223 | } |
ohrstrom@1504 | 224 | } |
ohrstrom@1504 | 225 | |
ohrstrom@1504 | 226 | public void savePubapi(StringBuilder b) { |
ohrstrom@1504 | 227 | for (String l : pubapi) { |
ohrstrom@1504 | 228 | b.append("I "+l+"\n"); |
ohrstrom@1504 | 229 | } |
ohrstrom@1504 | 230 | } |
ohrstrom@1504 | 231 | |
ohrstrom@1504 | 232 | public static void savePackages(Map<String,Package> packages, StringBuilder b) { |
ohrstrom@1504 | 233 | List<String> sorted_packages = new ArrayList<String>(); |
ohrstrom@1504 | 234 | for (String key : packages.keySet() ) { |
ohrstrom@1504 | 235 | sorted_packages.add(key); |
ohrstrom@1504 | 236 | } |
ohrstrom@1504 | 237 | Collections.sort(sorted_packages); |
ohrstrom@1504 | 238 | for (String s : sorted_packages) { |
ohrstrom@1504 | 239 | Package p = packages.get(s); |
ohrstrom@1504 | 240 | p.save(b); |
ohrstrom@1504 | 241 | } |
ohrstrom@1504 | 242 | } |
ohrstrom@1504 | 243 | |
ohrstrom@1504 | 244 | public void addArtifact(String a) { |
ohrstrom@1504 | 245 | artifacts.put(a, new File(a)); |
ohrstrom@1504 | 246 | } |
ohrstrom@1504 | 247 | |
ohrstrom@1504 | 248 | public void addArtifact(File f) { |
ohrstrom@1504 | 249 | artifacts.put(f.getPath(), f); |
ohrstrom@1504 | 250 | } |
ohrstrom@1504 | 251 | |
ohrstrom@1504 | 252 | public void addArtifacts(Set<URI> as) { |
ohrstrom@1504 | 253 | for (URI u : as) { |
ohrstrom@1504 | 254 | addArtifact(new File(u)); |
ohrstrom@1504 | 255 | } |
ohrstrom@1504 | 256 | } |
ohrstrom@1504 | 257 | |
ohrstrom@1504 | 258 | public void setArtifacts(Set<URI> as) { |
ohrstrom@1504 | 259 | assert(!artifacts.isEmpty()); |
ohrstrom@1504 | 260 | artifacts = new HashMap<String,File>(); |
ohrstrom@1504 | 261 | addArtifacts(as); |
ohrstrom@1504 | 262 | } |
ohrstrom@1504 | 263 | |
ohrstrom@1504 | 264 | public void loadArtifact(String l) { |
ohrstrom@1504 | 265 | // Find next space after "A ". |
ohrstrom@1504 | 266 | int dp = l.indexOf(' ',2); |
ohrstrom@1504 | 267 | String fn = l.substring(2,dp); |
ohrstrom@1504 | 268 | long last_modified = Long.parseLong(l.substring(dp+1)); |
ohrstrom@1504 | 269 | File f = new File(fn); |
ohrstrom@1504 | 270 | if (f.exists() && f.lastModified() != last_modified) { |
ohrstrom@1504 | 271 | // Hmm, the artifact on disk does not have the same last modified |
ohrstrom@1504 | 272 | // timestamp as the information from the build database. |
ohrstrom@1504 | 273 | // We no longer trust the artifact on disk. Delete it. |
ohrstrom@1504 | 274 | // The smart javac wrapper will then rebuild the artifact. |
ohrstrom@1504 | 275 | Log.debug("Removing "+f.getPath()+" since its timestamp does not match javac_state."); |
ohrstrom@1504 | 276 | f.delete(); |
ohrstrom@1504 | 277 | } |
ohrstrom@1504 | 278 | artifacts.put(f.getPath(), f); |
ohrstrom@1504 | 279 | } |
ohrstrom@1504 | 280 | |
ohrstrom@1504 | 281 | public void saveArtifacts(StringBuilder b) { |
ohrstrom@1504 | 282 | List<File> sorted_artifacts = new ArrayList<File>(); |
ohrstrom@1504 | 283 | for (File f : artifacts.values()) { |
ohrstrom@1504 | 284 | sorted_artifacts.add(f); |
ohrstrom@1504 | 285 | } |
ohrstrom@1504 | 286 | Collections.sort(sorted_artifacts); |
ohrstrom@1504 | 287 | for (File f : sorted_artifacts) { |
ohrstrom@1504 | 288 | // The last modified information is only used |
ohrstrom@1504 | 289 | // to detect tampering with the output dir. |
ohrstrom@1504 | 290 | // If the outputdir has been modified, not by javac, |
ohrstrom@1504 | 291 | // then a mismatch will be detected in the last modified |
ohrstrom@1504 | 292 | // timestamps stored in the build database compared |
ohrstrom@1504 | 293 | // to the timestamps on disk and the artifact will be deleted. |
ohrstrom@1504 | 294 | |
ohrstrom@1504 | 295 | b.append("A "+f.getPath()+" "+f.lastModified()+"\n"); |
ohrstrom@1504 | 296 | } |
ohrstrom@1504 | 297 | } |
ohrstrom@1504 | 298 | |
ohrstrom@1504 | 299 | /** |
ohrstrom@1504 | 300 | * Always clean out a tainted package before it is recompiled. |
ohrstrom@1504 | 301 | */ |
ohrstrom@1504 | 302 | public void deleteArtifacts() { |
ohrstrom@1504 | 303 | for (File a : artifacts.values()) { |
ohrstrom@1504 | 304 | a.delete(); |
ohrstrom@1504 | 305 | } |
ohrstrom@1504 | 306 | } |
ohrstrom@1504 | 307 | } |