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);
811 MethodSymbol samSym = (MethodSymbol) types.findDescriptorSymbol(tree.target.tsym);
812 List<LoadableConstant> staticArgs = List.of(
813 typeToMethodType(samSym.type),
814 refSym.asHandle(),
815 typeToMethodType(tree.getDescriptorType(types)));
816
817 //computed indy arg types
818 ListBuffer<Type> indy_args_types = new ListBuffer<>();
819 for (JCExpression arg : indy_args) {
820 indy_args_types.append(arg.type);
821 }
822
823 //finally, compute the type of the indy call
824 MethodType indyType = new MethodType(indy_args_types.toList(),
825 tree.type,
826 List.nil(),
827 syms.methodClass);
828
829 List<Symbol> bridges = bridges(tree);
830 boolean isSerializable = isSerializable(tree);
831 boolean needsAltMetafactory = tree.target.isIntersection() ||
832 isSerializable || bridges.length() > 1;
833
834 dumpStats(tree, needsAltMetafactory, nonDedupedRefSym);
835
836 Name metafactoryName = needsAltMetafactory ?
837 names.altMetafactory : names.metafactory;
838
839 if (needsAltMetafactory) {
840 ListBuffer<Type> markers = new ListBuffer<>();
841 List<Type> targets = tree.target.isIntersection() ?
842 types.directSupertypes(tree.target) :
843 List.nil();
844 for (Type t : targets) {
845 t = types.erasure(t);
846 if (t.tsym != syms.serializableType.tsym &&
847 t.tsym != tree.type.tsym &&
848 t.tsym != syms.objectType.tsym) {
849 markers.append(t);
850 }
851 }
852 int flags = isSerializable ? FLAG_SERIALIZABLE : 0;
853 boolean hasMarkers = markers.nonEmpty();
854 boolean hasBridges = bridges.nonEmpty();
855 if (hasMarkers) {
856 flags |= FLAG_MARKERS;
857 }
858 if (hasBridges) {
859 flags |= FLAG_BRIDGES;
860 }
861 staticArgs = staticArgs.append(LoadableConstant.Int(flags));
862 if (hasMarkers) {
863 staticArgs = staticArgs.append(LoadableConstant.Int(markers.length()));
864 staticArgs = staticArgs.appendList(List.convert(LoadableConstant.class, markers.toList()));
865 }
866 if (hasBridges) {
867 staticArgs = staticArgs.append(LoadableConstant.Int(bridges.length() - 1));
868 for (Symbol s : bridges) {
869 Type s_erasure = s.erasure(types);
870 if (!types.isSameType(s_erasure, samSym.erasure(types))) {
871 staticArgs = staticArgs.append(((MethodType)s.erasure(types)));
872 }
873 }
874 }
875 if (isSerializable) {
876 int prevPos = make.pos;
877 try {
878 make.at(kInfo.clazz);
879 addDeserializationCase(refSym, tree.type, samSym,
880 tree, staticArgs, indyType);
881 } finally {
882 make.at(prevPos);
883 }
884 }
885 }
886
887 return makeIndyCall(tree, syms.lambdaMetafactory, metafactoryName, staticArgs, indyType, indy_args, samSym.name);
888 }
889
890 /**
891 * Generate an indy method call with given name, type and static bootstrap
892 * arguments types
893 */
894 private JCExpression makeIndyCall(DiagnosticPosition pos, Type site, Name bsmName,
921 return proxyCall;
922 } finally {
923 make.at(prevPos);
924 }
925 }
926
927 List<Symbol> bridges(JCFunctionalExpression tree) {
928 ClassSymbol csym =
929 types.makeFunctionalInterfaceClass(attrEnv, names.empty, tree.target, ABSTRACT | INTERFACE);
930 return types.functionalInterfaceBridges(csym);
931 }
932
933 /** does this functional expression require serialization support? */
934 boolean isSerializable(JCFunctionalExpression tree) {
935 if (forceSerializable) {
936 return true;
937 }
938 return types.asSuper(tree.target, syms.serializableType.tsym) != null;
939 }
940
941 void dumpStats(JCFunctionalExpression tree, boolean needsAltMetafactory, Symbol sym) {
942 if (dumpLambdaToMethodStats) {
943 if (tree instanceof JCLambda lambda) {
944 log.note(tree, diags.noteKey(lambda.wasMethodReference ? "mref.stat.1" : "lambda.stat",
945 needsAltMetafactory, sym));
946 } else if (tree instanceof JCMemberReference) {
947 log.note(tree, Notes.MrefStat(needsAltMetafactory, null));
948 }
949 }
950 }
951
952 /**
953 * This class retains all the useful information about a lambda expression,
954 * and acts as a translation map that is used by the main translation routines
955 * in order to adjust references to captured locals/members, etc.
956 */
957 class LambdaTranslationContext {
958
959 /** the underlying (untranslated) tree */
960 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);
814 MethodSymbol samSym = (MethodSymbol) types.findDescriptorSymbol(tree.target.tsym);
815 List<LoadableConstant> staticArgs = List.of(
816 typeToMethodType(samSym.type),
817 refSym.asHandle(),
818 typeToMethodType(tree.getDescriptorType(types)));
819
820 //computed indy arg types
821 ListBuffer<Type> indy_args_types = new ListBuffer<>();
822 for (JCExpression arg : indy_args) {
823 indy_args_types.append(arg.type);
824 }
825
826 //finally, compute the type of the indy call
827 MethodType indyType = new MethodType(indy_args_types.toList(),
828 tree.type,
829 List.nil(),
830 syms.methodClass);
831
832 List<Symbol> bridges = bridges(tree);
833 boolean isSerializable = isSerializable(tree);
834 boolean isQuotable = isQuotable(tree);
835 boolean needsAltMetafactory = tree.target.isIntersection() ||
836 isSerializable || isQuotable || 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 !types.isQuotable(t) &&
852 t.tsym != tree.type.tsym &&
853 t.tsym != syms.objectType.tsym) {
854 markers.append(t);
855 }
856 }
857 int flags = isSerializable ? FLAG_SERIALIZABLE : 0;
858 flags |= isQuotable ? FLAG_QUOTABLE : 0;
859 boolean hasMarkers = markers.nonEmpty();
860 boolean hasBridges = bridges.nonEmpty();
861 if (hasMarkers) {
862 flags |= FLAG_MARKERS;
863 }
864 if (hasBridges) {
865 flags |= FLAG_BRIDGES;
866 }
867 staticArgs = staticArgs.append(LoadableConstant.Int(flags));
868 if (hasMarkers) {
869 staticArgs = staticArgs.append(LoadableConstant.Int(markers.length()));
870 staticArgs = staticArgs.appendList(List.convert(LoadableConstant.class, markers.toList()));
871 }
872 if (hasBridges) {
873 staticArgs = staticArgs.append(LoadableConstant.Int(bridges.length() - 1));
874 for (Symbol s : bridges) {
875 Type s_erasure = s.erasure(types);
876 if (!types.isSameType(s_erasure, samSym.erasure(types))) {
877 staticArgs = staticArgs.append(((MethodType)s.erasure(types)));
878 }
879 }
880 }
881 if (isQuotable) {
882 VarSymbol reflectField = (VarSymbol)tree.codeModel;
883 staticArgs = staticArgs.append(reflectField.asMethodHandle(true));
884 }
885 if (isSerializable) {
886 int prevPos = make.pos;
887 try {
888 make.at(kInfo.clazz);
889 addDeserializationCase(refSym, tree.type, samSym,
890 tree, staticArgs, indyType);
891 } finally {
892 make.at(prevPos);
893 }
894 }
895 }
896
897 return makeIndyCall(tree, syms.lambdaMetafactory, metafactoryName, staticArgs, indyType, indy_args, samSym.name);
898 }
899
900 /**
901 * Generate an indy method call with given name, type and static bootstrap
902 * arguments types
903 */
904 private JCExpression makeIndyCall(DiagnosticPosition pos, Type site, Name bsmName,
931 return proxyCall;
932 } finally {
933 make.at(prevPos);
934 }
935 }
936
937 List<Symbol> bridges(JCFunctionalExpression tree) {
938 ClassSymbol csym =
939 types.makeFunctionalInterfaceClass(attrEnv, names.empty, tree.target, ABSTRACT | INTERFACE);
940 return types.functionalInterfaceBridges(csym);
941 }
942
943 /** does this functional expression require serialization support? */
944 boolean isSerializable(JCFunctionalExpression tree) {
945 if (forceSerializable) {
946 return true;
947 }
948 return types.asSuper(tree.target, syms.serializableType.tsym) != null;
949 }
950
951 boolean isQuotable(JCFunctionalExpression tree) {
952 return tree.codeModel != null;
953 }
954
955 void dumpStats(JCFunctionalExpression tree, boolean needsAltMetafactory, Symbol sym) {
956 if (dumpLambdaToMethodStats) {
957 if (tree instanceof JCLambda lambda) {
958 log.note(tree, diags.noteKey(lambda.wasMethodReference ? "mref.stat.1" : "lambda.stat",
959 needsAltMetafactory, sym));
960 } else if (tree instanceof JCMemberReference) {
961 log.note(tree, Notes.MrefStat(needsAltMetafactory, null));
962 }
963 }
964 }
965
966 /**
967 * This class retains all the useful information about a lambda expression,
968 * and acts as a translation map that is used by the main translation routines
969 * in order to adjust references to captured locals/members, etc.
970 */
971 class LambdaTranslationContext {
972
973 /** the underlying (untranslated) tree */
974 final JCFunctionalExpression tree;
|