Avoid unnecessary path scanning during JSNI resolution.
This patch:
- caches the set of unresolvable types to avoid file scanning, however the
cache is cleared between generator invocations (generators may generate
one of the missing files).
- resolves inner classes by binary name, avoiding looking for files in
subdirectories.
Change-Id: Ic848d63f81400effdc92fa50f60e1e63200eed19
Bug-Link: https://github.com/gwtproject/gwt/issues/8960
diff --git a/dev/core/src/com/google/gwt/dev/javac/JdtCompiler.java b/dev/core/src/com/google/gwt/dev/javac/JdtCompiler.java
index ce6e733..b3fbfa3 100644
--- a/dev/core/src/com/google/gwt/dev/javac/JdtCompiler.java
+++ b/dev/core/src/com/google/gwt/dev/javac/JdtCompiler.java
@@ -30,6 +30,7 @@
import com.google.gwt.thirdparty.guava.common.collect.ImmutableMap;
import com.google.gwt.thirdparty.guava.common.collect.ListMultimap;
import com.google.gwt.thirdparty.guava.common.collect.Maps;
+import com.google.gwt.thirdparty.guava.common.collect.Sets;
import com.google.gwt.thirdparty.guava.common.io.BaseEncoding;
import org.eclipse.jdt.core.compiler.CharOperation;
@@ -104,7 +105,7 @@
* types are encountered during compilation. Currently used for allowing
* external tools to provide source lazily when undefined references appear.
*/
- public static interface AdditionalTypeProviderDelegate {
+ public interface AdditionalTypeProviderDelegate {
/**
* Checks for additional packages which may contain additional compilation
* units.
@@ -761,6 +762,11 @@
Maps.newHashMap();
/**
+ * Remembers types that where not found during resolution to avoid unnecessary file scanning.
+ */
+ private final Set<String> unresolvableReferences = Sets.newHashSet();
+
+ /**
* Only active during a compile.
*/
private transient CompilerImpl compilerImpl;
@@ -1035,7 +1041,15 @@
}
public ReferenceBinding resolveType(String sourceOrBinaryName) {
- return resolveType(compilerImpl.lookupEnvironment, sourceOrBinaryName);
+ if (unresolvableReferences.contains(sourceOrBinaryName)) {
+ return null;
+ }
+ ReferenceBinding typeBinding =
+ resolveType(compilerImpl.lookupEnvironment, sourceOrBinaryName);
+ if (typeBinding == null) {
+ unresolvableReferences.add(sourceOrBinaryName);
+ }
+ return typeBinding;
}
public void setAdditionalTypeProviderDelegate(AdditionalTypeProviderDelegate newDelegate) {
diff --git a/dev/core/src/com/google/gwt/dev/javac/JdtUtil.java b/dev/core/src/com/google/gwt/dev/javac/JdtUtil.java
index e1513b2..88983ea 100644
--- a/dev/core/src/com/google/gwt/dev/javac/JdtUtil.java
+++ b/dev/core/src/com/google/gwt/dev/javac/JdtUtil.java
@@ -108,9 +108,25 @@
}
public static String getSourceName(TypeBinding classBinding) {
+ return getSourceName(CharOperation.charToString(classBinding.qualifiedPackageName()),
+ CharOperation.charToString(classBinding.qualifiedSourceName()));
+ }
+
+ public static String getSourceName(String qualifiedPackageName, String qualifiedSourceName) {
return Joiner.on(".").skipNulls().join(new String[] {
- Strings.emptyToNull(CharOperation.charToString(classBinding.qualifiedPackageName())),
- CharOperation.charToString(classBinding.qualifiedSourceName())});
+ Strings.emptyToNull(qualifiedPackageName),
+ qualifiedSourceName});
+ }
+
+ public static String getBinaryName(TypeBinding classBinding) {
+ return getBinaryName(CharOperation.charToString(classBinding.qualifiedPackageName()),
+ CharOperation.charToString(classBinding.qualifiedSourceName()));
+ }
+
+ public static String getBinaryName(String qualifiedPackageName, String qualifiedSourceName) {
+ return Joiner.on(".").skipNulls().join(new String[] {
+ Strings.emptyToNull(qualifiedPackageName),
+ qualifiedSourceName.replace('.','$')});
}
public static boolean isInnerClass(ReferenceBinding binding) {
diff --git a/dev/core/src/com/google/gwt/dev/javac/JsniReferenceResolver.java b/dev/core/src/com/google/gwt/dev/javac/JsniReferenceResolver.java
index 6ea9488..ae1b897 100644
--- a/dev/core/src/com/google/gwt/dev/javac/JsniReferenceResolver.java
+++ b/dev/core/src/com/google/gwt/dev/javac/JsniReferenceResolver.java
@@ -295,9 +295,10 @@
originalName.substring(importedClassName.length()));
return;
}
- String fullClassName = declaringClassName + "." + originalName;
+ String fullClassName =
+ JdtUtil.getBinaryName(declaringClass) + "$" + originalName.replace('.', '$');
if (typeResolver.resolveType(fullClassName) != null) {
- jsniRef.setResolvedClassName(fullClassName);
+ jsniRef.setResolvedClassName(JdtUtil.getSourceName(declaringClass) + "." + originalName);
return;
}
declaringClass = declaringClass.enclosingTypeAt(1);
@@ -315,12 +316,16 @@
}
// 4. Check to see if this name is resolvable from the current package.
- String currentPackageClassName =
- String.valueOf(method.binding.declaringClass.qualifiedPackageName());
- currentPackageClassName += (currentPackageClassName.isEmpty() ? "" : ".") + originalName;
+ String currentPackageBinaryClassName =
+ JdtUtil.getBinaryName(
+ CharOperation.charToString(method.binding.declaringClass.qualifiedPackageName()),
+ originalName);
- if (typeResolver.resolveType(currentPackageClassName) != null) {
- jsniRef.setResolvedClassName(currentPackageClassName);
+ if (typeResolver.resolveType(currentPackageBinaryClassName) != null) {
+ jsniRef.setResolvedClassName(
+ JdtUtil.getSourceName(
+ CharOperation.charToString(method.binding.declaringClass.qualifiedPackageName()),
+ originalName));
return;
}
@@ -333,9 +338,9 @@
importPackages.add(JdtUtil.asDottedString(importReference.getImportName()));
}
for (String importPackage : importPackages) {
- String fullClassName = importPackage + "." + originalName;
+ String fullClassName = importPackage + "." + originalName.replace('.', '$');
if (typeResolver.resolveType(fullClassName) != null) {
- jsniRef.setResolvedClassName(fullClassName);
+ jsniRef.setResolvedClassName(importPackage + "." + originalName);
return;
}
}