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