changeset 1700:6acec3010e26

Enhancement: Add backed support for indy calls to alternate metafactory Serializable lambdas/method references should be created using an alternate bootstrap method.
author mcimadamore
date Fri, 14 Dec 2012 22:11:05 +0000
parents 2dd0e1a884ba
children 0a0392566a68
files src/share/classes/com/sun/tools/javac/comp/Attr.java src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java src/share/classes/com/sun/tools/javac/comp/TransTypes.java src/share/classes/com/sun/tools/javac/tree/JCTree.java src/share/classes/com/sun/tools/javac/util/Names.java
diffstat 5 files changed, 86 insertions(+), 26 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/com/sun/tools/javac/comp/Attr.java	Fri Dec 14 18:40:42 2012 +0000
+++ b/src/share/classes/com/sun/tools/javac/comp/Attr.java	Fri Dec 14 22:11:05 2012 +0000
@@ -2191,6 +2191,8 @@
                 lambdaType = fallbackDescriptorType(that);
             }
 
+            setFunctionalInfo(that, target, resultInfo.checkContext.inferenceContext());
+
             if (lambdaType.hasTag(FORALL)) {
                 //lambda expression target desc cannot be a generic method
                 resultInfo.checkContext.report(that, diags.fragment("invalid.generic.lambda.target",
@@ -2238,11 +2240,11 @@
             //if we are in a 'check' method context, and the lambda is not compatible
             //with the target-type, it will be recovered anyway in Attr.checkId
             needsRecovery = false;
-
+            
             FunctionalReturnContext funcContext = that.getBodyKind() == JCLambda.BodyKind.EXPRESSION ?
                     new ExpressionLambdaReturnContext((JCExpression)that.getBody(), resultInfo.checkContext) :
                     new FunctionalReturnContext(resultInfo.checkContext);
-
+            
             ResultInfo bodyResultInfo = lambdaType.getReturnType() == Type.recoveryType ?
                 recoveryInfo :
                 new ResultInfo(VAL, lambdaType.getReturnType(), funcContext);
@@ -2284,7 +2286,7 @@
 
     private Type checkIntersectionTarget(DiagnosticPosition pos, ResultInfo resultInfo) {
         Type pt = resultInfo.pt;
-        if (pt != Type.recoveryType && pt.isCompound()) {
+        if (pt != Type.recoveryType && pt.isCompound()) {            
             IntersectionClassType ict = (IntersectionClassType)pt;
             List<Type> bounds = ict.allInterfaces ?
                     ict.getComponents().tail :
@@ -2347,7 +2349,7 @@
          * context.
          */
         class FunctionalReturnContext extends Check.NestedCheckContext {
-
+            
             FunctionalReturnContext(CheckContext enclosingContext) {
                 super(enclosingContext);
             }
@@ -2363,9 +2365,9 @@
                 enclosingContext.report(pos, diags.fragment("incompatible.ret.type.in.lambda", details));
             }
         }
-
+        
         class ExpressionLambdaReturnContext extends FunctionalReturnContext {
-
+            
             JCExpression expr;
 
             ExpressionLambdaReturnContext(JCExpression expr, CheckContext enclosingContext) {
@@ -2481,6 +2483,7 @@
                 desc = fallbackDescriptorType(that);
             }
 
+            setFunctionalInfo(that, target, resultInfo.checkContext.inferenceContext());
             List<Type> argtypes = desc.getParameterTypes();
 
             boolean allowBoxing =
@@ -2534,7 +2537,7 @@
                     return;
                 }
             }
-
+            
             if (resultInfo.checkContext.deferredAttrContext().mode == AttrMode.CHECK) {
                 if (refSym.isStatic() && TreeInfo.isStaticSelector(that.expr, names) &&
                         exprType.getTypeArguments().nonEmpty()) {
@@ -2634,6 +2637,47 @@
             }
         }
     }
+    
+    public class FunctionalInfo {
+        
+        List<Symbol> targets = List.nil();
+        boolean isSerializable;
+        Type targetType;
+
+        FunctionalInfo(Type pt, Type targetType) {
+            if (pt.hasTag(CLASS) && pt.isCompound()) {
+                for (Type t : ((IntersectionClassType)pt).interfaces_field) {
+                    targets = targets.append(t.tsym);
+                }
+            } else {
+                targets = targets.prepend(pt.tsym);
+            }
+            isSerializable = types.asSuper(pt, syms.serializableType.tsym) != null;
+            this.targetType = targetType;
+        }
+    }
+    
+    private void setFunctionalInfo(final JCTree tree, final Type targetType, InferenceContext inferenceContext) {
+        if (inferenceContext.free(targetType)) {
+            inferenceContext.addFreeTypeListener(List.of(targetType), new FreeTypeListener() {
+                public void typesInferred(InferenceContext inferenceContext) {
+                    setFunctionalInfo(tree, inferenceContext.asInstType(targetType, types), inferenceContext);
+                }
+            });
+        } else {
+            FunctionalInfo fInfo = new FunctionalInfo(pt(), targetType);
+            switch (tree.getTag()) {
+                case LAMBDA:
+                    ((JCLambda)tree).fInfo = fInfo;
+                    break;
+                case REFERENCE:
+                    ((JCMemberReference)tree).fInfo = fInfo;
+                    break;
+                default:
+                    throw new AssertionError("Bad tree kind " + tree.getTag());
+            }
+        }
+    }
 
     public void visitParens(JCParens tree) {
         Type owntype = attribTree(tree.expr, env, resultInfo);
@@ -3581,7 +3625,7 @@
         }
         tree.type = result = t;
     }
-
+    
     public void visitTypeIntersection(JCTypeIntersection tree) {
         attribTypes(tree.bounds, env);
         tree.type = result = checkIntersection(tree, tree.bounds);
@@ -3594,7 +3638,7 @@
             typeVar.bound = checkIntersection(tree, tree.bounds);
         }
     }
-
+    
     Type checkIntersection(JCTree tree, List<JCExpression> bounds) {
         Set<Type> boundSet = new HashSet<Type>();
         if (bounds.nonEmpty()) {
@@ -3625,7 +3669,7 @@
                 }
             }
         }
