Bug 521438 - [1.8] Slow compilation in project with many wildcards
generics
Change-Id: Ifed39611382762a70b71c15890ae502ec9735a5a
(cherry picked from commit 48a3a3eb7ea3d5a31b91fda5c892849f5bc403c6)
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/AnnotatableTypeSystem.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/AnnotatableTypeSystem.java
index 14489de..54d0a7a 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/AnnotatableTypeSystem.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/AnnotatableTypeSystem.java
@@ -176,7 +176,8 @@
throw new IllegalStateException();
WildcardBinding nakedType = null;
- TypeBinding[] derivedTypes = getDerivedTypes(genericType);
+ boolean useDerivedTypesOfBound = bound instanceof TypeVariableBinding || bound instanceof ParameterizedTypeBinding;
+ TypeBinding[] derivedTypes = getDerivedTypes(useDerivedTypesOfBound ? bound : genericType);
for (int i = 0, length = derivedTypes.length; i < length; i++) {
TypeBinding derivedType = derivedTypes[i];
if (derivedType == null)
@@ -200,7 +201,7 @@
WildcardBinding wildcard = new WildcardBinding(genericType, rank, bound, otherBounds, boundKind, this.environment);
wildcard.id = nakedType.id;
wildcard.setTypeAnnotations(annotations, this.isAnnotationBasedNullAnalysisEnabled);
- return (WildcardBinding) cacheDerivedType(genericType, nakedType, wildcard);
+ return (WildcardBinding) cacheDerivedType(useDerivedTypesOfBound ? bound : genericType, nakedType, wildcard);
}
public WildcardBinding getWildcard(ReferenceBinding genericType, int rank, TypeBinding bound, TypeBinding[] otherBounds, int boundKind) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeSystem.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeSystem.java
index a50f020..d63ca66 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeSystem.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeSystem.java
@@ -65,27 +65,67 @@
public final class HashedParameterizedTypes {
- private final class InternalParameterizedTypeBinding extends ParameterizedTypeBinding {
-
- public InternalParameterizedTypeBinding(ReferenceBinding genericType, TypeBinding[] typeArguments, ReferenceBinding enclosingType, LookupEnvironment environment) {
- super(genericType, typeArguments, enclosingType, environment);
+ private final class PTBKey extends ReferenceBinding { // extends ReferenceBinding so it can be used as wrapper
+ protected ReferenceBinding type; // must ensure the type is resolved
+ public TypeBinding[] arguments;
+ private ReferenceBinding enclosingType;
+ public PTBKey(ReferenceBinding type, TypeBinding[] arguments, ReferenceBinding enclosingType, LookupEnvironment environment) {
+ this.type = type;
+ this.arguments = arguments;
+ this.enclosingType = enclosingType;
+
+ if(environment != null) {
+ // only add as wrapper when used in put()
+ if (type instanceof UnresolvedReferenceBinding)
+ ((UnresolvedReferenceBinding) type).addWrapper(this, environment);
+ if (arguments != null) {
+ for (int i = 0, l = arguments.length; i < l; i++) {
+ if (arguments[i] instanceof UnresolvedReferenceBinding)
+ ((UnresolvedReferenceBinding) arguments[i]).addWrapper(this, environment);
+ if (arguments[i].hasNullTypeAnnotations())
+ this.tagBits |= TagBits.HasNullTypeAnnotation;
+ }
+ }
+ }
}
-
+ @Override
+ public void swapUnresolved(UnresolvedReferenceBinding unresolvedType, ReferenceBinding resolvedType, LookupEnvironment env) {
+ if (this.type == unresolvedType) { //$IDENTITY-COMPARISON$
+ this.type = resolvedType; // cannot be raw since being parameterized below
+ ReferenceBinding enclosing = resolvedType.enclosingType();
+ if (enclosing != null) {
+ this.enclosingType = (ReferenceBinding) env.convertUnresolvedBinaryToRawType(enclosing); // needed when binding unresolved member type
+ }
+ }
+ if (this.arguments != null) {
+ for (int i = 0, l = this.arguments.length; i < l; i++) {
+ if (this.arguments[i] == unresolvedType) { //$IDENTITY-COMPARISON$
+ this.arguments[i] = env.convertUnresolvedBinaryToRawType(resolvedType);
+ }
+ }
+ }
+ }
public boolean equals(Object other) {
- ParameterizedTypeBinding that = (ParameterizedTypeBinding) other; // homogeneous container.
+ PTBKey that = (PTBKey) other; // homogeneous container.
return this.type == that.type && this.enclosingType == that.enclosingType && Util.effectivelyEqual(this.arguments, that.arguments); //$IDENTITY-COMPARISON$
}
-
+ final int hash(TypeBinding b) {
+ if(b instanceof WildcardBinding || b instanceof TypeVariableBinding) {
+ return System.identityHashCode(b);
+ }
+ return b.hashCode();
+ }
public int hashCode() {
- int hashCode = this.type.hashCode() + 13 * (this.enclosingType != null ? this.enclosingType.hashCode() : 0);
+ final int prime=31;
+ int hashCode = 1 + hash(this.type) + (this.enclosingType != null ? hash(this.enclosingType) : 0);
for (int i = 0, length = this.arguments == null ? 0 : this.arguments.length; i < length; i++) {
- hashCode += (i + 1) * this.arguments[i].hashCode();
+ hashCode = hashCode * prime + hash(this.arguments[i]);
}
return hashCode;
}
}
- HashMap<ParameterizedTypeBinding, ParameterizedTypeBinding []> hashedParameterizedTypes = new HashMap<ParameterizedTypeBinding, ParameterizedTypeBinding[]>(256);
+ HashMap<PTBKey, ParameterizedTypeBinding []> hashedParameterizedTypes = new HashMap<>(256);
ParameterizedTypeBinding get(ReferenceBinding genericType, TypeBinding[] typeArguments, ReferenceBinding enclosingType, AnnotationBinding[] annotations) {
@@ -97,7 +137,7 @@
}
ReferenceBinding unannotatedEnclosingType = enclosingType == null ? null : (ReferenceBinding) getUnannotatedType(enclosingType);
- ParameterizedTypeBinding typeParameterization = new InternalParameterizedTypeBinding(unannotatedGenericType, unannotatedTypeArguments, unannotatedEnclosingType, TypeSystem.this.environment);
+ PTBKey key = new PTBKey(unannotatedGenericType, unannotatedTypeArguments, unannotatedEnclosingType, null);
ReferenceBinding genericTypeToMatch = unannotatedGenericType, enclosingTypeToMatch = unannotatedEnclosingType;
TypeBinding [] typeArgumentsToMatch = unannotatedTypeArguments;
if (TypeSystem.this instanceof AnnotatableTypeSystem) {
@@ -105,7 +145,7 @@
enclosingTypeToMatch = enclosingType;
typeArgumentsToMatch = typeArguments;
}
- ParameterizedTypeBinding [] parameterizedTypeBindings = this.hashedParameterizedTypes.get(typeParameterization);
+ ParameterizedTypeBinding [] parameterizedTypeBindings = this.hashedParameterizedTypes.get(key);
for (int i = 0, length = parameterizedTypeBindings == null ? 0 : parameterizedTypeBindings.length; i < length; i++) {
ParameterizedTypeBinding parameterizedType = parameterizedTypeBindings[i];
if (parameterizedType.actualType() != genericTypeToMatch) { //$IDENTITY-COMPARISON$
@@ -130,9 +170,9 @@
}
ReferenceBinding unannotatedEnclosingType = enclosingType == null ? null : (ReferenceBinding) getUnannotatedType(enclosingType);
- ParameterizedTypeBinding typeParameterization = new InternalParameterizedTypeBinding(unannotatedGenericType, unannotatedTypeArguments, unannotatedEnclosingType, TypeSystem.this.environment);
+ PTBKey key = new PTBKey(unannotatedGenericType, unannotatedTypeArguments, unannotatedEnclosingType, TypeSystem.this.environment);
- ParameterizedTypeBinding [] parameterizedTypeBindings = this.hashedParameterizedTypes.get(typeParameterization);
+ ParameterizedTypeBinding [] parameterizedTypeBindings = this.hashedParameterizedTypes.get(key);
int slot;
if (parameterizedTypeBindings == null) {
slot = 0;
@@ -142,7 +182,7 @@
System.arraycopy(parameterizedTypeBindings, 0, parameterizedTypeBindings = new ParameterizedTypeBinding[slot + 1], 0, slot);
}
parameterizedTypeBindings[slot] = parameterizedType;
- this.hashedParameterizedTypes.put(typeParameterization, parameterizedTypeBindings);
+ this.hashedParameterizedTypes.put(key, parameterizedTypeBindings);
}
}
@@ -342,7 +382,9 @@
}
TypeBinding unannotatedBound = bound == null ? null : getUnannotatedType(bound);
- TypeBinding[] derivedTypes = this.types[unannotatedGenericType.id]; // by construction, cachedInfo != null now.
+ boolean useDerivedTypesOfBound = unannotatedBound instanceof TypeVariableBinding || unannotatedBound instanceof ParameterizedTypeBinding;
+ TypeBinding[] derivedTypes = this.types[useDerivedTypesOfBound ? unannotatedBound.id :unannotatedGenericType.id]; // by construction, cachedInfo != null now.
+
int i, length = derivedTypes.length;
for (i = 0; i < length; i++) {
TypeBinding derivedType = derivedTypes[i];
@@ -358,7 +400,7 @@
if (i == length) {
System.arraycopy(derivedTypes, 0, derivedTypes = new TypeBinding[length * 2], 0, length);
- this.types[unannotatedGenericType.id] = derivedTypes;
+ this.types[useDerivedTypesOfBound ? unannotatedBound.id :unannotatedGenericType.id] = derivedTypes;
}
TypeBinding wildcard = derivedTypes[i] = new WildcardBinding(unannotatedGenericType, rank, unannotatedBound, unannotatedOtherBounds, boundKind, this.environment);