src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java
changeset 54568 b2ed96c35687
parent 53515 a772e65727c5
child 54846 e4049522b074
equal deleted inserted replaced
54567:224515275cf9 54568:b2ed96c35687
    23  * questions.
    23  * questions.
    24  */
    24  */
    25 
    25 
    26 package com.sun.tools.javac.comp;
    26 package com.sun.tools.javac.comp;
    27 
    27 
       
    28 import com.sun.tools.javac.code.Symbol.MethodHandleSymbol;
    28 import com.sun.tools.javac.code.Types.SignatureGenerator.InvalidSignatureException;
    29 import com.sun.tools.javac.code.Types.SignatureGenerator.InvalidSignatureException;
       
    30 import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant;
    29 import com.sun.tools.javac.resources.CompilerProperties.Errors;
    31 import com.sun.tools.javac.resources.CompilerProperties.Errors;
    30 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
    32 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
    31 import com.sun.tools.javac.tree.*;
    33 import com.sun.tools.javac.tree.*;
    32 import com.sun.tools.javac.tree.JCTree.*;
    34 import com.sun.tools.javac.tree.JCTree.*;
    33 import com.sun.tools.javac.tree.JCTree.JCMemberReference.ReferenceKind;
    35 import com.sun.tools.javac.tree.JCTree.JCMemberReference.ReferenceKind;
    57 import java.util.EnumMap;
    59 import java.util.EnumMap;
    58 import java.util.HashMap;
    60 import java.util.HashMap;
    59 import java.util.HashSet;
    61 import java.util.HashSet;
    60 import java.util.LinkedHashMap;
    62 import java.util.LinkedHashMap;
    61 import java.util.Map;
    63 import java.util.Map;
    62 import java.util.Objects;
       
    63 import java.util.Optional;
    64 import java.util.Optional;
    64 import java.util.Set;
    65 import java.util.Set;
    65 import java.util.function.Consumer;
    66 import java.util.function.Consumer;
    66 import java.util.function.Supplier;
    67 import java.util.function.Supplier;
    67 
    68 
    68 import static com.sun.tools.javac.comp.LambdaToMethod.LambdaSymbolKind.*;
    69 import static com.sun.tools.javac.comp.LambdaToMethod.LambdaSymbolKind.*;
    69 import static com.sun.tools.javac.code.Flags.*;
    70 import static com.sun.tools.javac.code.Flags.*;
    70 import static com.sun.tools.javac.code.Kinds.Kind.*;
    71 import static com.sun.tools.javac.code.Kinds.Kind.*;
    71 import static com.sun.tools.javac.code.TypeTag.*;
    72 import static com.sun.tools.javac.code.TypeTag.*;
    72 import static com.sun.tools.javac.tree.JCTree.Tag.*;
    73 import static com.sun.tools.javac.tree.JCTree.Tag.*;
    73 import static com.sun.tools.javac.jvm.Pool.DynamicMethod;
       
    74 
    74 
    75 import javax.lang.model.element.ElementKind;
    75 import javax.lang.model.element.ElementKind;
    76 import javax.lang.model.type.TypeKind;
    76 import javax.lang.model.type.TypeKind;
    77 
    77 
    78 import com.sun.tools.javac.code.Type.IntersectionClassType;
       
    79 import com.sun.tools.javac.code.Types.FunctionDescriptorLookupError;
       
    80 import com.sun.tools.javac.main.Option;
    78 import com.sun.tools.javac.main.Option;
    81 
    79 
    82 /**
    80 /**
    83  * This pass desugars lambda expressions into static methods
    81  * This pass desugars lambda expressions into static methods
    84  *
    82  *
   212          */
   210          */
   213         private ListBuffer<JCTree> appendedMethodList;
   211         private ListBuffer<JCTree> appendedMethodList;
   214 
   212 
   215         private Map<DedupedLambda, DedupedLambda> dedupedLambdas;
   213         private Map<DedupedLambda, DedupedLambda> dedupedLambdas;
   216 
   214 
   217         private Map<DynamicMethod, DynamicMethodSymbol> dynMethSyms = new HashMap<>();
   215         private Map<Object, DynamicMethodSymbol> dynMethSyms = new HashMap<>();
   218 
   216 
   219         /**
   217         /**
   220          * list of deserialization cases
   218          * list of deserialization cases
   221          */
   219          */
   222         private final Map<String, ListBuffer<JCStatement>> deserializeCases;
   220         private final Map<String, ListBuffer<JCStatement>> deserializeCases;
   437         }
   435         }
   438 
   436 
   439         //then, determine the arguments to the indy call
   437         //then, determine the arguments to the indy call
   440         List<JCExpression> indy_args = translate(syntheticInits.toList(), localContext.prev);
   438         List<JCExpression> indy_args = translate(syntheticInits.toList(), localContext.prev);
   441 
   439 
   442         //build a sam instance using an indy call to the meta-factory
       
   443         int refKind = referenceKind(sym);
       
   444 
       
   445         //convert to an invokedynamic call
   440         //convert to an invokedynamic call
   446         result = makeMetafactoryIndyCall(context, refKind, sym, indy_args);
   441         result = makeMetafactoryIndyCall(context, sym.asHandle(), indy_args);
   447     }
   442     }
   448 
   443 
   449     // where
   444     // where
   450         // Reassign type annotations from the source that should really belong to the lambda
   445         // Reassign type annotations from the source that should really belong to the lambda
   451         private void apportionTypeAnnotations(JCLambda tree,
   446         private void apportionTypeAnnotations(JCLambda tree,
   486     public void visitReference(JCMemberReference tree) {
   481     public void visitReference(JCMemberReference tree) {
   487         ReferenceTranslationContext localContext = (ReferenceTranslationContext)context;
   482         ReferenceTranslationContext localContext = (ReferenceTranslationContext)context;
   488 
   483 
   489         //first determine the method symbol to be used to generate the sam instance
   484         //first determine the method symbol to be used to generate the sam instance
   490         //this is either the method reference symbol, or the bridged reference symbol
   485         //this is either the method reference symbol, or the bridged reference symbol
   491         Symbol refSym = tree.sym;
   486         MethodSymbol refSym = (MethodSymbol)tree.sym;
   492 
   487 
   493         //the qualifying expression is treated as a special captured arg
   488         //the qualifying expression is treated as a special captured arg
   494         JCExpression init;
   489         JCExpression init;
   495         switch(tree.kind) {
   490         switch(tree.kind) {
   496 
   491 
   520 
   515 
   521         List<JCExpression> indy_args = init==null? List.nil() : translate(List.of(init), localContext.prev);
   516         List<JCExpression> indy_args = init==null? List.nil() : translate(List.of(init), localContext.prev);
   522 
   517 
   523 
   518 
   524         //build a sam instance using an indy call to the meta-factory
   519         //build a sam instance using an indy call to the meta-factory
   525         result = makeMetafactoryIndyCall(localContext, localContext.referenceKind(), refSym, indy_args);
   520         result = makeMetafactoryIndyCall(localContext, refSym.asHandle(), indy_args);
   526     }
   521     }
   527 
   522 
   528     /**
   523     /**
   529      * Translate identifiers within a lambda to the mapped identifier
   524      * Translate identifiers within a lambda to the mapped identifier
   530      * @param tree
   525      * @param tree
   763     JCNewClass makeNewClass(Type ctype, List<JCExpression> args) {
   758     JCNewClass makeNewClass(Type ctype, List<JCExpression> args) {
   764         return makeNewClass(ctype, args,
   759         return makeNewClass(ctype, args,
   765                 rs.resolveConstructor(null, attrEnv, ctype, TreeInfo.types(args), List.nil()));
   760                 rs.resolveConstructor(null, attrEnv, ctype, TreeInfo.types(args), List.nil()));
   766      }
   761      }
   767 
   762 
   768     private void addDeserializationCase(int implMethodKind, Symbol refSym, Type targetType, MethodSymbol samSym,
   763     private void addDeserializationCase(MethodHandleSymbol refSym, Type targetType, MethodSymbol samSym,
   769             DiagnosticPosition pos, List<Object> staticArgs, MethodType indyType) {
   764                                         DiagnosticPosition pos, List<LoadableConstant> staticArgs, MethodType indyType) {
   770         String functionalInterfaceClass = classSig(targetType);
   765         String functionalInterfaceClass = classSig(targetType);
   771         String functionalInterfaceMethodName = samSym.getSimpleName().toString();
   766         String functionalInterfaceMethodName = samSym.getSimpleName().toString();
   772         String functionalInterfaceMethodSignature = typeSig(types.erasure(samSym.type));
   767         String functionalInterfaceMethodSignature = typeSig(types.erasure(samSym.type));
   773         String implClass = classSig(types.erasure(refSym.owner.type));
   768         String implClass = classSig(types.erasure(refSym.owner.type));
   774         String implMethodName = refSym.getQualifiedName().toString();
   769         String implMethodName = refSym.getQualifiedName().toString();
   775         String implMethodSignature = typeSig(types.erasure(refSym.type));
   770         String implMethodSignature = typeSig(types.erasure(refSym.type));
   776 
   771 
   777         JCExpression kindTest = eqTest(syms.intType, deserGetter("getImplMethodKind", syms.intType), make.Literal(implMethodKind));
   772         JCExpression kindTest = eqTest(syms.intType, deserGetter("getImplMethodKind", syms.intType),
       
   773                 make.Literal(refSym.referenceKind()));
   778         ListBuffer<JCExpression> serArgs = new ListBuffer<>();
   774         ListBuffer<JCExpression> serArgs = new ListBuffer<>();
   779         int i = 0;
   775         int i = 0;
   780         for (Type t : indyType.getParameterTypes()) {
   776         for (Type t : indyType.getParameterTypes()) {
   781             List<JCExpression> indexAsArg = new ListBuffer<JCExpression>().append(make.Literal(i)).toList();
   777             List<JCExpression> indexAsArg = new ListBuffer<JCExpression>().append(make.Literal(i)).toList();
   782             List<Type> argTypes = new ListBuffer<Type>().append(syms.intType).toList();
   778             List<Type> argTypes = new ListBuffer<Type>().append(syms.intType).toList();
  1104 
  1100 
  1105     /**
  1101     /**
  1106      * Generate an indy method call to the meta factory
  1102      * Generate an indy method call to the meta factory
  1107      */
  1103      */
  1108     private JCExpression makeMetafactoryIndyCall(TranslationContext<?> context,
  1104     private JCExpression makeMetafactoryIndyCall(TranslationContext<?> context,
  1109             int refKind, Symbol refSym, List<JCExpression> indy_args) {
  1105             MethodHandleSymbol refSym, List<JCExpression> indy_args) {
  1110         JCFunctionalExpression tree = context.tree;
  1106         JCFunctionalExpression tree = context.tree;
  1111         //determine the static bsm args
  1107         //determine the static bsm args
  1112         MethodSymbol samSym = (MethodSymbol) types.findDescriptorSymbol(tree.target.tsym);
  1108         MethodSymbol samSym = (MethodSymbol) types.findDescriptorSymbol(tree.target.tsym);
  1113         List<Object> staticArgs = List.of(
  1109         List<LoadableConstant> staticArgs = List.of(
  1114                 typeToMethodType(samSym.type),
  1110                 typeToMethodType(samSym.type),
  1115                 new Pool.MethodHandle(refKind, refSym, types),
  1111                 ((MethodSymbol)refSym).asHandle(),
  1116                 typeToMethodType(tree.getDescriptorType(types)));
  1112                 typeToMethodType(tree.getDescriptorType(types)));
  1117 
  1113 
  1118         //computed indy arg types
  1114         //computed indy arg types
  1119         ListBuffer<Type> indy_args_types = new ListBuffer<>();
  1115         ListBuffer<Type> indy_args_types = new ListBuffer<>();
  1120         for (JCExpression arg : indy_args) {
  1116         for (JCExpression arg : indy_args) {
  1129 
  1125 
  1130         Name metafactoryName = context.needsAltMetafactory() ?
  1126         Name metafactoryName = context.needsAltMetafactory() ?
  1131                 names.altMetafactory : names.metafactory;
  1127                 names.altMetafactory : names.metafactory;
  1132 
  1128 
  1133         if (context.needsAltMetafactory()) {
  1129         if (context.needsAltMetafactory()) {
  1134             ListBuffer<Object> markers = new ListBuffer<>();
  1130             ListBuffer<Type> markers = new ListBuffer<>();
  1135             List<Type> targets = tree.target.isIntersection() ?
  1131             List<Type> targets = tree.target.isIntersection() ?
  1136                     types.directSupertypes(tree.target) :
  1132                     types.directSupertypes(tree.target) :
  1137                     List.nil();
  1133                     List.nil();
  1138             for (Type t : targets) {
  1134             for (Type t : targets) {
  1139                 t = types.erasure(t);
  1135                 t = types.erasure(t);
  1140                 if (t.tsym != syms.serializableType.tsym &&
  1136                 if (t.tsym != syms.serializableType.tsym &&
  1141                     t.tsym != tree.type.tsym &&
  1137                     t.tsym != tree.type.tsym &&
  1142                     t.tsym != syms.objectType.tsym) {
  1138                     t.tsym != syms.objectType.tsym) {
  1143                     markers.append(t.tsym);
  1139                     markers.append(t);
  1144                 }
  1140                 }
  1145             }
  1141             }
  1146             int flags = context.isSerializable() ? FLAG_SERIALIZABLE : 0;
  1142             int flags = context.isSerializable() ? FLAG_SERIALIZABLE : 0;
  1147             boolean hasMarkers = markers.nonEmpty();
  1143             boolean hasMarkers = markers.nonEmpty();
  1148             boolean hasBridges = context.bridges.nonEmpty();
  1144             boolean hasBridges = context.bridges.nonEmpty();
  1150                 flags |= FLAG_MARKERS;
  1146                 flags |= FLAG_MARKERS;
  1151             }
  1147             }
  1152             if (hasBridges) {
  1148             if (hasBridges) {
  1153                 flags |= FLAG_BRIDGES;
  1149                 flags |= FLAG_BRIDGES;
  1154             }
  1150             }
  1155             staticArgs = staticArgs.append(flags);
  1151             staticArgs = staticArgs.append(LoadableConstant.Int(flags));
  1156             if (hasMarkers) {
  1152             if (hasMarkers) {
  1157                 staticArgs = staticArgs.append(markers.length());
  1153                 staticArgs = staticArgs.append(LoadableConstant.Int(markers.length()));
  1158                 staticArgs = staticArgs.appendList(markers.toList());
  1154                 staticArgs = staticArgs.appendList(List.convert(LoadableConstant.class, markers.toList()));
  1159             }
  1155             }
  1160             if (hasBridges) {
  1156             if (hasBridges) {
  1161                 staticArgs = staticArgs.append(context.bridges.length() - 1);
  1157                 staticArgs = staticArgs.append(LoadableConstant.Int(context.bridges.length() - 1));
  1162                 for (Symbol s : context.bridges) {
  1158                 for (Symbol s : context.bridges) {
  1163                     Type s_erasure = s.erasure(types);
  1159                     Type s_erasure = s.erasure(types);
  1164                     if (!types.isSameType(s_erasure, samSym.erasure(types))) {
  1160                     if (!types.isSameType(s_erasure, samSym.erasure(types))) {
  1165                         staticArgs = staticArgs.append(s.erasure(types));
  1161                         staticArgs = staticArgs.append(((MethodType)s.erasure(types)));
  1166                     }
  1162                     }
  1167                 }
  1163                 }
  1168             }
  1164             }
  1169             if (context.isSerializable()) {
  1165             if (context.isSerializable()) {
  1170                 int prevPos = make.pos;
  1166                 int prevPos = make.pos;
  1171                 try {
  1167                 try {
  1172                     make.at(kInfo.clazz);
  1168                     make.at(kInfo.clazz);
  1173                     addDeserializationCase(refKind, refSym, tree.type, samSym,
  1169                     addDeserializationCase(refSym, tree.type, samSym,
  1174                             tree, staticArgs, indyType);
  1170                             tree, staticArgs, indyType);
  1175                 } finally {
  1171                 } finally {
  1176                     make.at(prevPos);
  1172                     make.at(prevPos);
  1177                 }
  1173                 }
  1178             }
  1174             }
  1184     /**
  1180     /**
  1185      * Generate an indy method call with given name, type and static bootstrap
  1181      * Generate an indy method call with given name, type and static bootstrap
  1186      * arguments types
  1182      * arguments types
  1187      */
  1183      */
  1188     private JCExpression makeIndyCall(DiagnosticPosition pos, Type site, Name bsmName,
  1184     private JCExpression makeIndyCall(DiagnosticPosition pos, Type site, Name bsmName,
  1189             List<Object> staticArgs, MethodType indyType, List<JCExpression> indyArgs,
  1185                                       List<LoadableConstant> staticArgs, MethodType indyType, List<JCExpression> indyArgs,
  1190             Name methName) {
  1186                                       Name methName) {
  1191         int prevPos = make.pos;
  1187         int prevPos = make.pos;
  1192         try {
  1188         try {
  1193             make.at(pos);
  1189             make.at(pos);
  1194             List<Type> bsm_staticArgs = List.of(syms.methodHandleLookupType,
  1190             List<Type> bsm_staticArgs = List.of(syms.methodHandleLookupType,
  1195                     syms.stringType,
  1191                 syms.stringType,
  1196                     syms.methodTypeType).appendList(bsmStaticArgToTypes(staticArgs));
  1192                 syms.methodTypeType).appendList(staticArgs.map(types::constantType));
  1197 
  1193 
  1198             Symbol bsm = rs.resolveInternalMethod(pos, attrEnv, site,
  1194             Symbol bsm = rs.resolveInternalMethod(pos, attrEnv, site,
  1199                     bsmName, bsm_staticArgs, List.nil());
  1195                     bsmName, bsm_staticArgs, List.nil());
  1200 
  1196 
  1201             DynamicMethodSymbol dynSym =
  1197             DynamicMethodSymbol dynSym =
  1202                     new DynamicMethodSymbol(methName,
  1198                     new DynamicMethodSymbol(methName,
  1203                                             syms.noSymbol,
  1199                                             syms.noSymbol,
  1204                                             bsm.isStatic() ?
  1200                                             ((MethodSymbol)bsm).asHandle(),
  1205                                                 ClassFile.REF_invokeStatic :
       
  1206                                                 ClassFile.REF_invokeVirtual,
       
  1207                                             (MethodSymbol)bsm,
       
  1208                                             indyType,
  1201                                             indyType,
  1209                                             staticArgs.toArray());
  1202                                             staticArgs.toArray(new LoadableConstant[staticArgs.length()]));
  1210             JCFieldAccess qualifier = make.Select(make.QualIdent(site.tsym), bsmName);
  1203             JCFieldAccess qualifier = make.Select(make.QualIdent(site.tsym), bsmName);
  1211             DynamicMethodSymbol existing = kInfo.dynMethSyms.putIfAbsent(
  1204             DynamicMethodSymbol existing = kInfo.dynMethSyms.putIfAbsent(
  1212                     new DynamicMethod(dynSym, types), dynSym);
  1205                     dynSym.poolKey(types), dynSym);
  1213             qualifier.sym = existing != null ? existing : dynSym;
  1206             qualifier.sym = existing != null ? existing : dynSym;
  1214             qualifier.type = indyType.getReturnType();
  1207             qualifier.type = indyType.getReturnType();
  1215 
  1208 
  1216             JCMethodInvocation proxyCall = make.Apply(List.nil(), qualifier, indyArgs);
  1209             JCMethodInvocation proxyCall = make.Apply(List.nil(), qualifier, indyArgs);
  1217             proxyCall.type = indyType.getReturnType();
  1210             proxyCall.type = indyType.getReturnType();
  1218             return proxyCall;
  1211             return proxyCall;
  1219         } finally {
  1212         } finally {
  1220             make.at(prevPos);
  1213             make.at(prevPos);
  1221         }
       
  1222     }
       
  1223     //where
       
  1224     private List<Type> bsmStaticArgToTypes(List<Object> args) {
       
  1225         ListBuffer<Type> argtypes = new ListBuffer<>();
       
  1226         for (Object arg : args) {
       
  1227             argtypes.append(bsmStaticArgToType(arg));
       
  1228         }
       
  1229         return argtypes.toList();
       
  1230     }
       
  1231 
       
  1232     private Type bsmStaticArgToType(Object arg) {
       
  1233         Assert.checkNonNull(arg);
       
  1234         if (arg instanceof ClassSymbol) {
       
  1235             return syms.classType;
       
  1236         } else if (arg instanceof Integer) {
       
  1237             return syms.intType;
       
  1238         } else if (arg instanceof Long) {
       
  1239             return syms.longType;
       
  1240         } else if (arg instanceof Float) {
       
  1241             return syms.floatType;
       
  1242         } else if (arg instanceof Double) {
       
  1243             return syms.doubleType;
       
  1244         } else if (arg instanceof String) {
       
  1245             return syms.stringType;
       
  1246         } else if (arg instanceof Pool.MethodHandle) {
       
  1247             return syms.methodHandleType;
       
  1248         } else if (arg instanceof MethodType) {
       
  1249             return syms.methodTypeType;
       
  1250         } else {
       
  1251             Assert.error("bad static arg " + arg.getClass());
       
  1252             return null;
       
  1253         }
       
  1254     }
       
  1255 
       
  1256     /**
       
  1257      * Get the opcode associated with this method reference
       
  1258      */
       
  1259     private int referenceKind(Symbol refSym) {
       
  1260         if (refSym.isConstructor()) {
       
  1261             return ClassFile.REF_newInvokeSpecial;
       
  1262         } else {
       
  1263             if (refSym.isStatic()) {
       
  1264                 return ClassFile.REF_invokeStatic;
       
  1265             } else if ((refSym.flags() & PRIVATE) != 0) {
       
  1266                 return ClassFile.REF_invokeSpecial;
       
  1267             } else if (refSym.enclClass().isInterface()) {
       
  1268                 return ClassFile.REF_invokeInterface;
       
  1269             } else {
       
  1270                 return ClassFile.REF_invokeVirtual;
       
  1271             }
       
  1272         }
  1214         }
  1273     }
  1215     }
  1274 
  1216 
  1275     // <editor-fold defaultstate="collapsed" desc="Lambda/reference analyzer">
  1217     // <editor-fold defaultstate="collapsed" desc="Lambda/reference analyzer">
  1276     /**
  1218     /**
  2310             ReferenceTranslationContext(JCMemberReference tree) {
  2252             ReferenceTranslationContext(JCMemberReference tree) {
  2311                 super(tree);
  2253                 super(tree);
  2312                 this.isSuper = tree.hasKind(ReferenceKind.SUPER);
  2254                 this.isSuper = tree.hasKind(ReferenceKind.SUPER);
  2313             }
  2255             }
  2314 
  2256 
  2315             /**
       
  2316              * Get the opcode associated with this method reference
       
  2317              */
       
  2318             int referenceKind() {
       
  2319                 return LambdaToMethod.this.referenceKind(tree.sym);
       
  2320             }
       
  2321 
       
  2322             boolean needsVarArgsConversion() {
  2257             boolean needsVarArgsConversion() {
  2323                 return tree.varargsElement != null;
  2258                 return tree.varargsElement != null;
  2324             }
  2259             }
  2325 
  2260 
  2326             /**
  2261             /**