< prev index next >

src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java

Print this page

 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;
< prev index next >