< prev index next >

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

Print this page




   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.tools.javac.comp;
  27 
  28 import com.sun.tools.javac.code.Symbol.MethodHandleSymbol;
  29 import com.sun.tools.javac.code.Types.SignatureGenerator.InvalidSignatureException;
  30 import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant;
  31 import com.sun.tools.javac.resources.CompilerProperties.Errors;
  32 import com.sun.tools.javac.resources.CompilerProperties.Fragments;

  33 import com.sun.tools.javac.tree.*;
  34 import com.sun.tools.javac.tree.JCTree.*;
  35 import com.sun.tools.javac.tree.JCTree.JCMemberReference.ReferenceKind;
  36 import com.sun.tools.javac.tree.TreeMaker;
  37 import com.sun.tools.javac.tree.TreeTranslator;
  38 import com.sun.tools.javac.code.Attribute;
  39 import com.sun.tools.javac.code.Scope.WriteableScope;
  40 import com.sun.tools.javac.code.Symbol;
  41 import com.sun.tools.javac.code.Symbol.ClassSymbol;
  42 import com.sun.tools.javac.code.Symbol.DynamicMethodSymbol;
  43 import com.sun.tools.javac.code.Symbol.MethodSymbol;
  44 import com.sun.tools.javac.code.Symbol.TypeSymbol;
  45 import com.sun.tools.javac.code.Symbol.VarSymbol;
  46 import com.sun.tools.javac.code.Symtab;
  47 import com.sun.tools.javac.code.Type;
  48 import com.sun.tools.javac.code.Type.MethodType;
  49 import com.sun.tools.javac.code.Type.TypeVar;
  50 import com.sun.tools.javac.code.Types;
  51 import com.sun.tools.javac.comp.LambdaToMethod.LambdaAnalyzerPreprocessor.*;
  52 import com.sun.tools.javac.comp.Lower.BasicFreeVarCollector;
  53 import com.sun.tools.javac.resources.CompilerProperties.Notes;
  54 import com.sun.tools.javac.jvm.*;
  55 import com.sun.tools.javac.util.*;
  56 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
  57 import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
  58 
  59 import java.util.EnumMap;
  60 import java.util.HashMap;
  61 import java.util.HashSet;
  62 import java.util.LinkedHashMap;
  63 import java.util.Map;

  64 import java.util.Optional;
  65 import java.util.Set;
  66 import java.util.function.Consumer;
  67 import java.util.function.Supplier;
  68 
  69 import static com.sun.tools.javac.comp.LambdaToMethod.LambdaSymbolKind.*;
  70 import static com.sun.tools.javac.code.Flags.*;
  71 import static com.sun.tools.javac.code.Kinds.Kind.*;
  72 import static com.sun.tools.javac.code.TypeTag.*;
  73 import static com.sun.tools.javac.tree.JCTree.Tag.*;

  74 
  75 import javax.lang.model.element.ElementKind;
  76 import javax.lang.model.type.TypeKind;
  77 


  78 import com.sun.tools.javac.main.Option;


  79 
  80 /**
  81  * This pass desugars lambda expressions into static methods
  82  *
  83  *  <p><b>This is NOT part of any supported API.
  84  *  If you write code that depends on this, you do so at your own risk.
  85  *  This code and its internal interfaces are subject to change or
  86  *  deletion without notice.</b>
  87  */
  88 public class LambdaToMethod extends TreeTranslator {
  89 
  90     private Attr attr;
  91     private JCDiagnostic.Factory diags;
  92     private Log log;
  93     private Lower lower;
  94     private Names names;
  95     private Symtab syms;
  96     private Resolve rs;
  97     private Operators operators;
  98     private TreeMaker make;


 151         diags = JCDiagnostic.Factory.instance(context);
 152         log = Log.instance(context);
 153         lower = Lower.instance(context);
 154         names = Names.instance(context);
 155         syms = Symtab.instance(context);
 156         rs = Resolve.instance(context);
 157         operators = Operators.instance(context);
 158         make = TreeMaker.instance(context);
 159         types = Types.instance(context);
 160         transTypes = TransTypes.instance(context);
 161         analyzer = new LambdaAnalyzerPreprocessor();
 162         Options options = Options.instance(context);
 163         dumpLambdaToMethodStats = options.isSet("debug.dumpLambdaToMethodStats");
 164         attr = Attr.instance(context);
 165         forceSerializable = options.isSet("forceSerializable");
 166         debugLinesOrVars = options.isSet(Option.G)
 167                 || options.isSet(Option.G_CUSTOM, "lines")
 168                 || options.isSet(Option.G_CUSTOM, "vars");
 169         verboseDeduplication = options.isSet("debug.dumpLambdaToMethodDeduplication");
 170         deduplicateLambdas = options.getBoolean("deduplicateLambdas", true);






 171     }
 172     // </editor-fold>
 173 
 174     class DedupedLambda {
 175         private final MethodSymbol symbol;
 176         private final JCTree tree;
 177 
 178         private int hashCode;
 179 
 180         DedupedLambda(MethodSymbol symbol, JCTree tree) {
 181             this.symbol = symbol;
 182             this.tree = tree;
 183         }
 184 
 185 
 186         @Override
 187         public int hashCode() {
 188             int hashCode = this.hashCode;
 189             if (hashCode == 0) {
 190                 this.hashCode = hashCode = TreeHasher.hash(tree, symbol.params());


 195         @Override
 196         public boolean equals(Object o) {
 197             if (!(o instanceof DedupedLambda)) {
 198                 return false;
 199             }
 200             DedupedLambda that = (DedupedLambda) o;
 201             return types.isSameType(symbol.asType(), that.symbol.asType())
 202                     && new TreeDiffer(symbol.params(), that.symbol.params()).scan(tree, that.tree);
 203         }
 204     }
 205 
 206     private class KlassInfo {
 207 
 208         /**
 209          * list of methods to append
 210          */
 211         private ListBuffer<JCTree> appendedMethodList;
 212 
 213         private Map<DedupedLambda, DedupedLambda> dedupedLambdas;
 214 
 215         private Map<Object, DynamicMethodSymbol> dynMethSyms = new HashMap<>();
 216 
 217         /**
 218          * list of deserialization cases
 219          */
 220         private final Map<String, ListBuffer<JCStatement>> deserializeCases;
 221 
 222        /**
 223          * deserialize method symbol
 224          */
 225         private final MethodSymbol deserMethodSym;
 226 
 227         /**
 228          * deserialize method parameter symbol
 229          */
 230         private final VarSymbol deserParamSym;
 231 
 232         private final JCClassDecl clazz;
 233 
 234         private KlassInfo(JCClassDecl clazz) {
 235             this.clazz = clazz;


 420                     sym.owner.enclClass().asType(),
 421                     localContext.owner.enclClass()));
 422         }
 423 
 424         //add captured locals
 425         for (Symbol fv : localContext.getSymbolMap(CAPTURED_VAR).keySet()) {
 426             if (fv != localContext.self) {
 427                 JCTree captured_local = make.Ident(fv).setType(fv.type);
 428                 syntheticInits.append((JCExpression) captured_local);
 429             }
 430         }
 431         // add captured outer this instances (used only when `this' capture itself is illegal)
 432         for (Symbol fv : localContext.getSymbolMap(CAPTURED_OUTER_THIS).keySet()) {
 433             JCTree captured_local = make.QualThis(fv.type);
 434             syntheticInits.append((JCExpression) captured_local);
 435         }
 436 
 437         //then, determine the arguments to the indy call
 438         List<JCExpression> indy_args = translate(syntheticInits.toList(), localContext.prev);
 439 



 440         //convert to an invokedynamic call
 441         result = makeMetafactoryIndyCall(context, sym.asHandle(), indy_args);
 442     }
 443 
 444     // where
 445         // Reassign type annotations from the source that should really belong to the lambda
 446         private void apportionTypeAnnotations(JCLambda tree,
 447                                               Supplier<List<Attribute.TypeCompound>> source,
 448                                               Consumer<List<Attribute.TypeCompound>> owner,
 449                                               Consumer<List<Attribute.TypeCompound>> lambda) {
 450 
 451             ListBuffer<Attribute.TypeCompound> ownerTypeAnnos = new ListBuffer<>();
 452             ListBuffer<Attribute.TypeCompound> lambdaTypeAnnos = new ListBuffer<>();
 453 
 454             for (Attribute.TypeCompound tc : source.get()) {
 455                 if (tc.position.onLambda == tree) {
 456                     lambdaTypeAnnos.append(tc);
 457                 } else {
 458                     ownerTypeAnnos.append(tc);
 459                 }
 460             }
 461             if (lambdaTypeAnnos.nonEmpty()) {


 466 
 467     private JCIdent makeThis(Type type, Symbol owner) {
 468         VarSymbol _this = new VarSymbol(PARAMETER | FINAL | SYNTHETIC,
 469                 names._this,
 470                 type,
 471                 owner);
 472         return make.Ident(_this);
 473     }
 474 
 475     /**
 476      * Translate a method reference into an invokedynamic call to the
 477      * meta-factory.
 478      * @param tree
 479      */
 480     @Override
 481     public void visitReference(JCMemberReference tree) {
 482         ReferenceTranslationContext localContext = (ReferenceTranslationContext)context;
 483 
 484         //first determine the method symbol to be used to generate the sam instance
 485         //this is either the method reference symbol, or the bridged reference symbol
 486         MethodSymbol refSym = (MethodSymbol)tree.sym;
 487 
 488         //the qualifying expression is treated as a special captured arg
 489         JCExpression init;
 490         switch(tree.kind) {
 491 
 492             case IMPLICIT_INNER:    /** Inner :: new */
 493             case SUPER:             /** super :: instMethod */
 494                 init = makeThis(
 495                     localContext.owner.enclClass().asType(),
 496                     localContext.owner.enclClass());
 497                 break;
 498 
 499             case BOUND:             /** Expr :: instMethod */
 500                 init = transTypes.coerce(attrEnv, tree.getQualifierExpression(),
 501                     types.erasure(tree.sym.owner.type));
 502                 init = attr.makeNullCheck(init);
 503                 break;
 504 
 505             case UNBOUND:           /** Type :: instMethod */
 506             case STATIC:            /** Type :: staticMethod */
 507             case TOPLEVEL:          /** Top level :: new */
 508             case ARRAY_CTOR:        /** ArrayType :: new */
 509                 init = null;
 510                 break;
 511 
 512             default:
 513                 throw new InternalError("Should not have an invalid kind");
 514         }
 515 
 516         List<JCExpression> indy_args = init==null? List.nil() : translate(List.of(init), localContext.prev);
 517 
 518 
 519         //build a sam instance using an indy call to the meta-factory
 520         result = makeMetafactoryIndyCall(localContext, refSym.asHandle(), indy_args);
 521     }
 522 
 523     /**
 524      * Translate identifiers within a lambda to the mapped identifier
 525      * @param tree
 526      */
 527     @Override
 528     public void visitIdent(JCIdent tree) {
 529         if (context == null || !analyzer.lambdaIdentSymbolFilter(tree.sym)) {
 530             super.visitIdent(tree);
 531         } else {
 532             int prevPos = make.pos;
 533             try {
 534                 make.at(tree);
 535 
 536                 LambdaTranslationContext lambdaContext = (LambdaTranslationContext) context;
 537                 JCTree ltree = lambdaContext.translate(tree);
 538                 if (ltree != null) {
 539                     result = ltree;
 540                 } else {


 586             int prevPos = make.pos;
 587             try {
 588                 make.at(tree);
 589 
 590                 LambdaTranslationContext lambdaContext = (LambdaTranslationContext) context;
 591                 tree = lambdaContext.translate(tree);
 592                 super.visitNewClass(tree);
 593             } finally {
 594                 make.at(prevPos);
 595             }
 596         }
 597     }
 598 
 599     @Override
 600     public void visitVarDef(JCVariableDecl tree) {
 601         LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context;
 602         if (context != null && lambdaContext.getSymbolMap(LOCAL_VAR).containsKey(tree.sym)) {
 603             tree.init = translate(tree.init);
 604             tree.sym = (VarSymbol) lambdaContext.getSymbolMap(LOCAL_VAR).get(tree.sym);
 605             result = tree;















 606         } else {
 607             super.visitVarDef(tree);
 608         }
 609     }
 610 
 611     // </editor-fold>
 612 
 613     // <editor-fold defaultstate="collapsed" desc="Translation helper methods">
 614 
 615     private JCBlock makeLambdaBody(JCLambda tree, JCMethodDecl lambdaMethodDecl) {
 616         return tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION ?
 617                 makeLambdaExpressionBody((JCExpression)tree.body, lambdaMethodDecl) :
 618                 makeLambdaStatementBody((JCBlock)tree.body, lambdaMethodDecl, tree.canCompleteNormally);
 619     }
 620 
 621     private JCBlock makeLambdaExpressionBody(JCExpression expr, JCMethodDecl lambdaMethodDecl) {
 622         Type restype = lambdaMethodDecl.type.getReturnType();
 623         boolean isLambda_void = expr.type.hasTag(VOID);
 624         boolean isTarget_void = restype.hasTag(VOID);
 625         boolean isTarget_Void = types.isSameType(restype, types.boxedClass(syms.voidType).type);


 728      *  @param args     The constructor arguments.
 729      *  @param cons     The constructor symbol
 730      */
 731     JCNewClass makeNewClass(Type ctype, List<JCExpression> args, Symbol cons) {
 732         JCNewClass tree = make.NewClass(null,
 733             null, make.QualIdent(ctype.tsym), args, null);
 734         tree.constructor = cons;
 735         tree.type = ctype;
 736         return tree;
 737     }
 738 
 739     /** Make an attributed class instance creation expression.
 740      *  @param ctype    The class type.
 741      *  @param args     The constructor arguments.
 742      */
 743     JCNewClass makeNewClass(Type ctype, List<JCExpression> args) {
 744         return makeNewClass(ctype, args,
 745                 rs.resolveConstructor(null, attrEnv, ctype, TreeInfo.types(args), List.nil()));
 746      }
 747 
 748     private void addDeserializationCase(MethodHandleSymbol refSym, Type targetType, MethodSymbol samSym,
 749                                         DiagnosticPosition pos, List<LoadableConstant> staticArgs, MethodType indyType) {
 750         String functionalInterfaceClass = classSig(targetType);
 751         String functionalInterfaceMethodName = samSym.getSimpleName().toString();
 752         String functionalInterfaceMethodSignature = typeSig(types.erasure(samSym.type));
 753         String implClass = classSig(types.erasure(refSym.owner.type));
 754         String implMethodName = refSym.getQualifiedName().toString();
 755         String implMethodSignature = typeSig(types.erasure(refSym.type));
 756 
 757         JCExpression kindTest = eqTest(syms.intType, deserGetter("getImplMethodKind", syms.intType),
 758                 make.Literal(refSym.referenceKind()));
 759         ListBuffer<JCExpression> serArgs = new ListBuffer<>();
 760         int i = 0;
 761         for (Type t : indyType.getParameterTypes()) {
 762             List<JCExpression> indexAsArg = new ListBuffer<JCExpression>().append(make.Literal(i)).toList();
 763             List<Type> argTypes = new ListBuffer<Type>().append(syms.intType).toList();
 764             serArgs.add(make.TypeCast(types.erasure(t), deserGetter("getCapturedArg", syms.objectType, argTypes, indexAsArg)));
 765             ++i;
 766         }
 767         JCStatement stmt = make.If(
 768                 deserTest(deserTest(deserTest(deserTest(deserTest(
 769                     kindTest,
 770                     "getFunctionalInterfaceClass", functionalInterfaceClass),
 771                     "getFunctionalInterfaceMethodName", functionalInterfaceMethodName),
 772                     "getFunctionalInterfaceMethodSignature", functionalInterfaceMethodSignature),
 773                     "getImplClass", implClass),
 774                     "getImplMethodSignature", implMethodSignature),
 775                 make.Return(makeIndyCall(
 776                     pos,
 777                     syms.lambdaMetafactory,
 778                     names.altMetafactory,
 779                     staticArgs, indyType, serArgs.toList(), samSym.name)),
 780                 null);
 781         ListBuffer<JCStatement> stmts = kInfo.deserializeCases.get(implMethodName);
 782         if (stmts == null) {
 783             stmts = new ListBuffer<>();
 784             kInfo.deserializeCases.put(implMethodName, stmts);
 785         }
 786         /****
 787         System.err.printf("+++++++++++++++++\n");
 788         System.err.printf("*functionalInterfaceClass: '%s'\n", functionalInterfaceClass);
 789         System.err.printf("*functionalInterfaceMethodName: '%s'\n", functionalInterfaceMethodName);
 790         System.err.printf("*functionalInterfaceMethodSignature: '%s'\n", functionalInterfaceMethodSignature);
 791         System.err.printf("*implMethodKind: %d\n", implMethodKind);
 792         System.err.printf("*implClass: '%s'\n", implClass);
 793         System.err.printf("*implMethodName: '%s'\n", implMethodName);
 794         System.err.printf("*implMethodSignature: '%s'\n", implMethodSignature);
 795         ****/
 796         stmts.append(stmt);
 797     }
 798 
 799     private JCExpression eqTest(Type argType, JCExpression arg1, JCExpression arg2) {


1070             params.append(make.VarDef(vsym, null));
1071             if (genArg) {
1072                 args.append(make.Ident(vsym));
1073             }
1074             return vsym;
1075         }
1076     }
1077 
1078     private MethodType typeToMethodType(Type mt) {
1079         Type type = types.erasure(mt);
1080         return new MethodType(type.getParameterTypes(),
1081                         type.getReturnType(),
1082                         type.getThrownTypes(),
1083                         syms.methodClass);
1084     }
1085 
1086     /**
1087      * Generate an indy method call to the meta factory
1088      */
1089     private JCExpression makeMetafactoryIndyCall(TranslationContext<?> context,
1090             MethodHandleSymbol refSym, List<JCExpression> indy_args) {
1091         JCFunctionalExpression tree = context.tree;
1092         //determine the static bsm args
1093         MethodSymbol samSym = (MethodSymbol) types.findDescriptorSymbol(tree.target.tsym);
1094         List<LoadableConstant> staticArgs = List.of(
1095                 typeToMethodType(samSym.type),
1096                 ((MethodSymbol)refSym).asHandle(),
1097                 typeToMethodType(tree.getDescriptorType(types)));
1098 
1099         //computed indy arg types
1100         ListBuffer<Type> indy_args_types = new ListBuffer<>();
1101         for (JCExpression arg : indy_args) {
1102             indy_args_types.append(arg.type);
1103         }
1104 
1105         //finally, compute the type of the indy call
1106         MethodType indyType = new MethodType(indy_args_types.toList(),
1107                 tree.type,
1108                 List.nil(),
1109                 syms.methodClass);
1110 
1111         Name metafactoryName = context.needsAltMetafactory() ?
1112                 names.altMetafactory : names.metafactory;
1113 
1114         if (context.needsAltMetafactory()) {
1115             ListBuffer<Type> markers = new ListBuffer<>();
1116             List<Type> targets = tree.target.isIntersection() ?
1117                     types.directSupertypes(tree.target) :
1118                     List.nil();
1119             for (Type t : targets) {
1120                 t = types.erasure(t);
1121                 if (t.tsym != syms.serializableType.tsym &&
1122                     t.tsym != tree.type.tsym &&
1123                     t.tsym != syms.objectType.tsym) {
1124                     markers.append(t);
1125                 }
1126             }
1127             int flags = context.isSerializable() ? FLAG_SERIALIZABLE : 0;
1128             boolean hasMarkers = markers.nonEmpty();
1129             boolean hasBridges = context.bridges.nonEmpty();
1130             if (hasMarkers) {
1131                 flags |= FLAG_MARKERS;
1132             }
1133             if (hasBridges) {
1134                 flags |= FLAG_BRIDGES;
1135             }
1136             staticArgs = staticArgs.append(LoadableConstant.Int(flags));
1137             if (hasMarkers) {
1138                 staticArgs = staticArgs.append(LoadableConstant.Int(markers.length()));
1139                 staticArgs = staticArgs.appendList(List.convert(LoadableConstant.class, markers.toList()));
1140             }
1141             if (hasBridges) {
1142                 staticArgs = staticArgs.append(LoadableConstant.Int(context.bridges.length() - 1));
1143                 for (Symbol s : context.bridges) {
1144                     Type s_erasure = s.erasure(types);
1145                     if (!types.isSameType(s_erasure, samSym.erasure(types))) {
1146                         staticArgs = staticArgs.append(((MethodType)s.erasure(types)));
1147                     }
1148                 }
1149             }
1150             if (context.isSerializable()) {
1151                 int prevPos = make.pos;
1152                 try {
1153                     make.at(kInfo.clazz);
1154                     addDeserializationCase(refSym, tree.type, samSym,
1155                             tree, staticArgs, indyType);
1156                 } finally {
1157                     make.at(prevPos);
1158                 }
1159             }
1160         }
1161 
1162         return makeIndyCall(tree, syms.lambdaMetafactory, metafactoryName, staticArgs, indyType, indy_args, samSym.name);














































1163     }
1164 
1165     /**
1166      * Generate an indy method call with given name, type and static bootstrap
1167      * arguments types
1168      */
1169     private JCExpression makeIndyCall(DiagnosticPosition pos, Type site, Name bsmName,
1170                                       List<LoadableConstant> staticArgs, MethodType indyType, List<JCExpression> indyArgs,
1171                                       Name methName) {
1172         int prevPos = make.pos;
1173         try {
1174             make.at(pos);
1175             List<Type> bsm_staticArgs = List.of(syms.methodHandleLookupType,
1176                 syms.stringType,
1177                 syms.methodTypeType).appendList(staticArgs.map(types::constantType));
1178 
1179             Symbol bsm = rs.resolveInternalMethod(pos, attrEnv, site,
1180                     bsmName, bsm_staticArgs, List.nil());
1181 
1182             DynamicMethodSymbol dynSym =
1183                     new DynamicMethodSymbol(methName,
1184                                             syms.noSymbol,
1185                                             ((MethodSymbol)bsm).asHandle(),



1186                                             indyType,
1187                                             staticArgs.toArray(new LoadableConstant[staticArgs.length()]));
1188             JCFieldAccess qualifier = make.Select(make.QualIdent(site.tsym), bsmName);
1189             DynamicMethodSymbol existing = kInfo.dynMethSyms.putIfAbsent(
1190                     dynSym.poolKey(types), dynSym);
1191             qualifier.sym = existing != null ? existing : dynSym;
1192             qualifier.type = indyType.getReturnType();
1193 
1194             JCMethodInvocation proxyCall = make.Apply(List.nil(), qualifier, indyArgs);
1195             proxyCall.type = indyType.getReturnType();
1196             return proxyCall;
1197         } finally {
1198             make.at(prevPos);
1199         }
1200     }



















































1201 
1202     // <editor-fold defaultstate="collapsed" desc="Lambda/reference analyzer">
1203     /**
1204      * This visitor collects information about translation of a lambda expression.
1205      * More specifically, it keeps track of the enclosing contexts and captured locals
1206      * accessed by the lambda being translated (as well as other useful info).
1207      * It also translates away problems for LambdaToMethod.
1208      */
1209     class LambdaAnalyzerPreprocessor extends TreeTranslator {
1210 
1211         /** the frame stack - used to reconstruct translation info about enclosing scopes */
1212         private List<Frame> frameStack;
1213 
1214         /**
1215          * keep the count of lambda expression (used to generate unambiguous
1216          * names)
1217          */
1218         private int lambdaCount = 0;
1219 
1220         /**


1540                     }
1541                     localContext = localContext.prev;
1542                 }
1543             }
1544             super.visitSelect(tree);
1545         }
1546 
1547         @Override
1548         public void visitVarDef(JCVariableDecl tree) {
1549             TranslationContext<?> context = context();
1550             LambdaTranslationContext ltc = (context != null && context instanceof LambdaTranslationContext)?
1551                     (LambdaTranslationContext)context :
1552                     null;
1553             if (ltc != null) {
1554                 if (frameStack.head.tree.hasTag(LAMBDA)) {
1555                     ltc.addSymbol(tree.sym, LOCAL_VAR);
1556                 }
1557                 // Check for type variables (including as type arguments).
1558                 // If they occur within class nested in a lambda, mark for erasure
1559                 Type type = tree.sym.asType();



1560             }
1561 
1562             List<Frame> prevStack = frameStack;
1563             try {
1564                 if (tree.sym.owner.kind == MTH) {
1565                     frameStack.head.addLocal(tree.sym);
1566                 }
1567                 frameStack = frameStack.prepend(new Frame(tree));
1568                 super.visitVarDef(tree);
1569             }
1570             finally {
1571                 frameStack = prevStack;
1572             }
1573         }
1574 
1575         /**
1576          * Return a valid owner given the current declaration stack
1577          * (required to skip synthetic lambda symbols)
1578          */
1579         private Symbol owner() {


1909              */
1910             JCExpression methodReferenceReceiver;
1911 
1912             LambdaTranslationContext(JCLambda tree) {
1913                 super(tree);
1914                 Frame frame = frameStack.head;
1915                 switch (frame.tree.getTag()) {
1916                     case VARDEF:
1917                         assignedTo = self = ((JCVariableDecl) frame.tree).sym;
1918                         break;
1919                     case ASSIGN:
1920                         self = null;
1921                         assignedTo = TreeInfo.symbol(((JCAssign) frame.tree).getVariable());
1922                         break;
1923                     default:
1924                         assignedTo = self = null;
1925                         break;
1926                  }
1927 
1928                 // This symbol will be filled-in in complete
1929                 if (owner.kind == MTH) {
1930                     final MethodSymbol originalOwner = (MethodSymbol)owner.clone(owner.owner);
1931                     this.translatedSym = new MethodSymbol(SYNTHETIC | PRIVATE, null, null, owner.enclClass()) {
1932                         @Override
1933                         public MethodSymbol originalEnclosingMethod() {
1934                             return originalOwner;
1935                         }
1936                     };
1937                 } else {
1938                     this.translatedSym = makePrivateSyntheticMethod(0, null, null, owner.enclClass());
1939                 }
1940                 translatedSymbols = new EnumMap<>(LambdaSymbolKind.class);
1941 
1942                 translatedSymbols.put(PARAM, new LinkedHashMap<Symbol, Symbol>());
1943                 translatedSymbols.put(LOCAL_VAR, new LinkedHashMap<Symbol, Symbol>());
1944                 translatedSymbols.put(CAPTURED_VAR, new LinkedHashMap<Symbol, Symbol>());
1945                 translatedSymbols.put(CAPTURED_THIS, new LinkedHashMap<Symbol, Symbol>());
1946                 translatedSymbols.put(CAPTURED_OUTER_THIS, new LinkedHashMap<Symbol, Symbol>());

1947 
1948                 freeVarProcessedLocalClasses = new HashSet<>();
1949             }
1950 
1951              /**
1952              * For a serializable lambda, generate a disambiguating string
1953              * which maximizes stability across deserialization.
1954              *
1955              * @return String to differentiate synthetic lambda method names
1956              */
1957             private String serializedLambdaDisambiguation() {
1958                 StringBuilder buf = new StringBuilder();
1959                 // Append the enclosing method signature to differentiate
1960                 // overloaded enclosing methods.  For lambdas enclosed in
1961                 // lambdas, the generated lambda method will not have type yet,
1962                 // but the enclosing method's name will have been generated
1963                 // with this same method, so it will be unique and never be
1964                 // overloaded.
1965                 Assert.check(
1966                         owner.type != null ||


2019                 buf.append(Integer.toHexString(disam.hashCode()));
2020                 buf.append('$');
2021                 // The above appended name components may not be unique, append
2022                 // a count based on the above name components.
2023                 buf.append(syntheticMethodNameCounts.getIndex(buf));
2024                 String result = buf.toString();
2025                 //System.err.printf("serializedLambdaName: %s -- %s\n", result, disam);
2026                 return names.fromString(result);
2027             }
2028 
2029             /**
2030              * Translate a symbol of a given kind into something suitable for the
2031              * synthetic lambda body
2032              */
2033             Symbol translate(final Symbol sym, LambdaSymbolKind skind) {
2034                 Symbol ret;
2035                 switch (skind) {
2036                     case CAPTURED_THIS:
2037                         ret = sym;  // self represented
2038                         break;










2039                     case CAPTURED_VAR:
2040                         ret = new VarSymbol(SYNTHETIC | FINAL | PARAMETER, sym.name, types.erasure(sym.type), translatedSym) {
2041                             @Override
2042                             public Symbol baseSymbol() {
2043                                 //keep mapping with original captured symbol
2044                                 return sym;
2045                             }
2046                         };
2047                         break;
2048                     case CAPTURED_OUTER_THIS:
2049                         Name name = names.fromString(new String(sym.flatName().toString().replace('.', '$') + names.dollarThis));
2050                         ret = new VarSymbol(SYNTHETIC | FINAL | PARAMETER, name, types.erasure(sym.type), translatedSym) {
2051                             @Override
2052                             public Symbol baseSymbol() {
2053                                 //keep mapping with original captured symbol
2054                                 return sym;
2055                             }
2056                         };
2057                         break;
2058                     case LOCAL_VAR:


2217             Type generatedLambdaSig() {
2218                 return types.erasure(tree.getDescriptorType(types));
2219             }
2220         }
2221 
2222         /**
2223          * This class retains all the useful information about a method reference;
2224          * the contents of this class are filled by the LambdaAnalyzer visitor,
2225          * and the used by the main translation routines in order to adjust method
2226          * references (i.e. in case a bridge is needed)
2227          */
2228         final class ReferenceTranslationContext extends TranslationContext<JCMemberReference> {
2229 
2230             final boolean isSuper;
2231 
2232             ReferenceTranslationContext(JCMemberReference tree) {
2233                 super(tree);
2234                 this.isSuper = tree.hasKind(ReferenceKind.SUPER);
2235             }
2236 







2237             boolean needsVarArgsConversion() {
2238                 return tree.varargsElement != null;
2239             }
2240 
2241             /**
2242              * @return Is this an array operation like clone()
2243              */
2244             boolean isArrayOp() {
2245                 return tree.sym.owner == syms.arrayClass;
2246             }
2247 
2248             boolean receiverAccessible() {
2249                 //hack needed to workaround 292 bug (7087658)
2250                 //when 292 issue is fixed we should remove this and change the backend
2251                 //code to always generate a method handle to an accessible method
2252                 return tree.ownerAccessible;
2253             }
2254 
2255             /**
2256              * The VM does not support access across nested classes (8010319).


2315             Type generatedRefSig() {
2316                 return types.erasure(tree.sym.type);
2317             }
2318 
2319             Type bridgedRefSig() {
2320                 return types.erasure(types.findDescriptorSymbol(tree.target.tsym).type);
2321             }
2322         }
2323     }
2324     // </editor-fold>
2325 
2326     /*
2327      * These keys provide mappings for various translated lambda symbols
2328      * and the prevailing order must be maintained.
2329      */
2330     enum LambdaSymbolKind {
2331         PARAM,          // original to translated lambda parameters
2332         LOCAL_VAR,      // original to translated lambda locals
2333         CAPTURED_VAR,   // variables in enclosing scope to translated synthetic parameters
2334         CAPTURED_THIS,  // class symbols to translated synthetic parameters (for captured member access)
2335         CAPTURED_OUTER_THIS; // used when `this' capture is illegal, but outer this capture is legit (JDK-8129740)

2336 
2337         boolean propagateAnnotations() {
2338             switch (this) {
2339                 case CAPTURED_VAR:
2340                 case CAPTURED_THIS:
2341                 case CAPTURED_OUTER_THIS:
2342                     return false;
2343                 default:
2344                     return true;
2345            }
2346         }
2347     }
2348 
2349     /**
2350      * ****************************************************************
2351      * Signature Generation
2352      * ****************************************************************
2353      */
2354 
2355     private String typeSig(Type type) {




   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.tools.javac.comp;
  27 

  28 import com.sun.tools.javac.code.Types.SignatureGenerator.InvalidSignatureException;

  29 import com.sun.tools.javac.resources.CompilerProperties.Errors;
  30 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
  31 import com.sun.tools.javac.code.Source.Feature;
  32 import com.sun.tools.javac.tree.*;
  33 import com.sun.tools.javac.tree.JCTree.*;
  34 import com.sun.tools.javac.tree.JCTree.JCMemberReference.ReferenceKind;
  35 import com.sun.tools.javac.tree.TreeMaker;
  36 import com.sun.tools.javac.tree.TreeTranslator;
  37 import com.sun.tools.javac.code.Attribute;
  38 import com.sun.tools.javac.code.Scope.WriteableScope;
  39 import com.sun.tools.javac.code.Symbol;
  40 import com.sun.tools.javac.code.Symbol.ClassSymbol;
  41 import com.sun.tools.javac.code.Symbol.DynamicMethodSymbol;
  42 import com.sun.tools.javac.code.Symbol.MethodSymbol;
  43 import com.sun.tools.javac.code.Symbol.TypeSymbol;
  44 import com.sun.tools.javac.code.Symbol.VarSymbol;
  45 import com.sun.tools.javac.code.Symtab;
  46 import com.sun.tools.javac.code.Type;
  47 import com.sun.tools.javac.code.Type.MethodType;
  48 import com.sun.tools.javac.code.Type.TypeVar;
  49 import com.sun.tools.javac.code.Types;
  50 import com.sun.tools.javac.comp.LambdaToMethod.LambdaAnalyzerPreprocessor.*;
  51 import com.sun.tools.javac.comp.Lower.BasicFreeVarCollector;
  52 import com.sun.tools.javac.resources.CompilerProperties.Notes;
  53 import com.sun.tools.javac.jvm.*;
  54 import com.sun.tools.javac.util.*;
  55 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
  56 import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
  57 
  58 import java.util.EnumMap;
  59 import java.util.HashMap;
  60 import java.util.HashSet;
  61 import java.util.LinkedHashMap;
  62 import java.util.Map;
  63 import java.util.Objects;
  64 import java.util.Optional;
  65 import java.util.Set;
  66 import java.util.function.Consumer;
  67 import java.util.function.Supplier;
  68 
  69 import static com.sun.tools.javac.comp.LambdaToMethod.LambdaSymbolKind.*;
  70 import static com.sun.tools.javac.code.Flags.*;
  71 import static com.sun.tools.javac.code.Kinds.Kind.*;
  72 import static com.sun.tools.javac.code.TypeTag.*;
  73 import static com.sun.tools.javac.tree.JCTree.Tag.*;
  74 import static com.sun.tools.javac.jvm.Pool.DynamicMethod;
  75 
  76 import javax.lang.model.element.ElementKind;
  77 import javax.lang.model.type.TypeKind;
  78 
  79 import com.sun.tools.javac.code.Type.IntersectionClassType;
  80 import com.sun.tools.javac.code.Types.FunctionDescriptorLookupError;
  81 import com.sun.tools.javac.main.Option;
  82 import com.sun.tools.javac.code.Source;
  83 import com.sun.tools.javac.code.Symbol.DynamicVarSymbol;
  84 
  85 /**
  86  * This pass desugars lambda expressions into static methods
  87  *
  88  *  <p><b>This is NOT part of any supported API.
  89  *  If you write code that depends on this, you do so at your own risk.
  90  *  This code and its internal interfaces are subject to change or
  91  *  deletion without notice.</b>
  92  */
  93 public class LambdaToMethod extends TreeTranslator {
  94 
  95     private Attr attr;
  96     private JCDiagnostic.Factory diags;
  97     private Log log;
  98     private Lower lower;
  99     private Names names;
 100     private Symtab syms;
 101     private Resolve rs;
 102     private Operators operators;
 103     private TreeMaker make;


 156         diags = JCDiagnostic.Factory.instance(context);
 157         log = Log.instance(context);
 158         lower = Lower.instance(context);
 159         names = Names.instance(context);
 160         syms = Symtab.instance(context);
 161         rs = Resolve.instance(context);
 162         operators = Operators.instance(context);
 163         make = TreeMaker.instance(context);
 164         types = Types.instance(context);
 165         transTypes = TransTypes.instance(context);
 166         analyzer = new LambdaAnalyzerPreprocessor();
 167         Options options = Options.instance(context);
 168         dumpLambdaToMethodStats = options.isSet("debug.dumpLambdaToMethodStats");
 169         attr = Attr.instance(context);
 170         forceSerializable = options.isSet("forceSerializable");
 171         debugLinesOrVars = options.isSet(Option.G)
 172                 || options.isSet(Option.G_CUSTOM, "lines")
 173                 || options.isSet(Option.G_CUSTOM, "vars");
 174         verboseDeduplication = options.isSet("debug.dumpLambdaToMethodDeduplication");
 175         deduplicateLambdas = options.getBoolean("deduplicateLambdas", true);
 176         Source source = Source.instance(context);
 177         // format: -XDforNonCapturingLambda=generateCondy, which is the default, or -XDforNonCapturingLambda=generateIndy
 178         String condyOp = options.get("forNonCapturingLambda");
 179         condyForLambda = condyOp != null ?
 180                 condyOp.equals("generateCondy") :
 181                 Feature.CONDY_FOR_LAMBDA.allowedInSource(source);
 182     }
 183     // </editor-fold>
 184 
 185     class DedupedLambda {
 186         private final MethodSymbol symbol;
 187         private final JCTree tree;
 188 
 189         private int hashCode;
 190 
 191         DedupedLambda(MethodSymbol symbol, JCTree tree) {
 192             this.symbol = symbol;
 193             this.tree = tree;
 194         }
 195 
 196 
 197         @Override
 198         public int hashCode() {
 199             int hashCode = this.hashCode;
 200             if (hashCode == 0) {
 201                 this.hashCode = hashCode = TreeHasher.hash(tree, symbol.params());


 206         @Override
 207         public boolean equals(Object o) {
 208             if (!(o instanceof DedupedLambda)) {
 209                 return false;
 210             }
 211             DedupedLambda that = (DedupedLambda) o;
 212             return types.isSameType(symbol.asType(), that.symbol.asType())
 213                     && new TreeDiffer(symbol.params(), that.symbol.params()).scan(tree, that.tree);
 214         }
 215     }
 216 
 217     private class KlassInfo {
 218 
 219         /**
 220          * list of methods to append
 221          */
 222         private ListBuffer<JCTree> appendedMethodList;
 223 
 224         private Map<DedupedLambda, DedupedLambda> dedupedLambdas;
 225 
 226         private Map<DynamicMethod, DynamicMethodSymbol> dynMethSyms = new HashMap<>();
 227 
 228         /**
 229          * list of deserialization cases
 230          */
 231         private final Map<String, ListBuffer<JCStatement>> deserializeCases;
 232 
 233        /**
 234          * deserialize method symbol
 235          */
 236         private final MethodSymbol deserMethodSym;
 237 
 238         /**
 239          * deserialize method parameter symbol
 240          */
 241         private final VarSymbol deserParamSym;
 242 
 243         private final JCClassDecl clazz;
 244 
 245         private KlassInfo(JCClassDecl clazz) {
 246             this.clazz = clazz;


 431                     sym.owner.enclClass().asType(),
 432                     localContext.owner.enclClass()));
 433         }
 434 
 435         //add captured locals
 436         for (Symbol fv : localContext.getSymbolMap(CAPTURED_VAR).keySet()) {
 437             if (fv != localContext.self) {
 438                 JCTree captured_local = make.Ident(fv).setType(fv.type);
 439                 syntheticInits.append((JCExpression) captured_local);
 440             }
 441         }
 442         // add captured outer this instances (used only when `this' capture itself is illegal)
 443         for (Symbol fv : localContext.getSymbolMap(CAPTURED_OUTER_THIS).keySet()) {
 444             JCTree captured_local = make.QualThis(fv.type);
 445             syntheticInits.append((JCExpression) captured_local);
 446         }
 447 
 448         //then, determine the arguments to the indy call
 449         List<JCExpression> indy_args = translate(syntheticInits.toList(), localContext.prev);
 450 
 451         //build a sam instance using an indy call to the meta-factory
 452         int refKind = referenceKind(sym);
 453 
 454         //convert to an invokedynamic call
 455         result = makeMetafactoryIndyCall(context, refKind, sym, indy_args);
 456     }
 457 
 458     // where
 459         // Reassign type annotations from the source that should really belong to the lambda
 460         private void apportionTypeAnnotations(JCLambda tree,
 461                                               Supplier<List<Attribute.TypeCompound>> source,
 462                                               Consumer<List<Attribute.TypeCompound>> owner,
 463                                               Consumer<List<Attribute.TypeCompound>> lambda) {
 464 
 465             ListBuffer<Attribute.TypeCompound> ownerTypeAnnos = new ListBuffer<>();
 466             ListBuffer<Attribute.TypeCompound> lambdaTypeAnnos = new ListBuffer<>();
 467 
 468             for (Attribute.TypeCompound tc : source.get()) {
 469                 if (tc.position.onLambda == tree) {
 470                     lambdaTypeAnnos.append(tc);
 471                 } else {
 472                     ownerTypeAnnos.append(tc);
 473                 }
 474             }
 475             if (lambdaTypeAnnos.nonEmpty()) {


 480 
 481     private JCIdent makeThis(Type type, Symbol owner) {
 482         VarSymbol _this = new VarSymbol(PARAMETER | FINAL | SYNTHETIC,
 483                 names._this,
 484                 type,
 485                 owner);
 486         return make.Ident(_this);
 487     }
 488 
 489     /**
 490      * Translate a method reference into an invokedynamic call to the
 491      * meta-factory.
 492      * @param tree
 493      */
 494     @Override
 495     public void visitReference(JCMemberReference tree) {
 496         ReferenceTranslationContext localContext = (ReferenceTranslationContext)context;
 497 
 498         //first determine the method symbol to be used to generate the sam instance
 499         //this is either the method reference symbol, or the bridged reference symbol
 500         Symbol refSym = tree.sym;
 501 
 502         //the qualifying expression is treated as a special captured arg
 503         JCExpression init;
 504         switch(tree.kind) {
 505 
 506             case IMPLICIT_INNER:    /** Inner :: new */
 507             case SUPER:             /** super :: instMethod */
 508                 init = makeThis(
 509                     localContext.owner.enclClass().asType(),
 510                     localContext.owner.enclClass());
 511                 break;
 512 
 513             case BOUND:             /** Expr :: instMethod */
 514                 init = transTypes.coerce(attrEnv, tree.getQualifierExpression(),
 515                     types.erasure(tree.sym.owner.type));
 516                 init = attr.makeNullCheck(init);
 517                 break;
 518 
 519             case UNBOUND:           /** Type :: instMethod */
 520             case STATIC:            /** Type :: staticMethod */
 521             case TOPLEVEL:          /** Top level :: new */
 522             case ARRAY_CTOR:        /** ArrayType :: new */
 523                 init = null;
 524                 break;
 525 
 526             default:
 527                 throw new InternalError("Should not have an invalid kind");
 528         }
 529 
 530         List<JCExpression> indy_args = init==null? List.nil() : translate(List.of(init), localContext.prev);
 531 
 532 
 533         //build a sam instance using an indy call to the meta-factory
 534         result = makeMetafactoryIndyCall(localContext, localContext.referenceKind(), refSym, indy_args);
 535     }
 536 
 537     /**
 538      * Translate identifiers within a lambda to the mapped identifier
 539      * @param tree
 540      */
 541     @Override
 542     public void visitIdent(JCIdent tree) {
 543         if (context == null || !analyzer.lambdaIdentSymbolFilter(tree.sym)) {
 544             super.visitIdent(tree);
 545         } else {
 546             int prevPos = make.pos;
 547             try {
 548                 make.at(tree);
 549 
 550                 LambdaTranslationContext lambdaContext = (LambdaTranslationContext) context;
 551                 JCTree ltree = lambdaContext.translate(tree);
 552                 if (ltree != null) {
 553                     result = ltree;
 554                 } else {


 600             int prevPos = make.pos;
 601             try {
 602                 make.at(tree);
 603 
 604                 LambdaTranslationContext lambdaContext = (LambdaTranslationContext) context;
 605                 tree = lambdaContext.translate(tree);
 606                 super.visitNewClass(tree);
 607             } finally {
 608                 make.at(prevPos);
 609             }
 610         }
 611     }
 612 
 613     @Override
 614     public void visitVarDef(JCVariableDecl tree) {
 615         LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context;
 616         if (context != null && lambdaContext.getSymbolMap(LOCAL_VAR).containsKey(tree.sym)) {
 617             tree.init = translate(tree.init);
 618             tree.sym = (VarSymbol) lambdaContext.getSymbolMap(LOCAL_VAR).get(tree.sym);
 619             result = tree;
 620         } else if (context != null && lambdaContext.getSymbolMap(TYPE_VAR).containsKey(tree.sym)) {
 621             JCExpression init = translate(tree.init);
 622             VarSymbol xsym = (VarSymbol)lambdaContext.getSymbolMap(TYPE_VAR).get(tree.sym);
 623             int prevPos = make.pos;
 624             try {
 625                 result = make.at(tree).VarDef(xsym, init);
 626             } finally {
 627                 make.at(prevPos);
 628             }
 629             // Replace the entered symbol for this variable
 630             WriteableScope sc = tree.sym.owner.members();
 631             if (sc != null) {
 632                 sc.remove(tree.sym);
 633                 sc.enter(xsym);
 634             }
 635         } else {
 636             super.visitVarDef(tree);
 637         }
 638     }
 639 
 640     // </editor-fold>
 641 
 642     // <editor-fold defaultstate="collapsed" desc="Translation helper methods">
 643 
 644     private JCBlock makeLambdaBody(JCLambda tree, JCMethodDecl lambdaMethodDecl) {
 645         return tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION ?
 646                 makeLambdaExpressionBody((JCExpression)tree.body, lambdaMethodDecl) :
 647                 makeLambdaStatementBody((JCBlock)tree.body, lambdaMethodDecl, tree.canCompleteNormally);
 648     }
 649 
 650     private JCBlock makeLambdaExpressionBody(JCExpression expr, JCMethodDecl lambdaMethodDecl) {
 651         Type restype = lambdaMethodDecl.type.getReturnType();
 652         boolean isLambda_void = expr.type.hasTag(VOID);
 653         boolean isTarget_void = restype.hasTag(VOID);
 654         boolean isTarget_Void = types.isSameType(restype, types.boxedClass(syms.voidType).type);


 757      *  @param args     The constructor arguments.
 758      *  @param cons     The constructor symbol
 759      */
 760     JCNewClass makeNewClass(Type ctype, List<JCExpression> args, Symbol cons) {
 761         JCNewClass tree = make.NewClass(null,
 762             null, make.QualIdent(ctype.tsym), args, null);
 763         tree.constructor = cons;
 764         tree.type = ctype;
 765         return tree;
 766     }
 767 
 768     /** Make an attributed class instance creation expression.
 769      *  @param ctype    The class type.
 770      *  @param args     The constructor arguments.
 771      */
 772     JCNewClass makeNewClass(Type ctype, List<JCExpression> args) {
 773         return makeNewClass(ctype, args,
 774                 rs.resolveConstructor(null, attrEnv, ctype, TreeInfo.types(args), List.nil()));
 775      }
 776 
 777     private void addDeserializationCase(int implMethodKind, Symbol refSym, Type targetType, MethodSymbol samSym,
 778             DiagnosticPosition pos, List<Object> staticArgs, MethodType indyType) {
 779         String functionalInterfaceClass = classSig(targetType);
 780         String functionalInterfaceMethodName = samSym.getSimpleName().toString();
 781         String functionalInterfaceMethodSignature = typeSig(types.erasure(samSym.type));
 782         String implClass = classSig(types.erasure(refSym.owner.type));
 783         String implMethodName = refSym.getQualifiedName().toString();
 784         String implMethodSignature = typeSig(types.erasure(refSym.type));
 785 
 786         JCExpression kindTest = eqTest(syms.intType, deserGetter("getImplMethodKind", syms.intType), make.Literal(implMethodKind));

 787         ListBuffer<JCExpression> serArgs = new ListBuffer<>();
 788         int i = 0;
 789         for (Type t : indyType.getParameterTypes()) {
 790             List<JCExpression> indexAsArg = new ListBuffer<JCExpression>().append(make.Literal(i)).toList();
 791             List<Type> argTypes = new ListBuffer<Type>().append(syms.intType).toList();
 792             serArgs.add(make.TypeCast(types.erasure(t), deserGetter("getCapturedArg", syms.objectType, argTypes, indexAsArg)));
 793             ++i;
 794         }
 795         JCStatement stmt = make.If(
 796                 deserTest(deserTest(deserTest(deserTest(deserTest(
 797                     kindTest,
 798                     "getFunctionalInterfaceClass", functionalInterfaceClass),
 799                     "getFunctionalInterfaceMethodName", functionalInterfaceMethodName),
 800                     "getFunctionalInterfaceMethodSignature", functionalInterfaceMethodSignature),
 801                     "getImplClass", implClass),
 802                     "getImplMethodSignature", implMethodSignature),
 803                 make.Return(makeDynamicCall(
 804                     pos,
 805                     syms.lambdaMetafactory,
 806                     names.altMetafactory,
 807                     staticArgs, targetType, indyType, serArgs.toList(), samSym.name)),
 808                 null);
 809         ListBuffer<JCStatement> stmts = kInfo.deserializeCases.get(implMethodName);
 810         if (stmts == null) {
 811             stmts = new ListBuffer<>();
 812             kInfo.deserializeCases.put(implMethodName, stmts);
 813         }
 814         /****
 815         System.err.printf("+++++++++++++++++\n");
 816         System.err.printf("*functionalInterfaceClass: '%s'\n", functionalInterfaceClass);
 817         System.err.printf("*functionalInterfaceMethodName: '%s'\n", functionalInterfaceMethodName);
 818         System.err.printf("*functionalInterfaceMethodSignature: '%s'\n", functionalInterfaceMethodSignature);
 819         System.err.printf("*implMethodKind: %d\n", implMethodKind);
 820         System.err.printf("*implClass: '%s'\n", implClass);
 821         System.err.printf("*implMethodName: '%s'\n", implMethodName);
 822         System.err.printf("*implMethodSignature: '%s'\n", implMethodSignature);
 823         ****/
 824         stmts.append(stmt);
 825     }
 826 
 827     private JCExpression eqTest(Type argType, JCExpression arg1, JCExpression arg2) {


1098             params.append(make.VarDef(vsym, null));
1099             if (genArg) {
1100                 args.append(make.Ident(vsym));
1101             }
1102             return vsym;
1103         }
1104     }
1105 
1106     private MethodType typeToMethodType(Type mt) {
1107         Type type = types.erasure(mt);
1108         return new MethodType(type.getParameterTypes(),
1109                         type.getReturnType(),
1110                         type.getThrownTypes(),
1111                         syms.methodClass);
1112     }
1113 
1114     /**
1115      * Generate an indy method call to the meta factory
1116      */
1117     private JCExpression makeMetafactoryIndyCall(TranslationContext<?> context,
1118             int refKind, Symbol refSym, List<JCExpression> indy_args) {
1119         JCFunctionalExpression tree = context.tree;
1120         //determine the static bsm args
1121         MethodSymbol samSym = (MethodSymbol) types.findDescriptorSymbol(tree.target.tsym);
1122         List<Object> staticArgs = List.of(
1123                 typeToMethodType(samSym.type),
1124                 new Pool.MethodHandle(refKind, refSym, types),
1125                 typeToMethodType(tree.getDescriptorType(types)));
1126 
1127         //computed indy arg types
1128         ListBuffer<Type> indy_args_types = new ListBuffer<>();
1129         for (JCExpression arg : indy_args) {
1130             indy_args_types.append(arg.type);
1131         }
1132 
1133         //finally, compute the type of the indy call
1134         MethodType indyType = new MethodType(indy_args_types.toList(),
1135                 tree.type,
1136                 List.nil(),
1137                 syms.methodClass);
1138 
1139         Name metafactoryName = context.needsAltMetafactory() ?
1140                 names.altMetafactory : names.metafactory;
1141 
1142         if (context.needsAltMetafactory()) {
1143             ListBuffer<Object> markers = new ListBuffer<>();
1144             List<Type> targets = tree.target.isIntersection() ?
1145                     types.directSupertypes(tree.target) :
1146                     List.nil();
1147             for (Type t : targets) {
1148                 t = types.erasure(t);
1149                 if (t.tsym != syms.serializableType.tsym &&
1150                     t.tsym != tree.type.tsym &&
1151                     t.tsym != syms.objectType.tsym) {
1152                     markers.append(t.tsym);
1153                 }
1154             }
1155             int flags = context.isSerializable() ? FLAG_SERIALIZABLE : 0;
1156             boolean hasMarkers = markers.nonEmpty();
1157             boolean hasBridges = context.bridges.nonEmpty();
1158             if (hasMarkers) {
1159                 flags |= FLAG_MARKERS;
1160             }
1161             if (hasBridges) {
1162                 flags |= FLAG_BRIDGES;
1163             }
1164             staticArgs = staticArgs.append(flags);
1165             if (hasMarkers) {
1166                 staticArgs = staticArgs.append(markers.length());
1167                 staticArgs = staticArgs.appendList(markers.toList());
1168             }
1169             if (hasBridges) {
1170                 staticArgs = staticArgs.append(context.bridges.length() - 1);
1171                 for (Symbol s : context.bridges) {
1172                     Type s_erasure = s.erasure(types);
1173                     if (!types.isSameType(s_erasure, samSym.erasure(types))) {
1174                         staticArgs = staticArgs.append(s.erasure(types));
1175                     }
1176                 }
1177             }
1178             if (context.isSerializable()) {
1179                 int prevPos = make.pos;
1180                 try {
1181                     make.at(kInfo.clazz);
1182                     addDeserializationCase(refKind, refSym, tree.type, samSym,
1183                             tree, staticArgs, indyType);
1184                 } finally {
1185                     make.at(prevPos);
1186                 }
1187             }
1188         }
1189 
1190         return makeDynamicCall(tree, syms.lambdaMetafactory,
1191                 metafactoryName, staticArgs, tree.type, indyType, indy_args, samSym.name);
1192     }
1193 
1194     private JCExpression makeDynamicCall(DiagnosticPosition pos, Type site, Name bsmName,
1195             List<Object> staticArgs, Type interfaceType, MethodType indyType, List<JCExpression> indyArgs,
1196             Name methName) {
1197         return condyForLambda &&
1198                !context.needsAltMetafactory() &&
1199                indyArgs.isEmpty() ?
1200                makeCondy(pos, site, bsmName, staticArgs, interfaceType, methName) :
1201                makeIndyCall(pos, site, bsmName, staticArgs, indyType, indyArgs, methName);
1202     }
1203 
1204     /* this extra flag should be temporary and used as long as it's not possible to do the build
1205      * due to the lack of support for condy in the current version of ASM present in the build
1206      */
1207     private final boolean condyForLambda;
1208 
1209     private JCExpression makeCondy(DiagnosticPosition pos, Type site, Name bsmName,
1210             List<Object> staticArgs, Type interfaceType, Name methName) {
1211         int prevPos = make.pos;
1212         try {
1213             make.at(pos);
1214             List<Type> bsm_staticArgs = List.of(syms.methodHandlesLookupType,
1215                     syms.stringType,
1216                     syms.classType).appendList(bsmStaticArgToTypes(staticArgs));
1217 
1218             Symbol bsm = rs.resolveInternalMethod(pos, attrEnv, site,
1219                     bsmName, bsm_staticArgs, List.nil());
1220 
1221             DynamicVarSymbol dynSym = new DynamicVarSymbol(methName,
1222                     syms.noSymbol,
1223                     bsm.isStatic() ?
1224                         ClassFile.REF_invokeStatic :
1225                         ClassFile.REF_invokeVirtual,
1226                     (MethodSymbol)bsm,
1227                     interfaceType,
1228                     staticArgs.toArray());
1229 
1230             JCIdent ident = make.Ident(dynSym);
1231             ident.type = interfaceType;
1232 
1233             return ident;
1234         } finally {
1235             make.at(prevPos);
1236         }
1237     }
1238 
1239     /**
1240      * Generate an indy method call with given name, type and static bootstrap
1241      * arguments types
1242      */
1243     private JCExpression makeIndyCall(DiagnosticPosition pos, Type site, Name bsmName,
1244             List<Object> staticArgs, MethodType indyType, List<JCExpression> indyArgs,
1245             Name methName) {
1246         int prevPos = make.pos;
1247         try {
1248             make.at(pos);
1249             List<Type> bsm_staticArgs = List.of(syms.methodHandlesLookupType,
1250                     syms.stringType,
1251                     syms.methodTypeType).appendList(bsmStaticArgToTypes(staticArgs));
1252 
1253             Symbol bsm = rs.resolveInternalMethod(pos, attrEnv, site,
1254                     bsmName, bsm_staticArgs, List.nil());
1255 
1256             DynamicMethodSymbol dynSym =
1257                     new DynamicMethodSymbol(methName,
1258                                             syms.noSymbol,
1259                                             bsm.isStatic() ?
1260                                                 ClassFile.REF_invokeStatic :
1261                                                 ClassFile.REF_invokeVirtual,
1262                                             (MethodSymbol)bsm,
1263                                             indyType,
1264                                             staticArgs.toArray());
1265             JCFieldAccess qualifier = make.Select(make.QualIdent(site.tsym), bsmName);
1266             DynamicMethodSymbol existing = kInfo.dynMethSyms.putIfAbsent(
1267                     new DynamicMethod(dynSym, types), dynSym);
1268             qualifier.sym = existing != null ? existing : dynSym;
1269             qualifier.type = indyType.getReturnType();
1270 
1271             JCMethodInvocation proxyCall = make.Apply(List.nil(), qualifier, indyArgs);
1272             proxyCall.type = indyType.getReturnType();
1273             return proxyCall;
1274         } finally {
1275             make.at(prevPos);
1276         }
1277     }
1278     //where
1279     private List<Type> bsmStaticArgToTypes(List<Object> args) {
1280         ListBuffer<Type> argtypes = new ListBuffer<>();
1281         for (Object arg : args) {
1282             argtypes.append(bsmStaticArgToType(arg));
1283         }
1284         return argtypes.toList();
1285     }
1286 
1287     private Type bsmStaticArgToType(Object arg) {
1288         Assert.checkNonNull(arg);
1289         if (arg instanceof ClassSymbol) {
1290             return syms.classType;
1291         } else if (arg instanceof Integer) {
1292             return syms.intType;
1293         } else if (arg instanceof Long) {
1294             return syms.longType;
1295         } else if (arg instanceof Float) {
1296             return syms.floatType;
1297         } else if (arg instanceof Double) {
1298             return syms.doubleType;
1299         } else if (arg instanceof String) {
1300             return syms.stringType;
1301         } else if (arg instanceof Pool.MethodHandle) {
1302             return syms.methodHandleType;
1303         } else if (arg instanceof MethodType) {
1304             return syms.methodTypeType;
1305         } else {
1306             Assert.error("bad static arg " + arg.getClass());
1307             return null;
1308         }
1309     }
1310 
1311     /**
1312      * Get the opcode associated with this method reference
1313      */
1314     private int referenceKind(Symbol refSym) {
1315         if (refSym.isConstructor()) {
1316             return ClassFile.REF_newInvokeSpecial;
1317         } else {
1318             if (refSym.isStatic()) {
1319                 return ClassFile.REF_invokeStatic;
1320             } else if ((refSym.flags() & PRIVATE) != 0) {
1321                 return ClassFile.REF_invokeSpecial;
1322             } else if (refSym.enclClass().isInterface()) {
1323                 return ClassFile.REF_invokeInterface;
1324             } else {
1325                 return ClassFile.REF_invokeVirtual;
1326             }
1327         }
1328     }
1329 
1330     // <editor-fold defaultstate="collapsed" desc="Lambda/reference analyzer">
1331     /**
1332      * This visitor collects information about translation of a lambda expression.
1333      * More specifically, it keeps track of the enclosing contexts and captured locals
1334      * accessed by the lambda being translated (as well as other useful info).
1335      * It also translates away problems for LambdaToMethod.
1336      */
1337     class LambdaAnalyzerPreprocessor extends TreeTranslator {
1338 
1339         /** the frame stack - used to reconstruct translation info about enclosing scopes */
1340         private List<Frame> frameStack;
1341 
1342         /**
1343          * keep the count of lambda expression (used to generate unambiguous
1344          * names)
1345          */
1346         private int lambdaCount = 0;
1347 
1348         /**


1668                     }
1669                     localContext = localContext.prev;
1670                 }
1671             }
1672             super.visitSelect(tree);
1673         }
1674 
1675         @Override
1676         public void visitVarDef(JCVariableDecl tree) {
1677             TranslationContext<?> context = context();
1678             LambdaTranslationContext ltc = (context != null && context instanceof LambdaTranslationContext)?
1679                     (LambdaTranslationContext)context :
1680                     null;
1681             if (ltc != null) {
1682                 if (frameStack.head.tree.hasTag(LAMBDA)) {
1683                     ltc.addSymbol(tree.sym, LOCAL_VAR);
1684                 }
1685                 // Check for type variables (including as type arguments).
1686                 // If they occur within class nested in a lambda, mark for erasure
1687                 Type type = tree.sym.asType();
1688                 if (inClassWithinLambda() && !types.isSameType(types.erasure(type), type)) {
1689                     ltc.addSymbol(tree.sym, TYPE_VAR);
1690                 }
1691             }
1692 
1693             List<Frame> prevStack = frameStack;
1694             try {
1695                 if (tree.sym.owner.kind == MTH) {
1696                     frameStack.head.addLocal(tree.sym);
1697                 }
1698                 frameStack = frameStack.prepend(new Frame(tree));
1699                 super.visitVarDef(tree);
1700             }
1701             finally {
1702                 frameStack = prevStack;
1703             }
1704         }
1705 
1706         /**
1707          * Return a valid owner given the current declaration stack
1708          * (required to skip synthetic lambda symbols)
1709          */
1710         private Symbol owner() {


2040              */
2041             JCExpression methodReferenceReceiver;
2042 
2043             LambdaTranslationContext(JCLambda tree) {
2044                 super(tree);
2045                 Frame frame = frameStack.head;
2046                 switch (frame.tree.getTag()) {
2047                     case VARDEF:
2048                         assignedTo = self = ((JCVariableDecl) frame.tree).sym;
2049                         break;
2050                     case ASSIGN:
2051                         self = null;
2052                         assignedTo = TreeInfo.symbol(((JCAssign) frame.tree).getVariable());
2053                         break;
2054                     default:
2055                         assignedTo = self = null;
2056                         break;
2057                  }
2058 
2059                 // This symbol will be filled-in in complete
2060                 this.translatedSym = makePrivateSyntheticMethod(0, null, null, owner.enclClass());
2061 









2062                 translatedSymbols = new EnumMap<>(LambdaSymbolKind.class);
2063 
2064                 translatedSymbols.put(PARAM, new LinkedHashMap<Symbol, Symbol>());
2065                 translatedSymbols.put(LOCAL_VAR, new LinkedHashMap<Symbol, Symbol>());
2066                 translatedSymbols.put(CAPTURED_VAR, new LinkedHashMap<Symbol, Symbol>());
2067                 translatedSymbols.put(CAPTURED_THIS, new LinkedHashMap<Symbol, Symbol>());
2068                 translatedSymbols.put(CAPTURED_OUTER_THIS, new LinkedHashMap<Symbol, Symbol>());
2069                 translatedSymbols.put(TYPE_VAR, new LinkedHashMap<Symbol, Symbol>());
2070 
2071                 freeVarProcessedLocalClasses = new HashSet<>();
2072             }
2073 
2074              /**
2075              * For a serializable lambda, generate a disambiguating string
2076              * which maximizes stability across deserialization.
2077              *
2078              * @return String to differentiate synthetic lambda method names
2079              */
2080             private String serializedLambdaDisambiguation() {
2081                 StringBuilder buf = new StringBuilder();
2082                 // Append the enclosing method signature to differentiate
2083                 // overloaded enclosing methods.  For lambdas enclosed in
2084                 // lambdas, the generated lambda method will not have type yet,
2085                 // but the enclosing method's name will have been generated
2086                 // with this same method, so it will be unique and never be
2087                 // overloaded.
2088                 Assert.check(
2089                         owner.type != null ||


2142                 buf.append(Integer.toHexString(disam.hashCode()));
2143                 buf.append('$');
2144                 // The above appended name components may not be unique, append
2145                 // a count based on the above name components.
2146                 buf.append(syntheticMethodNameCounts.getIndex(buf));
2147                 String result = buf.toString();
2148                 //System.err.printf("serializedLambdaName: %s -- %s\n", result, disam);
2149                 return names.fromString(result);
2150             }
2151 
2152             /**
2153              * Translate a symbol of a given kind into something suitable for the
2154              * synthetic lambda body
2155              */
2156             Symbol translate(final Symbol sym, LambdaSymbolKind skind) {
2157                 Symbol ret;
2158                 switch (skind) {
2159                     case CAPTURED_THIS:
2160                         ret = sym;  // self represented
2161                         break;
2162                     case TYPE_VAR:
2163                         // Just erase the type var
2164                         ret = new VarSymbol(sym.flags(), sym.name,
2165                                 types.erasure(sym.type), sym.owner);
2166 
2167                         /* this information should also be kept for LVT generation at Gen
2168                          * a Symbol with pos < startPos won't be tracked.
2169                          */
2170                         ((VarSymbol)ret).pos = ((VarSymbol)sym).pos;
2171                         break;
2172                     case CAPTURED_VAR:
2173                         ret = new VarSymbol(SYNTHETIC | FINAL | PARAMETER, sym.name, types.erasure(sym.type), translatedSym) {
2174                             @Override
2175                             public Symbol baseSymbol() {
2176                                 //keep mapping with original captured symbol
2177                                 return sym;
2178                             }
2179                         };
2180                         break;
2181                     case CAPTURED_OUTER_THIS:
2182                         Name name = names.fromString(new String(sym.flatName().toString().replace('.', '$') + names.dollarThis));
2183                         ret = new VarSymbol(SYNTHETIC | FINAL | PARAMETER, name, types.erasure(sym.type), translatedSym) {
2184                             @Override
2185                             public Symbol baseSymbol() {
2186                                 //keep mapping with original captured symbol
2187                                 return sym;
2188                             }
2189                         };
2190                         break;
2191                     case LOCAL_VAR:


2350             Type generatedLambdaSig() {
2351                 return types.erasure(tree.getDescriptorType(types));
2352             }
2353         }
2354 
2355         /**
2356          * This class retains all the useful information about a method reference;
2357          * the contents of this class are filled by the LambdaAnalyzer visitor,
2358          * and the used by the main translation routines in order to adjust method
2359          * references (i.e. in case a bridge is needed)
2360          */
2361         final class ReferenceTranslationContext extends TranslationContext<JCMemberReference> {
2362 
2363             final boolean isSuper;
2364 
2365             ReferenceTranslationContext(JCMemberReference tree) {
2366                 super(tree);
2367                 this.isSuper = tree.hasKind(ReferenceKind.SUPER);
2368             }
2369 
2370             /**
2371              * Get the opcode associated with this method reference
2372              */
2373             int referenceKind() {
2374                 return LambdaToMethod.this.referenceKind(tree.sym);
2375             }
2376 
2377             boolean needsVarArgsConversion() {
2378                 return tree.varargsElement != null;
2379             }
2380 
2381             /**
2382              * @return Is this an array operation like clone()
2383              */
2384             boolean isArrayOp() {
2385                 return tree.sym.owner == syms.arrayClass;
2386             }
2387 
2388             boolean receiverAccessible() {
2389                 //hack needed to workaround 292 bug (7087658)
2390                 //when 292 issue is fixed we should remove this and change the backend
2391                 //code to always generate a method handle to an accessible method
2392                 return tree.ownerAccessible;
2393             }
2394 
2395             /**
2396              * The VM does not support access across nested classes (8010319).


2455             Type generatedRefSig() {
2456                 return types.erasure(tree.sym.type);
2457             }
2458 
2459             Type bridgedRefSig() {
2460                 return types.erasure(types.findDescriptorSymbol(tree.target.tsym).type);
2461             }
2462         }
2463     }
2464     // </editor-fold>
2465 
2466     /*
2467      * These keys provide mappings for various translated lambda symbols
2468      * and the prevailing order must be maintained.
2469      */
2470     enum LambdaSymbolKind {
2471         PARAM,          // original to translated lambda parameters
2472         LOCAL_VAR,      // original to translated lambda locals
2473         CAPTURED_VAR,   // variables in enclosing scope to translated synthetic parameters
2474         CAPTURED_THIS,  // class symbols to translated synthetic parameters (for captured member access)
2475         CAPTURED_OUTER_THIS, // used when `this' capture is illegal, but outer this capture is legit (JDK-8129740)
2476         TYPE_VAR;      // original to translated lambda type variables
2477 
2478         boolean propagateAnnotations() {
2479             switch (this) {
2480                 case CAPTURED_VAR:
2481                 case CAPTURED_THIS:
2482                 case CAPTURED_OUTER_THIS:
2483                     return false;
2484                 default:
2485                     return true;
2486            }
2487         }
2488     }
2489 
2490     /**
2491      * ****************************************************************
2492      * Signature Generation
2493      * ****************************************************************
2494      */
2495 
2496     private String typeSig(Type type) {


< prev index next >