-
+        
         if (bounds.length() == 0) {
             return syms.objectType;
         } else if (bounds.length() == 1) {
@@ -3668,6 +3712,7 @@
         }
     }
 
+
     public void visitWildcard(JCWildcard tree) {
         //- System.err.println("visitWildcard("+tree+");");//DEBUG
         Type type = (tree.kind.kind == BoundKind.UNBOUND)
--- a/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Fri Dec 14 18:40:42 2012 +0000
+++ b/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Fri Dec 14 22:11:05 2012 +0000
@@ -43,6 +43,7 @@
 import com.sun.tools.javac.code.Type.ClassType;
 import com.sun.tools.javac.code.Type.MethodType;
 import com.sun.tools.javac.code.Types;
+import com.sun.tools.javac.comp.Attr.FunctionalInfo;
 import com.sun.tools.javac.comp.LambdaToMethod.LambdaAnalyzer.*;
 import com.sun.tools.javac.jvm.*;
 import com.sun.tools.javac.util.*;
@@ -92,6 +93,9 @@
     /** list of translated methods
      **/
     private ListBuffer<JCTree> translatedMethodList;
+    
+    /** Flag for alternate metafactories indicating the lambda object is intended to be serializable */
+    public static final int FLAG_SERIALIZABLE = 1 << 0;
 
     // <editor-fold defaultstate="collapsed" desc="Instantiating">
     private static final Context.Key<LambdaToMethod> unlambdaKey =
@@ -253,7 +257,7 @@
         int refKind = referenceKind(sym);
 
         //convert to an invokedynamic call
-        result = makeMetaFactoryIndyCall(tree, tree.targetType, refKind, sym, indy_args);
+        result = makeMetaFactoryIndyCall(tree, tree.fInfo, refKind, sym, indy_args);
     }
 
     private JCIdent makeThis(Type type, Symbol owner) {
@@ -313,7 +317,7 @@
 
 
         //build a sam instance using an indy call to the meta-factory
-        result = makeMetaFactoryIndyCall(tree, tree.targetType, localContext.referenceKind(), refSym, indy_args);
+        result = makeMetaFactoryIndyCall(tree, tree.fInfo, localContext.referenceKind(), refSym, indy_args);
     }
 
     /**
@@ -688,16 +692,27 @@
     /**
      * Generate an indy method call to the meta factory
      */
