# HG changeset patch # User jlahoda # Date 1531737325 -7200 # Node ID a49d106e9b7cc5f0956ebd63c7a271e3ec4cf41a # Parent 4db6e8715e3520fed6c3f86f8db47922db16b0d2 8189747: JDK9 javax.lang.model.util.Elements#getTypeElement regressed 1000x in performance. Summary: Caching the results of Elements.getTypeElement/getPackageElement Reviewed-by: darcy diff -r 4db6e8715e35 -r a49d106e9b7c src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java Sun Jul 15 18:16:55 2018 +0300 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java Mon Jul 16 12:35:25 2018 +0200 @@ -26,9 +26,11 @@ package com.sun.tools.javac.model; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; @@ -184,7 +186,9 @@ } private final Set alreadyWarnedDuplicates = new HashSet<>(); + private final Map, Optional> resultCache = new HashMap<>(); + @SuppressWarnings("unchecked") private S unboundNameToSymbol(String methodName, String nameStr, Class clazz) { @@ -192,44 +196,46 @@ return nameToSymbol(syms.noModule, nameStr, clazz); } - Set found = new LinkedHashSet<>(); + return (S) resultCache.computeIfAbsent(Pair.of(methodName, nameStr), p -> { + Set found = new LinkedHashSet<>(); - for (ModuleSymbol msym : modules.allModules()) { - S sym = nameToSymbol(msym, nameStr, clazz); + for (ModuleSymbol msym : modules.allModules()) { + S sym = nameToSymbol(msym, nameStr, clazz); - if (sym == null) - continue; + if (sym == null) + continue; - if (clazz == ClassSymbol.class) { - // Always include classes - found.add(sym); - } else if (clazz == PackageSymbol.class) { - // In module mode, ignore the "spurious" empty packages that "enclose" module-specific packages. - // For example, if a module contains classes or package info in package p.q.r, it will also appear - // to have additional packages p.q and p, even though these packages have no content other - // than the subpackage. We don't want those empty packages showing up in searches for p or p.q. - if (!sym.members().isEmpty() || ((PackageSymbol) sym).package_info != null) { + if (clazz == ClassSymbol.class) { + // Always include classes found.add(sym); + } else if (clazz == PackageSymbol.class) { + // In module mode, ignore the "spurious" empty packages that "enclose" module-specific packages. + // For example, if a module contains classes or package info in package p.q.r, it will also appear + // to have additional packages p.q and p, even though these packages have no content other + // than the subpackage. We don't want those empty packages showing up in searches for p or p.q. + if (!sym.members().isEmpty() || ((PackageSymbol) sym).package_info != null) { + found.add(sym); + } } } - } - if (found.size() == 1) { - return found.iterator().next(); - } else if (found.size() > 1) { - //more than one element found, produce a note: - if (alreadyWarnedDuplicates.add(methodName + ":" + nameStr)) { - String moduleNames = found.stream() - .map(s -> s.packge().modle) - .map(m -> m.toString()) - .collect(Collectors.joining(", ")); - log.note(Notes.MultipleElements(methodName, nameStr, moduleNames)); + if (found.size() == 1) { + return Optional.of(found.iterator().next()); + } else if (found.size() > 1) { + //more than one element found, produce a note: + if (alreadyWarnedDuplicates.add(methodName + ":" + nameStr)) { + String moduleNames = found.stream() + .map(s -> s.packge().modle) + .map(m -> m.toString()) + .collect(Collectors.joining(", ")); + log.note(Notes.MultipleElements(methodName, nameStr, moduleNames)); + } + return Optional.empty(); + } else { + //not found: + return Optional.empty(); } - return null; - } else { - //not found, or more than one element found: - return null; - } + }).orElse(null); } /** @@ -787,4 +793,8 @@ throw new IllegalArgumentException(o.toString()); return clazz.cast(o); } + + public void newRound() { + resultCache.clear(); + } } diff -r 4db6e8715e35 -r a49d106e9b7c src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java Sun Jul 15 18:16:55 2018 +0300 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java Mon Jul 16 12:35:25 2018 +0200 @@ -1270,6 +1270,7 @@ modules.newRound(); types.newRound(); annotate.newRound(); + elementUtils.newRound(); boolean foundError = false; diff -r 4db6e8715e35 -r a49d106e9b7c test/langtools/tools/javac/modules/AnnotationProcessing.java --- a/test/langtools/tools/javac/modules/AnnotationProcessing.java Sun Jul 15 18:16:55 2018 +0300 +++ b/test/langtools/tools/javac/modules/AnnotationProcessing.java Mon Jul 16 12:35:25 2018 +0200 @@ -23,7 +23,7 @@ /** * @test - * @bug 8133884 8162711 8133896 8172158 8172262 8173636 8175119 + * @bug 8133884 8162711 8133896 8172158 8172262 8173636 8175119 8189747 * @summary Verify that annotation processing works. * @library /tools/lib * @modules @@ -1389,6 +1389,19 @@ .run() .writeAll(); + //from source: + new JavacTask(tb) + .options("--module-source-path", moduleSrc.toString(), + "--source-path", src.toString(), + "-processorpath", System.getProperty("test.class.path"), + "-processor", UnboundLookupGenerate.class.getName(), + "-XDrawDiagnostics") + .outdir(classes) + .files(findJavaFiles(moduleSrc)) + .run() + .writeAll() + .getOutput(OutputKind.DIRECT); + } @SupportedAnnotationTypes("*") @@ -1486,6 +1499,29 @@ } + @SupportedAnnotationTypes("*") + public static final class UnboundLookupGenerate extends AbstractProcessor { + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + if (processingEnv.getElementUtils().getTypeElement("nue.Nue") == null) { + try (Writer w = processingEnv.getFiler().createSourceFile("m1x/nue.Nue").openWriter()) { + w.write("package nue; public class Nue {}"); + } catch (IOException ex) { + throw new IllegalStateException(ex); + } + } + + return false; + } + + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latest(); + } + + } + @Test public void testWrongDefaultTargetModule(Path base) throws Exception { Path src = base.resolve("src");