146 private final boolean forceSerializable;
147
148 /** true if line or local variable debug info has been requested */
149 private final boolean debugLinesOrVars;
150
151 /** dump statistics about lambda method deduplication */
152 private final boolean verboseDeduplication;
153
154 /** deduplicate lambda implementation methods */
155 private final boolean deduplicateLambdas;
156
157 /** Flag for alternate metafactories indicating the lambda object is intended to be serializable */
158 public static final int FLAG_SERIALIZABLE = LambdaMetafactory.FLAG_SERIALIZABLE;
159
160 /** Flag for alternate metafactories indicating the lambda object has multiple targets */
161 public static final int FLAG_MARKERS = LambdaMetafactory.FLAG_MARKERS;
162
163 /** Flag for alternate metafactories indicating the lambda object requires multiple bridges */
164 public static final int FLAG_BRIDGES = LambdaMetafactory.FLAG_BRIDGES;
165
166 // <editor-fold defaultstate="collapsed" desc="Instantiating">
167 protected static final Context.Key<LambdaToMethod> unlambdaKey = new Context.Key<>();
168
169 public static LambdaToMethod instance(Context context) {
170 LambdaToMethod instance = context.get(unlambdaKey);
171 if (instance == null) {
172 instance = new LambdaToMethod(context);
173 }
174 return instance;
175 }
176 private LambdaToMethod(Context context) {
177 context.put(unlambdaKey, this);
178 diags = JCDiagnostic.Factory.instance(context);
179 log = Log.instance(context);
180 lower = Lower.instance(context);
181 names = Names.instance(context);
182 syms = Symtab.instance(context);
183 rs = Resolve.instance(context);
184 operators = Operators.instance(context);
185 make = TreeMaker.instance(context);
815 MethodSymbol samSym = (MethodSymbol) types.findDescriptorSymbol(tree.target.tsym);
816 List<LoadableConstant> staticArgs = List.of(
817 typeToMethodType(samSym.type),
818 refSym.asHandle(),
819 typeToMethodType(tree.getDescriptorType(types)));
820
821 //computed indy arg types
822 ListBuffer<Type> indy_args_types = new ListBuffer<>();
823 for (JCExpression arg : indy_args) {
824 indy_args_types.append(arg.type);
825 }
826
827 //finally, compute the type of the indy call
828 MethodType indyType = new MethodType(indy_args_types.toList(),
829 tree.type,
830 List.nil(),
831 syms.methodClass);
832
833 List<Symbol> bridges = bridges(tree);
834 boolean isSerializable = isSerializable(tree);
835 boolean needsAltMetafactory = tree.target.isIntersection() ||
836 isSerializable || bridges.length() > 1;
837
838 dumpStats(tree, needsAltMetafactory, nonDedupedRefSym);
839
840 Name metafactoryName = needsAltMetafactory ?
841 names.altMetafactory : names.metafactory;
842
843 if (needsAltMetafactory) {
844 ListBuffer<Type> markers = new ListBuffer<>();
845 List<Type> targets = tree.target.isIntersection() ?
846 types.directSupertypes(tree.target) :
847 List.nil();
848 for (Type t : targets) {
849 t = types.erasure(t);
850 if (t.tsym != syms.serializableType.tsym &&
851 t.tsym != tree.type.tsym &&
852 t.tsym != syms.objectType.tsym) {
853 markers.append(t);
854 }
855 }
856 int flags = isSerializable ? FLAG_SERIALIZABLE : 0;
857 boolean hasMarkers = markers.nonEmpty();
858 boolean hasBridges = bridges.nonEmpty();
859 if (hasMarkers) {
860 flags |= FLAG_MARKERS;
861 }
862 if (hasBridges) {
863 flags |= FLAG_BRIDGES;
864 }
865 staticArgs = staticArgs.append(LoadableConstant.Int(flags));
866 if (hasMarkers) {
867 staticArgs = staticArgs.append(LoadableConstant.Int(markers.length()));
868 staticArgs = staticArgs.appendList(List.convert(LoadableConstant.class, markers.toList()));
869 }
870 if (hasBridges) {
871 staticArgs = staticArgs.append(LoadableConstant.Int(bridges.length() - 1));
872 for (Symbol s : bridges) {
873 Type s_erasure = s.erasure(types);
874 if (!types.isSameType(s_erasure, samSym.erasure(types))) {
875 staticArgs = staticArgs.append(((MethodType)s.erasure(types)));
876 }
877 }
878 }
879 if (isSerializable) {
880 int prevPos = make.pos;
881 try {
882 make.at(kInfo.clazz);
883 addDeserializationCase(refSym, tree.type, samSym,
884 tree, staticArgs, indyType);
885 } finally {
886 make.at(prevPos);
887 }
888 }
889 }
890
891 return makeIndyCall(tree, syms.lambdaMetafactory, metafactoryName, staticArgs, indyType, indy_args, samSym.name);
892 }
893
894 /**
895 * Generate an indy method call with given name, type and static bootstrap
896 * arguments types
897 */
898 private JCExpression makeIndyCall(DiagnosticPosition pos, Type site, Name bsmName,
925 return proxyCall;
926 } finally {
927 make.at(prevPos);
928 }
929 }
930
931 List<Symbol> bridges(JCFunctionalExpression tree) {
932 ClassSymbol csym =
933 types.makeFunctionalInterfaceClass(attrEnv, names.empty, tree.target, ABSTRACT | INTERFACE);
934 return types.functionalInterfaceBridges(csym);
935 }
936
937 /** does this functional expression require serialization support? */
938 boolean isSerializable(JCFunctionalExpression tree) {
939 if (forceSerializable) {
940 return true;
941 }
942 return types.asSuper(tree.target, syms.serializableType.tsym) != null;
943 }
944
945 void dumpStats(JCFunctionalExpression tree, boolean needsAltMetafactory, Symbol sym) {
946 if (dumpLambdaToMethodStats) {
947 if (tree instanceof JCLambda lambda) {
948 log.note(tree, diags.noteKey(lambda.wasMethodReference ? "mref.stat.1" : "lambda.stat",
949 needsAltMetafactory, sym));
950 } else if (tree instanceof JCMemberReference) {
951 log.note(tree, Notes.MrefStat(needsAltMetafactory, null));
952 }
953 }
954 }
955
956 /**
957 * This class retains all the useful information about a lambda expression,
958 * and acts as a translation map that is used by the main translation routines
959 * in order to adjust references to captured locals/members, etc.
960 */
961 class LambdaTranslationContext {
962
963 /** the underlying (untranslated) tree */
964 final JCFunctionalExpression tree;
|
146 private final boolean forceSerializable;
147
148 /** true if line or local variable debug info has been requested */
149 private final boolean debugLinesOrVars;
150
151 /** dump statistics about lambda method deduplication */
152 private final boolean verboseDeduplication;
153
154 /** deduplicate lambda implementation methods */
155 private final boolean deduplicateLambdas;
156
157 /** Flag for alternate metafactories indicating the lambda object is intended to be serializable */
158 public static final int FLAG_SERIALIZABLE = LambdaMetafactory.FLAG_SERIALIZABLE;
159
160 /** Flag for alternate metafactories indicating the lambda object has multiple targets */
161 public static final int FLAG_MARKERS = LambdaMetafactory.FLAG_MARKERS;
162
163 /** Flag for alternate metafactories indicating the lambda object requires multiple bridges */
164 public static final int FLAG_BRIDGES = LambdaMetafactory.FLAG_BRIDGES;
165
166 /** Flag for alternate metafactories indicating the lambda object is intended to be quotable */
167 public static final int FLAG_QUOTABLE = 1 << 3;
168
169 // <editor-fold defaultstate="collapsed" desc="Instantiating">
170 protected static final Context.Key<LambdaToMethod> unlambdaKey = new Context.Key<>();
171
172 public static LambdaToMethod instance(Context context) {
173 LambdaToMethod instance = context.get(unlambdaKey);
174 if (instance == null) {
175 instance = new LambdaToMethod(context);
176 }
177 return instance;
178 }
179 private LambdaToMethod(Context context) {
180 context.put(unlambdaKey, this);
181 diags = JCDiagnostic.Factory.instance(context);
182 log = Log.instance(context);
183 lower = Lower.instance(context);
184 names = Names.instance(context);
185 syms = Symtab.instance(context);
186 rs = Resolve.instance(context);
187 operators = Operators.instance(context);
188 make = TreeMaker.instance(context);
818 MethodSymbol samSym = (MethodSymbol) types.findDescriptorSymbol(tree.target.tsym);
819 List<LoadableConstant> staticArgs = List.of(
820 typeToMethodType(samSym.type),
821 refSym.asHandle(),
822 typeToMethodType(tree.getDescriptorType(types)));
823
824 //computed indy arg types
825 ListBuffer<Type> indy_args_types = new ListBuffer<>();
826 for (JCExpression arg : indy_args) {
827 indy_args_types.append(arg.type);
828 }
829
830 //finally, compute the type of the indy call
831 MethodType indyType = new MethodType(indy_args_types.toList(),
832 tree.type,
833 List.nil(),
834 syms.methodClass);
835
836 List<Symbol> bridges = bridges(tree);
837 boolean isSerializable = isSerializable(tree);
838 boolean isQuotable = isQuotable(tree);
839 boolean needsAltMetafactory = tree.target.isIntersection() ||
840 isSerializable || isQuotable || bridges.length() > 1;
841
842 dumpStats(tree, needsAltMetafactory, nonDedupedRefSym);
843
844 Name metafactoryName = needsAltMetafactory ?
845 names.altMetafactory : names.metafactory;
846
847 if (needsAltMetafactory) {
848 ListBuffer<Type> markers = new ListBuffer<>();
849 List<Type> targets = tree.target.isIntersection() ?
850 types.directSupertypes(tree.target) :
851 List.nil();
852 for (Type t : targets) {
853 t = types.erasure(t);
854 if (t.tsym != syms.serializableType.tsym &&
855 !types.isQuotable(t) &&
856 t.tsym != tree.type.tsym &&
857 t.tsym != syms.objectType.tsym) {
858 markers.append(t);
859 }
860 }
861 int flags = isSerializable ? FLAG_SERIALIZABLE : 0;
862 flags |= isQuotable ? FLAG_QUOTABLE : 0;
863 boolean hasMarkers = markers.nonEmpty();
864 boolean hasBridges = bridges.nonEmpty();
865 if (hasMarkers) {
866 flags |= FLAG_MARKERS;
867 }
868 if (hasBridges) {
869 flags |= FLAG_BRIDGES;
870 }
871 staticArgs = staticArgs.append(LoadableConstant.Int(flags));
872 if (hasMarkers) {
873 staticArgs = staticArgs.append(LoadableConstant.Int(markers.length()));
874 staticArgs = staticArgs.appendList(List.convert(LoadableConstant.class, markers.toList()));
875 }
876 if (hasBridges) {
877 staticArgs = staticArgs.append(LoadableConstant.Int(bridges.length() - 1));
878 for (Symbol s : bridges) {
879 Type s_erasure = s.erasure(types);
880 if (!types.isSameType(s_erasure, samSym.erasure(types))) {
881 staticArgs = staticArgs.append(((MethodType)s.erasure(types)));
882 }
883 }
884 }
885 if (isQuotable) {
886 MethodSymbol opMethodSym = tree.codeModel;
887 staticArgs = staticArgs.append(opMethodSym.asHandle());
888 }
889 if (isSerializable) {
890 int prevPos = make.pos;
891 try {
892 make.at(kInfo.clazz);
893 addDeserializationCase(refSym, tree.type, samSym,
894 tree, staticArgs, indyType);
895 } finally {
896 make.at(prevPos);
897 }
898 }
899 }
900
901 return makeIndyCall(tree, syms.lambdaMetafactory, metafactoryName, staticArgs, indyType, indy_args, samSym.name);
902 }
903
904 /**
905 * Generate an indy method call with given name, type and static bootstrap
906 * arguments types
907 */
908 private JCExpression makeIndyCall(DiagnosticPosition pos, Type site, Name bsmName,
935 return proxyCall;
936 } finally {
937 make.at(prevPos);
938 }
939 }
940
941 List<Symbol> bridges(JCFunctionalExpression tree) {
942 ClassSymbol csym =
943 types.makeFunctionalInterfaceClass(attrEnv, names.empty, tree.target, ABSTRACT | INTERFACE);
944 return types.functionalInterfaceBridges(csym);
945 }
946
947 /** does this functional expression require serialization support? */
948 boolean isSerializable(JCFunctionalExpression tree) {
949 if (forceSerializable) {
950 return true;
951 }
952 return types.asSuper(tree.target, syms.serializableType.tsym) != null;
953 }
954
955 boolean isQuotable(JCFunctionalExpression tree) {
956 return tree.codeModel != null;
957 }
958
959 void dumpStats(JCFunctionalExpression tree, boolean needsAltMetafactory, Symbol sym) {
960 if (dumpLambdaToMethodStats) {
961 if (tree instanceof JCLambda lambda) {
962 log.note(tree, diags.noteKey(lambda.wasMethodReference ? "mref.stat.1" : "lambda.stat",
963 needsAltMetafactory, sym));
964 } else if (tree instanceof JCMemberReference) {
965 log.note(tree, Notes.MrefStat(needsAltMetafactory, null));
966 }
967 }
968 }
969
970 /**
971 * This class retains all the useful information about a lambda expression,
972 * and acts as a translation map that is used by the main translation routines
973 * in order to adjust references to captured locals/members, etc.
974 */
975 class LambdaTranslationContext {
976
977 /** the underlying (untranslated) tree */
978 final JCFunctionalExpression tree;
|