-    private JCExpression makeMetaFactoryIndyCall(JCExpression tree, Type targetType, int refKind, Symbol refSym, List<JCExpression> indy_args) {
+    private JCExpression makeMetaFactoryIndyCall(JCExpression tree, FunctionalInfo fInfo, int refKind, Symbol refSym, List<JCExpression> indy_args) {
         //determine the static bsm args
-        Type mtype = makeFunctionalDescriptorType(targetType, true);
+        Type mtype = makeFunctionalDescriptorType(fInfo.targetType, true);
         List<Object> staticArgs = List.<Object>of(
-                new Pool.MethodHandle(ClassFile.REF_invokeInterface, types.findDescriptorSymbol(targetType.tsym)),
+                new Pool.MethodHandle(ClassFile.REF_invokeInterface, types.findDescriptorSymbol(fInfo.targetType.tsym)),
                 new Pool.MethodHandle(refKind, refSym),
                 new MethodType(mtype.getParameterTypes(),
                         mtype.getReturnType(),
                         mtype.getThrownTypes(),
                         syms.methodClass));
+        
+        boolean altMetafactory =
+                fInfo.isSerializable || fInfo.targets.tail.nonEmpty();
+        
+        if (altMetafactory) {
+            int flags = fInfo.isSerializable ? FLAG_SERIALIZABLE : 0;
+            staticArgs = staticArgs.append(flags);
+            for (Symbol t : fInfo.targets.tail) {
+                staticArgs = staticArgs.append(t);
+            }
+        }
 
         //computed indy arg types
         ListBuffer<Type> indy_args_types = ListBuffer.lb();
@@ -710,8 +725,11 @@
                 tree.type,
                 List.<Type>nil(),
                 syms.methodClass);
+        
+        Name metafactoryName = altMetafactory ?
+                names.altMetaFactory : names.metaFactory;
 
-        return makeIndyCall(tree, syms.lambdaMetafactory, names.metaFactory, staticArgs, indyType, indy_args);
+        return makeIndyCall(tree, syms.lambdaMetafactory, metafactoryName, staticArgs, indyType, indy_args);
     }
 
     /**
@@ -1318,7 +1336,7 @@
             }
 
             Type generatedLambdaSig() {
-                return types.erasure(types.findDescriptorType(tree.targetType));
+                return types.erasure(types.findDescriptorType(tree.fInfo.targetType));
             }
         }
 
@@ -1374,7 +1392,7 @@
             }
 
             Type bridgedRefSig() {
-                return types.erasure(types.findDescriptorSymbol(tree.targetType.tsym).type);
+                return types.erasure(types.findDescriptorSymbol(tree.fInfo.targetType.tsym).type);
             }
         }
     }
--- a/src/share/classes/com/sun/tools/javac/comp/TransTypes.java	Fri Dec 14 18:40:42 2012 +0000
+++ b/src/share/classes/com/sun/tools/javac/comp/TransTypes.java	Fri Dec 14 22:11:05 2012 +0000
@@ -570,9 +570,6 @@
             currentMethod = null;
             tree.params = translate(tree.params);
             tree.body = translate(tree.body, null);
-            //save non-erased target
-            tree.targetType = tree.type;
-            Assert.check(!tree.targetType.isCompound(), "Intersection-type targets not supported yet!");
             tree.type = erasure(tree.type);
             result = tree;
         }
@@ -806,9 +803,6 @@
 
     public void visitReference(JCMemberReference tree) {
         tree.expr = translate(tree.expr, null);
-        //save non-erased target
-        tree.targetType = tree.type;
-        Assert.check(!tree.targetType.isCompound(), "Intersection-type targets not supported yet!");
         tree.type = erasure(tree.type);
         result = tree;
     }
--- a/src/share/classes/com/sun/tools/javac/tree/JCTree.java	Fri Dec 14 18:40:42 2012 +0000
+++ b/src/share/classes/com/sun/tools/javac/tree/JCTree.java	Fri Dec 14 22:11:05 2012 +0000
@@ -39,6 +39,7 @@
 import com.sun.tools.javac.code.*;
 import com.sun.tools.javac.code.Scope.*;
 import com.sun.tools.javac.code.Symbol.*;
+import com.sun.tools.javac.comp.Attr.FunctionalInfo;
 import com.sun.tools.javac.util.*;
 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
 import com.sun.tools.javac.util.List;
@@ -1508,7 +1509,7 @@
 
         public List<JCVariableDecl> params;
         public JCTree body;
-        public Type targetType;
+        public FunctionalInfo fInfo;
         public boolean canCompleteNormally = true;
         public List<Type> inferredThrownTypes;
 
@@ -1820,7 +1821,7 @@
         public Name name;
         public JCExpression expr;
         public List<JCExpression> typeargs;
-        public Type targetType;
+        public FunctionalInfo fInfo;
         public Symbol sym;
         public Type varargsElement;
 
--- a/src/share/classes/com/sun/tools/javac/util/Names.java	Fri Dec 14 18:40:42 2012 +0000
+++ b/src/share/classes/com/sun/tools/javac/util/Names.java	Fri Dec 14 22:11:05 2012 +0000
@@ -173,6 +173,7 @@
     //lambda-related
     public final Name lambda;
     public final Name metaFactory;
+    public final Name altMetaFactory;
 
     public final Name.Table table;
 
@@ -306,6 +307,7 @@
         //lambda-related
         lambda = fromString("lambda");
         metaFactory = fromString("metaFactory");
+        altMetaFactory = fromString("altMetaFactory");
     }
 
     protected Name.Table createTable(Options options) {