deduplicating lambda methods
B. Blaser
bsrbnd at gmail.com
Thu Mar 29 18:37:50 UTC 2018
On 29 March 2018 at 16:04, Maurizio Cimadamore
<maurizio.cimadamore at oracle.com> wrote:
> In other words, what I'm saying is that the key should be
> DynamicMethodSymbol, and that we should avoid creating multiple DMS for
> callsites which have the same properties. That reflects also invariant in
> javac: symbols are shared (where possible). A similar point holds for class
> literals, which are modeled as field access to a fictional symbol called
> 'class' - we should no creating that fictional symbol multiple times, there
> should be some shared Scope or similar structure somewhere which, given a
> class C, gives you back the .class symbol associated with C.
>
> Maurizio
I was expecting a simpler key but I think you're right.
Here is a patch with the full DMS as key.
All 'javac/lambda' tests are passing successfully, I'll run the others soon...
Bernard
diff -r 9925be430918
src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java
Wed Mar 28 14:24:17 2018 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java
Thu Mar 29 20:09:45 2018 +0200
@@ -226,6 +226,8 @@
private Map<DedupedLambda, DedupedLambda> dedupedLambdas;
+ private Map<DynMethSymKey, DynamicMethodSymbol> dynMethSyms =
new HashMap<>();
+
/**
* list of deserialization cases
*/
@@ -1218,9 +1220,10 @@
(MethodSymbol)bsm,
indyType,
staticArgs.toArray());
-
JCFieldAccess qualifier =
make.Select(make.QualIdent(site.tsym), bsmName);
- qualifier.sym = dynSym;
+ DynamicMethodSymbol existing = kInfo.dynMethSyms.putIfAbsent(
+ new DynMethSymKey(dynSym), dynSym);
+ qualifier.sym = existing != null ? existing : dynSym;
qualifier.type = indyType.getReturnType();
JCMethodInvocation proxyCall = make.Apply(List.nil(),
qualifier, indyArgs);
@@ -1231,6 +1234,63 @@
}
}
//where
+ private class DynMethSymKey {
+ private DynamicMethodSymbol sym;
+
+ public DynMethSymKey(DynamicMethodSymbol sym) {
+ this.sym = sym;
+ }
+
+ @Override
+ public int hashCode() {
+ return sym.name.hashCode() |
+ sym.owner.hashCode() << 8 |
+ ((Integer)sym.bsmKind).hashCode() << 16 |
+ sym.bsm.hashCode() << 24;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if ( !(o instanceof DynMethSymKey) )
+ return false;
+
+ DynMethSymKey that = (DynMethSymKey) o;
+ boolean equals = true;
+
+ // name, type, owner
+ equals &= sym.name == that.sym.name;
+ equals &= types.isSameType(sym.type, that.sym.type);
+ equals &= sym.owner == that.sym.owner;
+
+ // bsmKind, bsm
+ equals &= sym.bsmKind == that.sym.bsmKind;
+ equals &= sym.bsm == that.sym.bsm;
+
+ // staticArgs
+ if (sym.staticArgs.length != that.sym.staticArgs.length)
+ return false;
+
+ for (int i=0; i<sym.staticArgs.length; i++)
+ equals &= equalsStaticArg(sym.staticArgs[i],
that.sym.staticArgs[i]);
+
+ return equals;
+ }
+
+ private boolean equalsStaticArg(Object arg1, Object arg2) {
+ Assert.checkNonNull(arg1);
+ Assert.checkNonNull(arg2);
+ if (arg1 instanceof Number && arg2 instanceof Number
+ || arg1 instanceof String && arg2 instanceof String
+ || arg1 instanceof Pool.MethodHandle && arg2
instanceof Pool.MethodHandle) {
+ return arg1.equals(arg2);
+ } else if (arg1 instanceof MethodType && arg2 instanceof
MethodType) {
+ return types.isSameType((MethodType)arg1, (MethodType)arg2);
+ } else {
+ return false;
+ }
+ }
+ }
+
private List<Type> bsmStaticArgToTypes(List<Object> args) {
ListBuffer<Type> argtypes = new ListBuffer<>();
for (Object arg : args) {
More information about the amber-dev
mailing list