< prev index next >

src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java

Print this page

        

@@ -23,15 +23,14 @@
  * questions.
  */
 
 package com.sun.tools.javac.comp;
 
-import com.sun.tools.javac.code.Symbol.MethodHandleSymbol;
 import com.sun.tools.javac.code.Types.SignatureGenerator.InvalidSignatureException;
-import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant;
 import com.sun.tools.javac.resources.CompilerProperties.Errors;
 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
+import com.sun.tools.javac.code.Source.Feature;
 import com.sun.tools.javac.tree.*;
 import com.sun.tools.javac.tree.JCTree.*;
 import com.sun.tools.javac.tree.JCTree.JCMemberReference.ReferenceKind;
 import com.sun.tools.javac.tree.TreeMaker;
 import com.sun.tools.javac.tree.TreeTranslator;

@@ -59,25 +58,31 @@
 import java.util.EnumMap;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Optional;
 import java.util.Set;
 import java.util.function.Consumer;
 import java.util.function.Supplier;
 
 import static com.sun.tools.javac.comp.LambdaToMethod.LambdaSymbolKind.*;
 import static com.sun.tools.javac.code.Flags.*;
 import static com.sun.tools.javac.code.Kinds.Kind.*;
 import static com.sun.tools.javac.code.TypeTag.*;
 import static com.sun.tools.javac.tree.JCTree.Tag.*;
+import static com.sun.tools.javac.jvm.Pool.DynamicMethod;
 
 import javax.lang.model.element.ElementKind;
 import javax.lang.model.type.TypeKind;
 
+import com.sun.tools.javac.code.Type.IntersectionClassType;
+import com.sun.tools.javac.code.Types.FunctionDescriptorLookupError;
 import com.sun.tools.javac.main.Option;
+import com.sun.tools.javac.code.Source;
+import com.sun.tools.javac.code.Symbol.DynamicVarSymbol;
 
 /**
  * This pass desugars lambda expressions into static methods
  *
  *  <p><b>This is NOT part of any supported API.

@@ -166,10 +171,16 @@
         debugLinesOrVars = options.isSet(Option.G)
                 || options.isSet(Option.G_CUSTOM, "lines")
                 || options.isSet(Option.G_CUSTOM, "vars");
         verboseDeduplication = options.isSet("debug.dumpLambdaToMethodDeduplication");
         deduplicateLambdas = options.getBoolean("deduplicateLambdas", true);
+        Source source = Source.instance(context);
+        // format: -XDforNonCapturingLambda=generateCondy, which is the default, or -XDforNonCapturingLambda=generateIndy
+        String condyOp = options.get("forNonCapturingLambda");
+        condyForLambda = condyOp != null ?
+                condyOp.equals("generateCondy") :
+                Feature.CONDY_FOR_LAMBDA.allowedInSource(source);
     }
     // </editor-fold>
 
     class DedupedLambda {
         private final MethodSymbol symbol;

@@ -210,11 +221,11 @@
          */
         private ListBuffer<JCTree> appendedMethodList;
 
         private Map<DedupedLambda, DedupedLambda> dedupedLambdas;
 
-        private Map<Object, DynamicMethodSymbol> dynMethSyms = new HashMap<>();
+        private Map<DynamicMethod, DynamicMethodSymbol> dynMethSyms = new HashMap<>();
 
         /**
          * list of deserialization cases
          */
         private final Map<String, ListBuffer<JCStatement>> deserializeCases;

@@ -435,12 +446,15 @@
         }
 
         //then, determine the arguments to the indy call
         List<JCExpression> indy_args = translate(syntheticInits.toList(), localContext.prev);
 
+        //build a sam instance using an indy call to the meta-factory
+        int refKind = referenceKind(sym);
+
         //convert to an invokedynamic call
