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 * |
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, |
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 /** |