Tue, 08 Oct 2013 13:11:15 +0200
8025965: Specialized functions with same weight replace each other in TreeSet
Reviewed-by: jlaskey, sundar
src/jdk/nashorn/internal/runtime/CompiledFunction.java | file | annotate | diff | comparison | revisions |
1.1 --- a/src/jdk/nashorn/internal/runtime/CompiledFunction.java Tue Oct 08 13:02:39 2013 +0200 1.2 +++ b/src/jdk/nashorn/internal/runtime/CompiledFunction.java Tue Oct 08 13:11:15 2013 +0200 1.3 @@ -48,6 +48,7 @@ 1.4 } 1.5 1.6 CompiledFunction(final MethodType type, final MethodHandle invoker, final MethodHandle constructor) { 1.7 + assert type != null; 1.8 this.type = type; 1.9 this.invoker = invoker; 1.10 this.constructor = constructor; 1.11 @@ -80,7 +81,37 @@ 1.12 1.13 @Override 1.14 public int compareTo(final CompiledFunction o) { 1.15 - return weight() - o.weight(); 1.16 + return compareMethodTypes(type(), o.type()); 1.17 + } 1.18 + 1.19 + private static int compareMethodTypes(final MethodType ownType, final MethodType otherType) { 1.20 + // Comparable interface demands that compareTo() should only return 0 if objects are equal. 1.21 + // Failing to meet this requirement causes same weight functions to replace each other in TreeSet, 1.22 + // so we go some lengths to come up with an ordering between same weight functions, 1.23 + // first falling back to parameter count and then to hash code. 1.24 + if (ownType.equals(otherType)) { 1.25 + return 0; 1.26 + } 1.27 + 1.28 + final int diff = weight(ownType) - weight(otherType); 1.29 + if (diff != 0) { 1.30 + return diff; 1.31 + } 1.32 + if (ownType.parameterCount() != otherType.parameterCount()) { 1.33 + return ownType.parameterCount() - otherType.parameterCount(); 1.34 + } 1.35 + // We're just interested in not returning 0 here, not correct ordering 1.36 + return ownType.hashCode() - otherType.hashCode(); 1.37 + } 1.38 + 1.39 + @Override 1.40 + public boolean equals(Object obj) { 1.41 + return obj instanceof CompiledFunction && type().equals(((CompiledFunction)obj).type()); 1.42 + } 1.43 + 1.44 + @Override 1.45 + public int hashCode() { 1.46 + return type().hashCode(); 1.47 } 1.48 1.49 private int weight() { 1.50 @@ -119,14 +150,14 @@ 1.51 * a semantically equivalent linkage can be performed. 1.52 * 1.53 * @param mt type to check against 1.54 - * @return 1.55 + * @return true if types are compatible 1.56 */ 1.57 boolean typeCompatible(final MethodType mt) { 1.58 - final Class<?>[] wantedParams = mt.parameterArray(); 1.59 - final Class<?>[] existingParams = type().parameterArray(); 1.60 + final int wantedParamCount = mt.parameterCount(); 1.61 + final int existingParamCount = type.parameterCount(); 1.62 1.63 //if we are not examining a varargs type, the number of parameters must be the same 1.64 - if (wantedParams.length != existingParams.length && !isVarArgsType(mt)) { 1.65 + if (wantedParamCount != existingParamCount && !isVarArgsType(mt)) { 1.66 return false; 1.67 } 1.68 1.69 @@ -134,10 +165,10 @@ 1.70 //parameters lengths do not match is if our type ends with a varargs argument. 1.71 //then every trailing parameter in the given callsite can be folded into it, making 1.72 //us compatible (albeit slower than a direct specialization) 1.73 - final int lastParamIndex = Math.min(wantedParams.length, existingParams.length); 1.74 + final int lastParamIndex = Math.min(wantedParamCount, existingParamCount); 1.75 for (int i = 0; i < lastParamIndex; i++) { 1.76 - final Type w = Type.typeFor(wantedParams[i]); 1.77 - final Type e = Type.typeFor(existingParams[i]); 1.78 + final Type w = Type.typeFor(mt.parameterType(i)); 1.79 + final Type e = Type.typeFor(type.parameterType(i)); 1.80 1.81 //don't specialize on booleans, we have the "true" vs int 1 ambiguity in resolution 1.82 //we also currently don't support boolean as a javascript function callsite type.