-        result = makeMetafactoryIndyCall(context, sym.asHandle(), indy_args);
+        result = makeMetafactoryIndyCall(context, refKind, sym, indy_args);
     }
 
     // where
         // Reassign type annotations from the source that should really belong to the lambda
         private void apportionTypeAnnotations(JCLambda tree,

@@ -481,11 +495,11 @@
     public void visitReference(JCMemberReference tree) {
         ReferenceTranslationContext localContext = (ReferenceTranslationContext)context;
 
         //first determine the method symbol to be used to generate the sam instance
         //this is either the method reference symbol, or the bridged reference symbol
-        MethodSymbol refSym = (MethodSymbol)tree.sym;
+        Symbol refSym = tree.sym;
 
         //the qualifying expression is treated as a special captured arg
         JCExpression init;
         switch(tree.kind) {
 

@@ -515,11 +529,11 @@
 
         List<JCExpression> indy_args = init==null? List.nil() : translate(List.of(init), localContext.prev);
 
 
         //build a sam instance using an indy call to the meta-factory
-        result = makeMetafactoryIndyCall(localContext, refSym.asHandle(), indy_args);
+        result = makeMetafactoryIndyCall(localContext, localContext.referenceKind(), refSym, indy_args);
     }
 
     /**
      * Translate identifiers within a lambda to the mapped identifier
      * @param tree

@@ -758,21 +772,20 @@
     JCNewClass makeNewClass(Type ctype, List<JCExpression> args) {
         return makeNewClass(ctype, args,
                 rs.resolveConstructor(null, attrEnv, ctype, TreeInfo.types(args), List.nil()));
      }
 
-    private void addDeserializationCase(MethodHandleSymbol refSym, Type targetType, MethodSymbol samSym,
-                                        DiagnosticPosition pos, List<LoadableConstant> staticArgs, MethodType indyType) {
+    private void addDeserializationCase(int implMethodKind, Symbol refSym, Type targetType, MethodSymbol samSym,
+            DiagnosticPosition pos, List<Object> staticArgs, MethodType indyType) {
         String functionalInterfaceClass = classSig(targetType);
         String functionalInterfaceMethodName = samSym.getSimpleName().toString();
         String functionalInterfaceMethodSignature = typeSig(types.erasure(samSym.type));
         String implClass = classSig(types.erasure(refSym.owner.type));
         String implMethodName = refSym.getQualifiedName().toString();
         String implMethodSignature = typeSig(types.erasure(refSym.type));
 
-        JCExpression kindTest = eqTest(syms.intType, deserGetter("getImplMethodKind", syms.intType),
-                make.Literal(refSym.referenceKind()));
+        JCExpression kindTest = eqTest(syms.intType, deserGetter("getImplMethodKind", syms.intType), make.Literal(implMethodKind));
         ListBuffer<JCExpression> serArgs = new ListBuffer<>();
         int i = 0;
         for (Type t : indyType.getParameterTypes()) {
             List<JCExpression> indexAsArg = new ListBuffer<JCExpression>().append(make.Literal(i)).toList();
             List<Type> argTypes = new ListBuffer<Type>().append(syms.intType).toList();

@@ -785,15 +798,15 @@
                     "getFunctionalInterfaceClass", functionalInterfaceClass),
                     "getFunctionalInterfaceMethodName", functionalInterfaceMethodName),
                     "getFunctionalInterfaceMethodSignature", functionalInterfaceMethodSignature),
                     "getImplClass", implClass),
                     "getImplMethodSignature", implMethodSignature),
-                make.Return(makeIndyCall(
+                make.Return(makeDynamicCall(
                     pos,
                     syms.lambdaMetafactory,
                     names.altMetafactory,
-                    staticArgs, indyType, serArgs.toList(), samSym.name)),
+                    staticArgs, targetType, indyType, serArgs.toList(), samSym.name)),
                 null);
         ListBuffer<JCStatement> stmts = kInfo.deserializeCases.get(implMethodName);
         if (stmts == null) {
             stmts = new ListBuffer<>();
             kInfo.deserializeCases.put(implMethodName, stmts);

@@ -1100,17 +1113,17 @@
 
     /**
      * Generate an indy method call to the meta factory
      */
     private JCExpression makeMetafactoryIndyCall(TranslationContext<?> context,
-            MethodHandleSymbol refSym, List<JCExpression> indy_args) {
+            int refKind, Symbol refSym, List<JCExpression> indy_args) {
         JCFunctionalExpression tree = context.tree;
         //determine the static bsm args
         MethodSymbol samSym = (MethodSymbol) types.findDescriptorSymbol(tree.target.tsym);
-        List<LoadableConstant> staticArgs = List.of(
+        List<Object> staticArgs = List.of(
                 typeToMethodType(samSym.type),
-                ((MethodSymbol)refSym).asHandle(),
+                new Pool.MethodHandle(refKind, refSym, types),
                 typeToMethodType(tree.getDescriptorType(types)));
 
         //computed indy arg types
         ListBuffer<Type> indy_args_types = new ListBuffer<>();
         for (JCExpression arg : indy_args) {

@@ -1125,20 +1138,20 @@
 
         Name metafactoryName = context.needsAltMetafactory() ?
                 names.altMetafactory : names.metafactory;
 
         if (context.needsAltMetafactory()) {
-            ListBuffer<Type> markers = new ListBuffer<>();
+            ListBuffer<Object> markers = new ListBuffer<>();
             List<Type> targets = tree.target.isIntersection() ?
                     types.directSupertypes(tree.target) :
                     List.nil();
             for (Type t : targets) {
                 t = types.erasure(t);
                 if (t.tsym != syms.serializableType.tsym &&
                     t.tsym != tree.type.tsym &&
                     t.tsym != syms.objectType.tsym) {
-                    markers.append(t);
+                    markers.append(t.tsym);
                 }
             }
             int flags = context.isSerializable() ? FLAG_SERIALIZABLE : 0;
             boolean hasMarkers = markers.nonEmpty();
             boolean hasBridges = context.bridges.nonEmpty();

@@ -1146,75 +1159,175 @@
                 flags |= FLAG_MARKERS;
             }
             if (hasBridges) {
                 flags |= FLAG_BRIDGES;
             }
-            staticArgs = staticArgs.append(LoadableConstant.Int(flags));
+            staticArgs = staticArgs.append(flags);
             if (hasMarkers) {
-                staticArgs = staticArgs.append(LoadableConstant.Int(markers.length()));
-                staticArgs = staticArgs.appendList(List.convert(LoadableConstant.class, markers.toList()));
+                staticArgs = staticArgs.append(markers.length());
+                staticArgs = staticArgs.appendList(markers.toList());
             }
             if (hasBridges) {
-                staticArgs = staticArgs.append(LoadableConstant.Int(context.bridges.length() - 1));
+                staticArgs = staticArgs.append(context.bridges.length() - 1);
                 for (Symbol s : context.bridges) {
                     Type s_erasure = s.erasure(types);
                     if (!types.isSameType(s_erasure, samSym.erasure(types))) {
-                        staticArgs = staticArgs.append(((MethodType)s.erasure(types)));
+                        staticArgs = staticArgs.append(s.erasure(types));
                     }
                 }
             }
             if (context.isSerializable()) {
                 int prevPos = make.pos;
                 try {
                     make.at(kInfo.clazz);
-                    addDeserializationCase(refSym, tree.type, samSym,
+                    addDeserializationCase(refKind, refSym, tree.type, samSym,
                             tree, staticArgs, indyType);
                 } finally {
                     make.at(prevPos);
                 }
             }
         }
 
-        return makeIndyCall(tree, syms.lambdaMetafactory, metafactoryName, staticArgs, indyType, indy_args, samSym.name);
+        return makeDynamicCall(tree, syms.lambdaMetafactory,
+                metafactoryName, staticArgs, tree.type, indyType, indy_args, samSym.name);
+    }
+
+    private JCExpression makeDynamicCall(DiagnosticPosition pos, Type site, Name bsmName,
+            List<Object> staticArgs, Type interfaceType, MethodType indyType, List<JCExpression> indyArgs,
+            Name methName) {
+        return condyForLambda &&
+               !context.needsAltMetafactory() &&
+               indyArgs.isEmpty() ?
+               makeCondy(pos, site, bsmName, staticArgs, interfaceType, methName) :
+               makeIndyCall(pos, site, bsmName, staticArgs, indyType, indyArgs, methName);
+    }
+
+    /* this extra flag should be temporary and used as long as it's not possible to do the build
+     * due to the lack of support for condy in the current version of ASM present in the build
+     */
+    private final boolean condyForLambda;
+
+    private JCExpression makeCondy(DiagnosticPosition pos, Type site, Name bsmName,
+            List<Object> staticArgs, Type interfaceType, Name methName) {
+        int prevPos = make.pos;
+        try {
+            make.at(pos);
+            List<Type> bsm_staticArgs = List.of(syms.methodHandlesLookupType,
+                    syms.stringType,
+                    syms.classType).appendList(bsmStaticArgToTypes(staticArgs));
+
+            Symbol bsm = rs.resolveInternalMethod(pos, attrEnv, site,
+                    bsmName, bsm_staticArgs, List.nil());
+
+            DynamicVarSymbol dynSym = new DynamicVarSymbol(methName,
+                    syms.noSymbol,
+                    bsm.isStatic() ?
+                        ClassFile.REF_invokeStatic :
+                        ClassFile.REF_invokeVirtual,
+                    (MethodSymbol)bsm,
+                    interfaceType,
+                    staticArgs.toArray());
+
+            JCIdent ident = make.Ident(dynSym);
+            ident.type = interfaceType;
+
+            return ident;
+        } finally {
+            make.at(prevPos);
+        }
     }
 
     /**
      * Generate an indy method call with given name, type and static bootstrap
      * arguments types
      */
     private JCExpression makeIndyCall(DiagnosticPosition pos, Type site, Name bsmName,
-                                      List<LoadableConstant> staticArgs, MethodType indyType, List<JCExpression> indyArgs,
-                                      Name methName) {
+            List<Object> staticArgs, MethodType indyType, List<JCExpression> indyArgs,
+            Name methName) {
         int prevPos = make.pos;
         try {
             make.at(pos);
-            List<Type> bsm_staticArgs = List.of(syms.methodHandleLookupType,
-                syms.stringType,
-                syms.methodTypeType).appendList(staticArgs.map(types::constantType));
+            List<Type> bsm_staticArgs = List.of(syms.methodHandlesLookupType,
+                    syms.stringType,
+                    syms.methodTypeType).appendList(bsmStaticArgToTypes(staticArgs));
 
             Symbol bsm = rs.resolveInternalMethod(pos, attrEnv, site,
                     bsmName, bsm_staticArgs, List.nil());
 
             DynamicMethodSymbol dynSym =
                     new DynamicMethodSymbol(methName,
                                             syms.noSymbol,
-                                            ((MethodSymbol)bsm).asHandle(),
+                                            bsm.isStatic() ?
+                                                ClassFile.REF_invokeStatic :
+                                                ClassFile.REF_invokeVirtual,
+                                            (MethodSymbol)bsm,
                                             indyType,
-                                            staticArgs.toArray(new LoadableConstant[staticArgs.length()]));
+                                            staticArgs.toArray());
             JCFieldAccess qualifier = make.Select(make.QualIdent(site.tsym), bsmName);
             DynamicMethodSymbol existing = kInfo.dynMethSyms.putIfAbsent(
-                    dynSym.poolKey(types), dynSym);
+                    new DynamicMethod(dynSym, types), dynSym);
             qualifier.sym = existing != null ? existing : dynSym;
             qualifier.type = indyType.getReturnType();
 
             JCMethodInvocation proxyCall = make.Apply(List.nil(), qualifier, indyArgs);
             proxyCall.type = indyType.getReturnType();
             return proxyCall;
         } finally {
             make.at(prevPos);
         }
     }
+    //where
+    private List<Type> bsmStaticArgToTypes(List<Object> args) {
+        ListBuffer<Type> argtypes = new ListBuffer<>();
+        for (Object arg : args) {
+            argtypes.append(bsmStaticArgToType(arg));
+        }
+        return argtypes.toList();
+    }
+
+    private Type bsmStaticArgToType(Object arg) {
+        Assert.checkNonNull(arg);
+        if (arg instanceof ClassSymbol) {
+            return syms.classType;
+        } else if (arg instanceof Integer) {
+            return syms.intType;
+        } else if (arg instanceof Long) {
+            return syms.longType;
+        } else if (arg instanceof Float) {
+            return syms.floatType;
+        } else if (arg instanceof Double) {
+            return syms.doubleType;
+        } else if (arg instanceof String) {
+            return syms.stringType;
+        } else if (arg instanceof Pool.MethodHandle) {
+            return syms.methodHandleType;
+        } else if (arg instanceof MethodType) {
+            return syms.methodTypeType;
+        } else {
+            Assert.error("bad static arg " + arg.getClass());
+            return null;
+        }
+    }
+
+    /**
+     * Get the opcode associated with this method reference
+     */
+    private int referenceKind(Symbol refSym) {
+        if (refSym.isConstructor()) {
+            return ClassFile.REF_newInvokeSpecial;
+        } else {
+            if (refSym.isStatic()) {
+                return ClassFile.REF_invokeStatic;
+            } else if ((refSym.flags() & PRIVATE) != 0) {
+                return ClassFile.REF_invokeSpecial;
+            } else if (refSym.enclClass().isInterface()) {
+                return ClassFile.REF_invokeInterface;
+            } else {
+                return ClassFile.REF_invokeVirtual;
+            }
+        }
+    }
 
     // <editor-fold defaultstate="collapsed" desc="Lambda/reference analyzer">
     /**
      * This visitor collects information about translation of a lambda expression.
      * More specifically, it keeps track of the enclosing contexts and captured locals

@@ -2252,10 +2365,17 @@
             ReferenceTranslationContext(JCMemberReference tree) {
                 super(tree);
                 this.isSuper = tree.hasKind(ReferenceKind.SUPER);
             }
 
+            /**
+             * Get the opcode associated with this method reference
+             */
+            int referenceKind() {
+                return LambdaToMethod.this.referenceKind(tree.sym);
+            }
+
             boolean needsVarArgsConversion() {
                 return tree.varargsElement != null;
             }
 
             /**
< prev index next >