1 /*
2  * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
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 package com.sun.tools.javac.comp;
26 
27 import com.sun.tools.javac.tree.*;
28 import com.sun.tools.javac.tree.JCTree.*;
29 import com.sun.tools.javac.tree.JCTree.JCMemberReference.ReferenceKind;
30 import com.sun.tools.javac.tree.TreeMaker;
31 import com.sun.tools.javac.tree.TreeTranslator;
32 import com.sun.tools.javac.code.Attribute;
33 import com.sun.tools.javac.code.Kinds;
34 import com.sun.tools.javac.code.Scope;
35 import com.sun.tools.javac.code.Symbol;
36 import com.sun.tools.javac.code.Symbol.ClassSymbol;
37 import com.sun.tools.javac.code.Symbol.DynamicMethodSymbol;
38 import com.sun.tools.javac.code.Symbol.MethodSymbol;
39 import com.sun.tools.javac.code.Symbol.TypeSymbol;
40 import com.sun.tools.javac.code.Symbol.VarSymbol;
41 import com.sun.tools.javac.code.Symtab;
42 import com.sun.tools.javac.code.Type;
43 import com.sun.tools.javac.code.Type.MethodType;
44 import com.sun.tools.javac.code.Type.TypeVar;
45 import com.sun.tools.javac.code.Types;
46 import com.sun.tools.javac.comp.LambdaToMethod.LambdaAnalyzerPreprocessor.*;
47 import com.sun.tools.javac.comp.Lower.BasicFreeVarCollector;
48 import com.sun.tools.javac.jvm.*;
49 import com.sun.tools.javac.util.*;
50 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
51 import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
52 
53 import java.util.EnumMap;
54 import java.util.HashMap;
55 import java.util.HashSet;
56 import java.util.LinkedHashMap;
57 import java.util.Map;
58 import java.util.Set;
59 
60 import static com.sun.tools.javac.comp.LambdaToMethod.LambdaSymbolKind.*;
61 import static com.sun.tools.javac.code.Flags.*;
62 import static com.sun.tools.javac.code.Kinds.*;
63 import static com.sun.tools.javac.code.TypeTag.*;
64 import static com.sun.tools.javac.tree.JCTree.Tag.*;
65 import javax.lang.model.type.TypeKind;
66 
67 /**
68  * This pass desugars lambda expressions into static methods
69  *
70  *  <p><b>This is NOT part of any supported API.
71  *  If you write code that depends on this, you do so at your own risk.
72  *  This code and its internal interfaces are subject to change or
73  *  deletion without notice.</b>
74  */
75 public class LambdaToMethod extends TreeTranslator {
76 
77     private Attr attr;
78     private JCDiagnostic.Factory diags;
79     private Log log;
80     private Lower lower;
81     private Names names;
82     private Symtab syms;
83     private Resolve rs;
84     private TreeMaker make;
85     private Types types;
86     private TransTypes transTypes;
87     private Env<AttrContext> attrEnv;
88 
89     /** the analyzer scanner */
90     private LambdaAnalyzerPreprocessor analyzer;
91 
92     /** map from lambda trees to translation contexts */
93     private Map<JCTree, TranslationContext<?>> contextMap;
94 
95     /** current translation context (visitor argument) */
96     private TranslationContext<?> context;
97 
98     /** info about the current class being processed */
99     private KlassInfo kInfo;
100 
101     /** dump statistics about lambda code generation */
102     private boolean dumpLambdaToMethodStats;
103 
104     /** force serializable representation, for stress testing **/
105     private final boolean forceSerializable;
106 
107     /** Flag for alternate metafactories indicating the lambda object is intended to be serializable */
108     public static final int FLAG_SERIALIZABLE = 1 << 0;
109 
110     /** Flag for alternate metafactories indicating the lambda object has multiple targets */
111     public static final int FLAG_MARKERS = 1 << 1;
112 
113     /** Flag for alternate metafactories indicating the lambda object requires multiple bridges */
114     public static final int FLAG_BRIDGES = 1 << 2;
115 
116     // <editor-fold defaultstate="collapsed" desc="Instantiating">
117     protected static final Context.Key<LambdaToMethod> unlambdaKey =
118             new Context.Key<LambdaToMethod>();
119 
instance(Context context)120     public static LambdaToMethod instance(Context context) {
121         LambdaToMethod instance = context.get(unlambdaKey);
122         if (instance == null) {
123             instance = new LambdaToMethod(context);
124         }
125         return instance;
126     }
LambdaToMethod(Context context)127     private LambdaToMethod(Context context) {
128         context.put(unlambdaKey, this);
129         diags = JCDiagnostic.Factory.instance(context);
130         log = Log.instance(context);
131         lower = Lower.instance(context);
132         names = Names.instance(context);
133         syms = Symtab.instance(context);
134         rs = Resolve.instance(context);
135         make = TreeMaker.instance(context);
136         types = Types.instance(context);
137         transTypes = TransTypes.instance(context);
138         analyzer = new LambdaAnalyzerPreprocessor();
139         Options options = Options.instance(context);
140         dumpLambdaToMethodStats = options.isSet("dumpLambdaToMethodStats");
141         attr = Attr.instance(context);
142         forceSerializable = options.isSet("forceSerializable");
143     }
144     // </editor-fold>
145 
146     private class KlassInfo {
147 
148         /**
149          * list of methods to append
150          */
151         private ListBuffer<JCTree> appendedMethodList;
152 
153         /**
154          * list of deserialization cases
155          */
156         private final Map<String, ListBuffer<JCStatement>> deserializeCases;
157 
158        /**
159          * deserialize method symbol
160          */
161         private final MethodSymbol deserMethodSym;
162 
163         /**
164          * deserialize method parameter symbol
165          */
166         private final VarSymbol deserParamSym;
167 
168         private final JCClassDecl clazz;
169 
KlassInfo(JCClassDecl clazz)170         private KlassInfo(JCClassDecl clazz) {
171             this.clazz = clazz;
172             appendedMethodList = new ListBuffer<>();
173             deserializeCases = new HashMap<String, ListBuffer<JCStatement>>();
174             MethodType type = new MethodType(List.of(syms.serializedLambdaType), syms.objectType,
175                     List.<Type>nil(), syms.methodClass);
176             deserMethodSym = makePrivateSyntheticMethod(STATIC, names.deserializeLambda, type, clazz.sym);
177             deserParamSym = new VarSymbol(FINAL, names.fromString("lambda"),
178                     syms.serializedLambdaType, deserMethodSym);
179         }
180 
addMethod(JCTree decl)181         private void addMethod(JCTree decl) {
182             appendedMethodList = appendedMethodList.prepend(decl);
183         }
184     }
185 
186     // <editor-fold defaultstate="collapsed" desc="translate methods">
187     @Override
translate(T tree)188     public <T extends JCTree> T translate(T tree) {
189         TranslationContext<?> newContext = contextMap.get(tree);
190         return translate(tree, newContext != null ? newContext : context);
191     }
192 
translate(T tree, TranslationContext<?> newContext)193     <T extends JCTree> T translate(T tree, TranslationContext<?> newContext) {
194         TranslationContext<?> prevContext = context;
195         try {
196             context = newContext;
197             return super.translate(tree);
198         }
199         finally {
200             context = prevContext;
201         }
202     }
203 
translate(List<T> trees, TranslationContext<?> newContext)204     <T extends JCTree> List<T> translate(List<T> trees, TranslationContext<?> newContext) {
205         ListBuffer<T> buf = new ListBuffer<>();
206         for (T tree : trees) {
207             buf.append(translate(tree, newContext));
208         }
209         return buf.toList();
210     }
211 
translateTopLevelClass(Env<AttrContext> env, JCTree cdef, TreeMaker make)212     public JCTree translateTopLevelClass(Env<AttrContext> env, JCTree cdef, TreeMaker make) {
213         this.make = make;
214         this.attrEnv = env;
215         this.context = null;
216         this.contextMap = new HashMap<JCTree, TranslationContext<?>>();
217         return translate(cdef);
218     }
219     // </editor-fold>
220 
221     // <editor-fold defaultstate="collapsed" desc="visitor methods">
222     /**
223      * Visit a class.
224      * Maintain the translatedMethodList across nested classes.
225      * Append the translatedMethodList to the class after it is translated.
226      * @param tree
227      */
228     @Override
visitClassDef(JCClassDecl tree)229     public void visitClassDef(JCClassDecl tree) {
230         if (tree.sym.owner.kind == PCK) {
231             //analyze class
232             tree = analyzer.analyzeAndPreprocessClass(tree);
233         }
234         KlassInfo prevKlassInfo = kInfo;
235         try {
236             kInfo = new KlassInfo(tree);
237             super.visitClassDef(tree);
238             if (!kInfo.deserializeCases.isEmpty()) {
239                 int prevPos = make.pos;
240                 try {
241                     make.at(tree);
242                     kInfo.addMethod(makeDeserializeMethod(tree.sym));
243                 } finally {
244                     make.at(prevPos);
245                 }
246             }
247             //add all translated instance methods here
248             List<JCTree> newMethods = kInfo.appendedMethodList.toList();
249             tree.defs = tree.defs.appendList(newMethods);
250             for (JCTree lambda : newMethods) {
251                 tree.sym.members().enter(((JCMethodDecl)lambda).sym);
252             }
253             result = tree;
254         } finally {
255             kInfo = prevKlassInfo;
256         }
257     }
258 
259     /**
260      * Translate a lambda into a method to be inserted into the class.
261      * Then replace the lambda site with an invokedynamic call of to lambda
262      * meta-factory, which will use the lambda method.
263      * @param tree
264      */
265     @Override
visitLambda(JCLambda tree)266     public void visitLambda(JCLambda tree) {
267         LambdaTranslationContext localContext = (LambdaTranslationContext)context;
268         MethodSymbol sym = localContext.translatedSym;
269         MethodType lambdaType = (MethodType) sym.type;
270 
271         {
272             Symbol owner = localContext.owner;
273             ListBuffer<Attribute.TypeCompound> ownerTypeAnnos = new ListBuffer<Attribute.TypeCompound>();
274             ListBuffer<Attribute.TypeCompound> lambdaTypeAnnos = new ListBuffer<Attribute.TypeCompound>();
275 
276             for (Attribute.TypeCompound tc : owner.getRawTypeAttributes()) {
277                 if (tc.position.onLambda == tree) {
278                     lambdaTypeAnnos.append(tc);
279                 } else {
280                     ownerTypeAnnos.append(tc);
281                 }
282             }
283             if (lambdaTypeAnnos.nonEmpty()) {
284                 owner.setTypeAttributes(ownerTypeAnnos.toList());
285                 sym.setTypeAttributes(lambdaTypeAnnos.toList());
286             }
287         }
288 
289         //create the method declaration hoisting the lambda body
290         JCMethodDecl lambdaDecl = make.MethodDef(make.Modifiers(sym.flags_field),
291                 sym.name,
292                 make.QualIdent(lambdaType.getReturnType().tsym),
293                 List.<JCTypeParameter>nil(),
294                 localContext.syntheticParams,
295                 lambdaType.getThrownTypes() == null ?
296                     List.<JCExpression>nil() :
297                     make.Types(lambdaType.getThrownTypes()),
298                 null,
299                 null);
300         lambdaDecl.sym = sym;
301         lambdaDecl.type = lambdaType;
302 
303         //translate lambda body
304         //As the lambda body is translated, all references to lambda locals,
305         //captured variables, enclosing members are adjusted accordingly
306         //to refer to the static method parameters (rather than i.e. acessing to
307         //captured members directly).
308         lambdaDecl.body = translate(makeLambdaBody(tree, lambdaDecl));
309 
310         //Add the method to the list of methods to be added to this class.
311         kInfo.addMethod(lambdaDecl);
312 
313         //now that we have generated a method for the lambda expression,
314         //we can translate the lambda into a method reference pointing to the newly
315         //created method.
316         //
317         //Note that we need to adjust the method handle so that it will match the
318         //signature of the SAM descriptor - this means that the method reference
319         //should be added the following synthetic arguments:
320         //
321         // * the "this" argument if it is an instance method
322         // * enclosing locals captured by the lambda expression
323 
324         ListBuffer<JCExpression> syntheticInits = new ListBuffer<>();
325 
326         if (localContext.methodReferenceReceiver != null) {
327             syntheticInits.append(localContext.methodReferenceReceiver);
328         } else if (!sym.isStatic()) {
329             syntheticInits.append(makeThis(
330                     sym.owner.enclClass().asType(),
331                     localContext.owner.enclClass()));
332         }
333 
334         //add captured locals
335         for (Symbol fv : localContext.getSymbolMap(CAPTURED_VAR).keySet()) {
336             if (fv != localContext.self) {
337                 JCTree captured_local = make.Ident(fv).setType(fv.type);
338                 syntheticInits.append((JCExpression) captured_local);
339             }
340         }
341         // add captured outer this instances (used only when `this' capture itself is illegal)
342         for (Symbol fv : localContext.getSymbolMap(CAPTURED_OUTER_THIS).keySet()) {
343             JCTree captured_local = make.QualThis(fv.type);
344             syntheticInits.append((JCExpression) captured_local);
345         }
346 
347         //then, determine the arguments to the indy call
348         List<JCExpression> indy_args = translate(syntheticInits.toList(), localContext.prev);
349 
350         //build a sam instance using an indy call to the meta-factory
351         int refKind = referenceKind(sym);
352 
353         //convert to an invokedynamic call
354         result = makeMetafactoryIndyCall(context, refKind, sym, indy_args);
355     }
356 
makeThis(Type type, Symbol owner)357     private JCIdent makeThis(Type type, Symbol owner) {
358         VarSymbol _this = new VarSymbol(PARAMETER | FINAL | SYNTHETIC,
359                 names._this,
360                 type,
361                 owner);
362         return make.Ident(_this);
363     }
364 
365     /**
366      * Translate a method reference into an invokedynamic call to the
367      * meta-factory.
368      * @param tree
369      */
370     @Override
visitReference(JCMemberReference tree)371     public void visitReference(JCMemberReference tree) {
372         ReferenceTranslationContext localContext = (ReferenceTranslationContext)context;
373 
374         //first determine the method symbol to be used to generate the sam instance
375         //this is either the method reference symbol, or the bridged reference symbol
376         Symbol refSym = localContext.isSignaturePolymorphic()
377                 ? localContext.sigPolySym
378                 : tree.sym;
379 
380         //the qualifying expression is treated as a special captured arg
381         JCExpression init;
382         switch(tree.kind) {
383 
384             case IMPLICIT_INNER:    /** Inner :: new */
385             case SUPER:             /** super :: instMethod */
386                 init = makeThis(
387                     localContext.owner.enclClass().asType(),
388                     localContext.owner.enclClass());
389                 break;
390 
391             case BOUND:             /** Expr :: instMethod */
392                 init = tree.getQualifierExpression();
393                 init = attr.makeNullCheck(init);
394                 break;
395 
396             case UNBOUND:           /** Type :: instMethod */
397             case STATIC:            /** Type :: staticMethod */
398             case TOPLEVEL:          /** Top level :: new */
399             case ARRAY_CTOR:        /** ArrayType :: new */
400                 init = null;
401                 break;
402 
403             default:
404                 throw new InternalError("Should not have an invalid kind");
405         }
406 
407         List<JCExpression> indy_args = init==null? List.<JCExpression>nil() : translate(List.of(init), localContext.prev);
408 
409 
410         //build a sam instance using an indy call to the meta-factory
411         result = makeMetafactoryIndyCall(localContext, localContext.referenceKind(), refSym, indy_args);
412     }
413 
414     /**
415      * Translate identifiers within a lambda to the mapped identifier
416      * @param tree
417      */
418     @Override
visitIdent(JCIdent tree)419     public void visitIdent(JCIdent tree) {
420         if (context == null || !analyzer.lambdaIdentSymbolFilter(tree.sym)) {
421             super.visitIdent(tree);
422         } else {
423             int prevPos = make.pos;
424             try {
425                 make.at(tree);
426 
427                 LambdaTranslationContext lambdaContext = (LambdaTranslationContext) context;
428                 JCTree ltree = lambdaContext.translate(tree);
429                 if (ltree != null) {
430                     result = ltree;
431                 } else {
432                     //access to untranslated symbols (i.e. compile-time constants,
433                     //members defined inside the lambda body, etc.) )
434                     super.visitIdent(tree);
435                 }
436             } finally {
437                 make.at(prevPos);
438             }
439         }
440     }
441 
442     /**
443      * Translate qualified `this' references within a lambda to the mapped identifier
444      * @param tree
445      */
446     @Override
visitSelect(JCFieldAccess tree)447     public void visitSelect(JCFieldAccess tree) {
448         if (context == null || !analyzer.lambdaFieldAccessFilter(tree)) {
449             super.visitSelect(tree);
450         } else {
451             int prevPos = make.pos;
452             try {
453                 make.at(tree);
454 
455                 LambdaTranslationContext lambdaContext = (LambdaTranslationContext) context;
456                 JCTree ltree = lambdaContext.translate(tree);
457                 if (ltree != null) {
458                     result = ltree;
459                 } else {
460                     super.visitSelect(tree);
461                 }
462             } finally {
463                 make.at(prevPos);
464             }
465         }
466     }
467 
468     @Override
visitVarDef(JCVariableDecl tree)469     public void visitVarDef(JCVariableDecl tree) {
470         LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context;
471         if (context != null && lambdaContext.getSymbolMap(LOCAL_VAR).containsKey(tree.sym)) {
472             tree.init = translate(tree.init);
473             tree.sym = (VarSymbol) lambdaContext.getSymbolMap(LOCAL_VAR).get(tree.sym);
474             result = tree;
475         } else if (context != null && lambdaContext.getSymbolMap(TYPE_VAR).containsKey(tree.sym)) {
476             JCExpression init = translate(tree.init);
477             VarSymbol xsym = (VarSymbol)lambdaContext.getSymbolMap(TYPE_VAR).get(tree.sym);
478             int prevPos = make.pos;
479             try {
480                 result = make.at(tree).VarDef(xsym, init);
481             } finally {
482                 make.at(prevPos);
483             }
484             // Replace the entered symbol for this variable
485             Scope sc = tree.sym.owner.members();
486             if (sc != null) {
487                 sc.remove(tree.sym);
488                 sc.enter(xsym);
489             }
490         } else {
491             super.visitVarDef(tree);
492         }
493     }
494 
495     // </editor-fold>
496 
497     // <editor-fold defaultstate="collapsed" desc="Translation helper methods">
498 
makeLambdaBody(JCLambda tree, JCMethodDecl lambdaMethodDecl)499     private JCBlock makeLambdaBody(JCLambda tree, JCMethodDecl lambdaMethodDecl) {
500         return tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION ?
501                 makeLambdaExpressionBody((JCExpression)tree.body, lambdaMethodDecl) :
502                 makeLambdaStatementBody((JCBlock)tree.body, lambdaMethodDecl, tree.canCompleteNormally);
503     }
504 
makeLambdaExpressionBody(JCExpression expr, JCMethodDecl lambdaMethodDecl)505     private JCBlock makeLambdaExpressionBody(JCExpression expr, JCMethodDecl lambdaMethodDecl) {
506         Type restype = lambdaMethodDecl.type.getReturnType();
507         boolean isLambda_void = expr.type.hasTag(VOID);
508         boolean isTarget_void = restype.hasTag(VOID);
509         boolean isTarget_Void = types.isSameType(restype, types.boxedClass(syms.voidType).type);
510         int prevPos = make.pos;
511         try {
512             if (isTarget_void) {
513                 //target is void:
514                 // BODY;
515                 JCStatement stat = make.at(expr).Exec(expr);
516                 return make.Block(0, List.<JCStatement>of(stat));
517             } else if (isLambda_void && isTarget_Void) {
518                 //void to Void conversion:
519                 // BODY; return null;
520                 ListBuffer<JCStatement> stats = new ListBuffer<>();
521                 stats.append(make.at(expr).Exec(expr));
522                 stats.append(make.Return(make.Literal(BOT, null).setType(syms.botType)));
523                 return make.Block(0, stats.toList());
524             } else {
525                 //non-void to non-void conversion:
526                 // return (TYPE)BODY;
527                 JCExpression retExpr = transTypes.coerce(attrEnv, expr, restype);
528                 return make.at(retExpr).Block(0, List.<JCStatement>of(make.Return(retExpr)));
529             }
530         } finally {
531             make.at(prevPos);
532         }
533     }
534 
makeLambdaStatementBody(JCBlock block, final JCMethodDecl lambdaMethodDecl, boolean completeNormally)535     private JCBlock makeLambdaStatementBody(JCBlock block, final JCMethodDecl lambdaMethodDecl, boolean completeNormally) {
536         final Type restype = lambdaMethodDecl.type.getReturnType();
537         final boolean isTarget_void = restype.hasTag(VOID);
538         boolean isTarget_Void = types.isSameType(restype, types.boxedClass(syms.voidType).type);
539 
540         class LambdaBodyTranslator extends TreeTranslator {
541 
542             @Override
543             public void visitClassDef(JCClassDecl tree) {
544                 //do NOT recurse on any inner classes
545                 result = tree;
546             }
547 
548             @Override
549             public void visitLambda(JCLambda tree) {
550                 //do NOT recurse on any nested lambdas
551                 result = tree;
552             }
553 
554             @Override
555             public void visitReturn(JCReturn tree) {
556                 boolean isLambda_void = tree.expr == null;
557                 if (isTarget_void && !isLambda_void) {
558                     //Void to void conversion:
559                     // { TYPE $loc = RET-EXPR; return; }
560                     VarSymbol loc = makeSyntheticVar(0, names.fromString("$loc"), tree.expr.type, lambdaMethodDecl.sym);
561                     JCVariableDecl varDef = make.VarDef(loc, tree.expr);
562                     result = make.Block(0, List.<JCStatement>of(varDef, make.Return(null)));
563                 } else if (!isTarget_void || !isLambda_void) {
564                     //non-void to non-void conversion:
565                     // return (TYPE)RET-EXPR;
566                     tree.expr = transTypes.coerce(attrEnv, tree.expr, restype);
567                     result = tree;
568                 } else {
569                     result = tree;
570                 }
571 
572             }
573         }
574 
575         JCBlock trans_block = new LambdaBodyTranslator().translate(block);
576         if (completeNormally && isTarget_Void) {
577             //there's no return statement and the lambda (possibly inferred)
578             //return type is java.lang.Void; emit a synthetic return statement
579             trans_block.stats = trans_block.stats.append(make.Return(make.Literal(BOT, null).setType(syms.botType)));
580         }
581         return trans_block;
582     }
583 
makeDeserializeMethod(Symbol kSym)584     private JCMethodDecl makeDeserializeMethod(Symbol kSym) {
585         ListBuffer<JCCase> cases = new ListBuffer<>();
586         ListBuffer<JCBreak> breaks = new ListBuffer<>();
587         for (Map.Entry<String, ListBuffer<JCStatement>> entry : kInfo.deserializeCases.entrySet()) {
588             JCBreak br = make.Break(null);
589             breaks.add(br);
590             List<JCStatement> stmts = entry.getValue().append(br).toList();
591             cases.add(make.Case(make.Literal(entry.getKey()), stmts));
592         }
593         JCSwitch sw = make.Switch(deserGetter("getImplMethodName", syms.stringType), cases.toList());
594         for (JCBreak br : breaks) {
595             br.target = sw;
596         }
597         JCBlock body = make.Block(0L, List.<JCStatement>of(
598                 sw,
599                 make.Throw(makeNewClass(
600                     syms.illegalArgumentExceptionType,
601                     List.<JCExpression>of(make.Literal("Invalid lambda deserialization"))))));
602         JCMethodDecl deser = make.MethodDef(make.Modifiers(kInfo.deserMethodSym.flags()),
603                         names.deserializeLambda,
604                         make.QualIdent(kInfo.deserMethodSym.getReturnType().tsym),
605                         List.<JCTypeParameter>nil(),
606                         List.of(make.VarDef(kInfo.deserParamSym, null)),
607                         List.<JCExpression>nil(),
608                         body,
609                         null);
610         deser.sym = kInfo.deserMethodSym;
611         deser.type = kInfo.deserMethodSym.type;
612         //System.err.printf("DESER: '%s'\n", deser);
613         return deser;
614     }
615 
616     /** Make an attributed class instance creation expression.
617      *  @param ctype    The class type.
618      *  @param args     The constructor arguments.
619      *  @param cons     The constructor symbol
620      */
makeNewClass(Type ctype, List<JCExpression> args, Symbol cons)621     JCNewClass makeNewClass(Type ctype, List<JCExpression> args, Symbol cons) {
622         JCNewClass tree = make.NewClass(null,
623             null, make.QualIdent(ctype.tsym), args, null);
624         tree.constructor = cons;
625         tree.type = ctype;
626         return tree;
627     }
628 
629     /** Make an attributed class instance creation expression.
630      *  @param ctype    The class type.
631      *  @param args     The constructor arguments.
632      */
makeNewClass(Type ctype, List<JCExpression> args)633     JCNewClass makeNewClass(Type ctype, List<JCExpression> args) {
634         return makeNewClass(ctype, args,
635                 rs.resolveConstructor(null, attrEnv, ctype, TreeInfo.types(args), List.<Type>nil()));
636      }
637 
addDeserializationCase(int implMethodKind, Symbol refSym, Type targetType, MethodSymbol samSym, DiagnosticPosition pos, List<Object> staticArgs, MethodType indyType)638     private void addDeserializationCase(int implMethodKind, Symbol refSym, Type targetType, MethodSymbol samSym,
639             DiagnosticPosition pos, List<Object> staticArgs, MethodType indyType) {
640         String functionalInterfaceClass = classSig(targetType);
641         String functionalInterfaceMethodName = samSym.getSimpleName().toString();
642         String functionalInterfaceMethodSignature = typeSig(types.erasure(samSym.type));
643         String implClass = classSig(types.erasure(refSym.owner.type));
644         String implMethodName = refSym.getQualifiedName().toString();
645         String implMethodSignature = typeSig(types.erasure(refSym.type));
646 
647         JCExpression kindTest = eqTest(syms.intType, deserGetter("getImplMethodKind", syms.intType), make.Literal(implMethodKind));
648         ListBuffer<JCExpression> serArgs = new ListBuffer<>();
649         int i = 0;
650         for (Type t : indyType.getParameterTypes()) {
651             List<JCExpression> indexAsArg = new ListBuffer<JCExpression>().append(make.Literal(i)).toList();
652             List<Type> argTypes = new ListBuffer<Type>().append(syms.intType).toList();
653             serArgs.add(make.TypeCast(types.erasure(t), deserGetter("getCapturedArg", syms.objectType, argTypes, indexAsArg)));
654             ++i;
655         }
656         JCStatement stmt = make.If(
657                 deserTest(deserTest(deserTest(deserTest(deserTest(
658                     kindTest,
659                     "getFunctionalInterfaceClass", functionalInterfaceClass),
660                     "getFunctionalInterfaceMethodName", functionalInterfaceMethodName),
661                     "getFunctionalInterfaceMethodSignature", functionalInterfaceMethodSignature),
662                     "getImplClass", implClass),
663                     "getImplMethodSignature", implMethodSignature),
664                 make.Return(makeIndyCall(
665                     pos,
666                     syms.lambdaMetafactory,
667                     names.altMetafactory,
668                     staticArgs, indyType, serArgs.toList(), samSym.name)),
669                 null);
670         ListBuffer<JCStatement> stmts = kInfo.deserializeCases.get(implMethodName);
671         if (stmts == null) {
672             stmts = new ListBuffer<>();
673             kInfo.deserializeCases.put(implMethodName, stmts);
674         }
675         /****
676         System.err.printf("+++++++++++++++++\n");
677         System.err.printf("*functionalInterfaceClass: '%s'\n", functionalInterfaceClass);
678         System.err.printf("*functionalInterfaceMethodName: '%s'\n", functionalInterfaceMethodName);
679         System.err.printf("*functionalInterfaceMethodSignature: '%s'\n", functionalInterfaceMethodSignature);
680         System.err.printf("*implMethodKind: %d\n", implMethodKind);
681         System.err.printf("*implClass: '%s'\n", implClass);
682         System.err.printf("*implMethodName: '%s'\n", implMethodName);
683         System.err.printf("*implMethodSignature: '%s'\n", implMethodSignature);
684         ****/
685         stmts.append(stmt);
686     }
687 
eqTest(Type argType, JCExpression arg1, JCExpression arg2)688     private JCExpression eqTest(Type argType, JCExpression arg1, JCExpression arg2) {
689         JCBinary testExpr = make.Binary(JCTree.Tag.EQ, arg1, arg2);
690         testExpr.operator = rs.resolveBinaryOperator(null, JCTree.Tag.EQ, attrEnv, argType, argType);
691         testExpr.setType(syms.booleanType);
692         return testExpr;
693     }
694 
deserTest(JCExpression prev, String func, String lit)695     private JCExpression deserTest(JCExpression prev, String func, String lit) {
696         MethodType eqmt = new MethodType(List.of(syms.objectType), syms.booleanType, List.<Type>nil(), syms.methodClass);
697         Symbol eqsym = rs.resolveQualifiedMethod(null, attrEnv, syms.objectType, names.equals, List.of(syms.objectType), List.<Type>nil());
698         JCMethodInvocation eqtest = make.Apply(
699                 List.<JCExpression>nil(),
700                 make.Select(deserGetter(func, syms.stringType), eqsym).setType(eqmt),
701                 List.<JCExpression>of(make.Literal(lit)));
702         eqtest.setType(syms.booleanType);
703         JCBinary compound = make.Binary(JCTree.Tag.AND, prev, eqtest);
704         compound.operator = rs.resolveBinaryOperator(null, JCTree.Tag.AND, attrEnv, syms.booleanType, syms.booleanType);
705         compound.setType(syms.booleanType);
706         return compound;
707     }
708 
deserGetter(String func, Type type)709     private JCExpression deserGetter(String func, Type type) {
710         return deserGetter(func, type, List.<Type>nil(), List.<JCExpression>nil());
711     }
712 
deserGetter(String func, Type type, List<Type> argTypes, List<JCExpression> args)713     private JCExpression deserGetter(String func, Type type, List<Type> argTypes, List<JCExpression> args) {
714         MethodType getmt = new MethodType(argTypes, type, List.<Type>nil(), syms.methodClass);
715         Symbol getsym = rs.resolveQualifiedMethod(null, attrEnv, syms.serializedLambdaType, names.fromString(func), argTypes, List.<Type>nil());
716         return make.Apply(
717                     List.<JCExpression>nil(),
718                     make.Select(make.Ident(kInfo.deserParamSym).setType(syms.serializedLambdaType), getsym).setType(getmt),
719                     args).setType(type);
720     }
721 
722     /**
723      * Create new synthetic method with given flags, name, type, owner
724      */
makePrivateSyntheticMethod(long flags, Name name, Type type, Symbol owner)725     private MethodSymbol makePrivateSyntheticMethod(long flags, Name name, Type type, Symbol owner) {
726         return new MethodSymbol(flags | SYNTHETIC | PRIVATE, name, type, owner);
727     }
728 
729     /**
730      * Create new synthetic variable with given flags, name, type, owner
731      */
makeSyntheticVar(long flags, String name, Type type, Symbol owner)732     private VarSymbol makeSyntheticVar(long flags, String name, Type type, Symbol owner) {
733         return makeSyntheticVar(flags, names.fromString(name), type, owner);
734     }
735 
736     /**
737      * Create new synthetic variable with given flags, name, type, owner
738      */
makeSyntheticVar(long flags, Name name, Type type, Symbol owner)739     private VarSymbol makeSyntheticVar(long flags, Name name, Type type, Symbol owner) {
740         return new VarSymbol(flags | SYNTHETIC, name, type, owner);
741     }
742 
743     /**
744      * Set varargsElement field on a given tree (must be either a new class tree
745      * or a method call tree)
746      */
setVarargsIfNeeded(JCTree tree, Type varargsElement)747     private void setVarargsIfNeeded(JCTree tree, Type varargsElement) {
748         if (varargsElement != null) {
749             switch (tree.getTag()) {
750                 case APPLY: ((JCMethodInvocation)tree).varargsElement = varargsElement; break;
751                 case NEWCLASS: ((JCNewClass)tree).varargsElement = varargsElement; break;
752                 default: throw new AssertionError();
753             }
754         }
755     }
756 
757     /**
758      * Convert method/constructor arguments by inserting appropriate cast
759      * as required by type-erasure - this is needed when bridging a lambda/method
760      * reference, as the bridged signature might require downcast to be compatible
761      * with the generated signature.
762      */
convertArgs(Symbol meth, List<JCExpression> args, Type varargsElement)763     private List<JCExpression> convertArgs(Symbol meth, List<JCExpression> args, Type varargsElement) {
764        Assert.check(meth.kind == Kinds.MTH);
765        List<Type> formals = types.erasure(meth.type).getParameterTypes();
766        if (varargsElement != null) {
767            Assert.check((meth.flags() & VARARGS) != 0);
768        }
769        return transTypes.translateArgs(args, formals, varargsElement, attrEnv);
770     }
771 
772     // </editor-fold>
773 
774     /**
775      * Converts a method reference which cannot be used directly into a lambda
776      */
777     private class MemberReferenceToLambda {
778 
779         private final JCMemberReference tree;
780         private final ReferenceTranslationContext localContext;
781         private final Symbol owner;
782         private final ListBuffer<JCExpression> args = new ListBuffer<>();
783         private final ListBuffer<JCVariableDecl> params = new ListBuffer<>();
784 
785         private JCExpression receiverExpression = null;
786 
MemberReferenceToLambda(JCMemberReference tree, ReferenceTranslationContext localContext, Symbol owner)787         MemberReferenceToLambda(JCMemberReference tree, ReferenceTranslationContext localContext, Symbol owner) {
788             this.tree = tree;
789             this.localContext = localContext;
790             this.owner = owner;
791         }
792 
lambda()793         JCLambda lambda() {
794             int prevPos = make.pos;
795             try {
796                 make.at(tree);
797 
798                 //body generation - this can be either a method call or a
799                 //new instance creation expression, depending on the member reference kind
800                 VarSymbol rcvr = addParametersReturnReceiver();
801                 JCExpression expr = (tree.getMode() == ReferenceMode.INVOKE)
802                         ? expressionInvoke(rcvr)
803                         : expressionNew();
804 
805                 JCLambda slam = make.Lambda(params.toList(), expr);
806                 slam.targets = tree.targets;
807                 slam.type = tree.type;
808                 slam.pos = tree.pos;
809                 return slam;
810             } finally {
811                 make.at(prevPos);
812             }
813         }
814 
815         /**
816          * Generate the parameter list for the converted member reference.
817          *
818          * @return The receiver variable symbol, if any
819          */
addParametersReturnReceiver()820         VarSymbol addParametersReturnReceiver() {
821             Type samDesc = localContext.bridgedRefSig();
822             List<Type> samPTypes = samDesc.getParameterTypes();
823             List<Type> descPTypes = tree.getDescriptorType(types).getParameterTypes();
824 
825             // Determine the receiver, if any
826             VarSymbol rcvr;
827             switch (tree.kind) {
828                 case BOUND:
829                     // The receiver is explicit in the method reference
830                     rcvr = addParameter("rec$", tree.getQualifierExpression().type, false);
831                     receiverExpression = attr.makeNullCheck(tree.getQualifierExpression());
832                     break;
833                 case UNBOUND:
834                     // The receiver is the first parameter, extract it and
835                     // adjust the SAM and unerased type lists accordingly
836                     rcvr = addParameter("rec$", samDesc.getParameterTypes().head, false);
837                     samPTypes = samPTypes.tail;
838                     descPTypes = descPTypes.tail;
839                     break;
840                 default:
841                     rcvr = null;
842                     break;
843             }
844             List<Type> implPTypes = tree.sym.type.getParameterTypes();
845             int implSize = implPTypes.size();
846             int samSize = samPTypes.size();
847             // Last parameter to copy from referenced method, exclude final var args
848             int last = localContext.needsVarArgsConversion() ? implSize - 1 : implSize;
849 
850             // Failsafe -- assure match-up
851             boolean checkForIntersection = tree.varargsElement != null || implSize == descPTypes.size();
852 
853             // Use parameter types of the implementation method unless the unerased
854             // SAM parameter type is an intersection type, in that case use the
855             // erased SAM parameter type so that the supertype relationship
856             // the implementation method parameters is not obscured.
857             // Note: in this loop, the lists implPTypes, samPTypes, and descPTypes
858             // are used as pointers to the current parameter type information
859             // and are thus not usable afterwards.
860             for (int i = 0; implPTypes.nonEmpty() && i < last; ++i) {
861                 // By default use the implementation method parmeter type
862                 Type parmType = implPTypes.head;
863                 // If the unerased parameter type is a type variable whose
864                 // bound is an intersection (eg. <T extends A & B>) then
865                 // use the SAM parameter type
866                 if (checkForIntersection && descPTypes.head.getKind() == TypeKind.TYPEVAR) {
867                     TypeVar tv = (TypeVar) descPTypes.head;
868                     if (tv.bound.getKind() == TypeKind.INTERSECTION) {
869                         parmType = samPTypes.head;
870                     }
871                 }
872                 addParameter("x$" + i, parmType, true);
873 
874                 // Advance to the next parameter
875                 implPTypes = implPTypes.tail;
876                 samPTypes = samPTypes.tail;
877                 descPTypes = descPTypes.tail;
878             }
879             // Flatten out the var args
880             for (int i = last; i < samSize; ++i) {
881                 addParameter("xva$" + i, tree.varargsElement, true);
882             }
883 
884             return rcvr;
885         }
886 
getReceiverExpression()887         JCExpression getReceiverExpression() {
888             return receiverExpression;
889         }
890 
makeReceiver(VarSymbol rcvr)891         private JCExpression makeReceiver(VarSymbol rcvr) {
892             if (rcvr == null) return null;
893             JCExpression rcvrExpr = make.Ident(rcvr);
894             Type rcvrType = tree.ownerAccessible ? tree.sym.enclClass().type : tree.expr.type;
895             if (rcvrType == syms.arrayClass.type) {
896                 // Map the receiver type to the actually type, not just "array"
897                 rcvrType = tree.getQualifierExpression().type;
898             }
899             if (!rcvr.type.tsym.isSubClass(rcvrType.tsym, types)) {
900                 rcvrExpr = make.TypeCast(make.Type(rcvrType), rcvrExpr).setType(rcvrType);
901             }
902             return rcvrExpr;
903         }
904 
905         /**
906          * determine the receiver of the method call - the receiver can
907          * be a type qualifier, the synthetic receiver parameter or 'super'.
908          */
expressionInvoke(VarSymbol rcvr)909         private JCExpression expressionInvoke(VarSymbol rcvr) {
910             JCExpression qualifier =
911                     (rcvr != null) ?
912                         makeReceiver(rcvr) :
913                         tree.getQualifierExpression();
914 
915             //create the qualifier expression
916             JCFieldAccess select = make.Select(qualifier, tree.sym.name);
917             select.sym = tree.sym;
918             select.type = tree.sym.erasure(types);
919 
920             //create the method call expression
921             JCExpression apply = make.Apply(List.<JCExpression>nil(), select,
922                     convertArgs(tree.sym, args.toList(), tree.varargsElement)).
923                     setType(tree.sym.erasure(types).getReturnType());
924 
925             apply = transTypes.coerce(apply, localContext.generatedRefSig().getReturnType());
926             setVarargsIfNeeded(apply, tree.varargsElement);
927             return apply;
928         }
929 
930         /**
931          * Lambda body to use for a 'new'.
932          */
expressionNew()933         private JCExpression expressionNew() {
934             if (tree.kind == ReferenceKind.ARRAY_CTOR) {
935                 //create the array creation expression
936                 JCNewArray newArr = make.NewArray(
937                         make.Type(types.elemtype(tree.getQualifierExpression().type)),
938                         List.of(make.Ident(params.first())),
939                         null);
940                 newArr.type = tree.getQualifierExpression().type;
941                 return newArr;
942             } else {
943                 //create the instance creation expression
944                 //note that method reference syntax does not allow an explicit
945                 //enclosing class (so the enclosing class is null)
946                 JCNewClass newClass = make.NewClass(null,
947                         List.<JCExpression>nil(),
948                         make.Type(tree.getQualifierExpression().type),
949                         convertArgs(tree.sym, args.toList(), tree.varargsElement),
950                         null);
951                 newClass.constructor = tree.sym;
952                 newClass.constructorType = tree.sym.erasure(types);
953                 newClass.type = tree.getQualifierExpression().type;
954                 setVarargsIfNeeded(newClass, tree.varargsElement);
955                 return newClass;
956             }
957         }
958 
addParameter(String name, Type p, boolean genArg)959         private VarSymbol addParameter(String name, Type p, boolean genArg) {
960             VarSymbol vsym = new VarSymbol(PARAMETER | SYNTHETIC, names.fromString(name), p, owner);
961             vsym.pos = tree.pos;
962             params.append(make.VarDef(vsym, null));
963             if (genArg) {
964                 args.append(make.Ident(vsym));
965             }
966             return vsym;
967         }
968     }
969 
typeToMethodType(Type mt)970     private MethodType typeToMethodType(Type mt) {
971         Type type = types.erasure(mt);
972         return new MethodType(type.getParameterTypes(),
973                         type.getReturnType(),
974                         type.getThrownTypes(),
975                         syms.methodClass);
976     }
977 
978     /**
979      * Generate an indy method call to the meta factory
980      */
makeMetafactoryIndyCall(TranslationContext<?> context, int refKind, Symbol refSym, List<JCExpression> indy_args)981     private JCExpression makeMetafactoryIndyCall(TranslationContext<?> context,
982             int refKind, Symbol refSym, List<JCExpression> indy_args) {
983         JCFunctionalExpression tree = context.tree;
984         //determine the static bsm args
985         MethodSymbol samSym = (MethodSymbol) types.findDescriptorSymbol(tree.type.tsym);
986         List<Object> staticArgs = List.<Object>of(
987                 typeToMethodType(samSym.type),
988                 new Pool.MethodHandle(refKind, refSym, types),
989                 typeToMethodType(tree.getDescriptorType(types)));
990 
991         //computed indy arg types
992         ListBuffer<Type> indy_args_types = new ListBuffer<>();
993         for (JCExpression arg : indy_args) {
994             indy_args_types.append(arg.type);
995         }
996 
997         //finally, compute the type of the indy call
998         MethodType indyType = new MethodType(indy_args_types.toList(),
999                 tree.type,
1000                 List.<Type>nil(),
1001                 syms.methodClass);
1002 
1003         Name metafactoryName = context.needsAltMetafactory() ?
1004                 names.altMetafactory : names.metafactory;
1005 
1006         if (context.needsAltMetafactory()) {
1007             ListBuffer<Object> markers = new ListBuffer<>();
1008             for (Type t : tree.targets.tail) {
1009                 if (t.tsym != syms.serializableType.tsym) {
1010                     markers.append(t.tsym);
1011                 }
1012             }
1013             int flags = context.isSerializable() ? FLAG_SERIALIZABLE : 0;
1014             boolean hasMarkers = markers.nonEmpty();
1015             boolean hasBridges = context.bridges.nonEmpty();
1016             if (hasMarkers) {
1017                 flags |= FLAG_MARKERS;
1018             }
1019             if (hasBridges) {
1020                 flags |= FLAG_BRIDGES;
1021             }
1022             staticArgs = staticArgs.append(flags);
1023             if (hasMarkers) {
1024                 staticArgs = staticArgs.append(markers.length());
1025                 staticArgs = staticArgs.appendList(markers.toList());
1026             }
1027             if (hasBridges) {
1028                 staticArgs = staticArgs.append(context.bridges.length() - 1);
1029                 for (Symbol s : context.bridges) {
1030                     Type s_erasure = s.erasure(types);
1031                     if (!types.isSameType(s_erasure, samSym.erasure(types))) {
1032                         staticArgs = staticArgs.append(s.erasure(types));
1033                     }
1034                 }
1035             }
1036             if (context.isSerializable()) {
1037                 int prevPos = make.pos;
1038                 try {
1039                     make.at(kInfo.clazz);
1040                     addDeserializationCase(refKind, refSym, tree.type, samSym,
1041                             tree, staticArgs, indyType);
1042                 } finally {
1043                     make.at(prevPos);
1044                 }
1045             }
1046         }
1047 
1048         return makeIndyCall(tree, syms.lambdaMetafactory, metafactoryName, staticArgs, indyType, indy_args, samSym.name);
1049     }
1050 
1051     /**
1052      * Generate an indy method call with given name, type and static bootstrap
1053      * arguments types
1054      */
makeIndyCall(DiagnosticPosition pos, Type site, Name bsmName, List<Object> staticArgs, MethodType indyType, List<JCExpression> indyArgs, Name methName)1055     private JCExpression makeIndyCall(DiagnosticPosition pos, Type site, Name bsmName,
1056             List<Object> staticArgs, MethodType indyType, List<JCExpression> indyArgs,
1057             Name methName) {
1058         int prevPos = make.pos;
1059         try {
1060             make.at(pos);
1061             List<Type> bsm_staticArgs = List.of(syms.methodHandleLookupType,
1062                     syms.stringType,
1063                     syms.methodTypeType).appendList(bsmStaticArgToTypes(staticArgs));
1064 
1065             Symbol bsm = rs.resolveInternalMethod(pos, attrEnv, site,
1066                     bsmName, bsm_staticArgs, List.<Type>nil());
1067 
1068             DynamicMethodSymbol dynSym =
1069                     new DynamicMethodSymbol(methName,
1070                                             syms.noSymbol,
1071                                             bsm.isStatic() ?
1072                                                 ClassFile.REF_invokeStatic :
1073                                                 ClassFile.REF_invokeVirtual,
1074                                             (MethodSymbol)bsm,
1075                                             indyType,
1076                                             staticArgs.toArray());
1077 
1078             JCFieldAccess qualifier = make.Select(make.QualIdent(site.tsym), bsmName);
1079             qualifier.sym = dynSym;
1080             qualifier.type = indyType.getReturnType();
1081 
1082             JCMethodInvocation proxyCall = make.Apply(List.<JCExpression>nil(), qualifier, indyArgs);
1083             proxyCall.type = indyType.getReturnType();
1084             return proxyCall;
1085         } finally {
1086             make.at(prevPos);
1087         }
1088     }
1089     //where
bsmStaticArgToTypes(List<Object> args)1090     private List<Type> bsmStaticArgToTypes(List<Object> args) {
1091         ListBuffer<Type> argtypes = new ListBuffer<>();
1092         for (Object arg : args) {
1093             argtypes.append(bsmStaticArgToType(arg));
1094         }
1095         return argtypes.toList();
1096     }
1097 
bsmStaticArgToType(Object arg)1098     private Type bsmStaticArgToType(Object arg) {
1099         Assert.checkNonNull(arg);
1100         if (arg instanceof ClassSymbol) {
1101             return syms.classType;
1102         } else if (arg instanceof Integer) {
1103             return syms.intType;
1104         } else if (arg instanceof Long) {
1105             return syms.longType;
1106         } else if (arg instanceof Float) {
1107             return syms.floatType;
1108         } else if (arg instanceof Double) {
1109             return syms.doubleType;
1110         } else if (arg instanceof String) {
1111             return syms.stringType;
1112         } else if (arg instanceof Pool.MethodHandle) {
1113             return syms.methodHandleType;
1114         } else if (arg instanceof MethodType) {
1115             return syms.methodTypeType;
1116         } else {
1117             Assert.error("bad static arg " + arg.getClass());
1118             return null;
1119         }
1120     }
1121 
1122     /**
1123      * Get the opcode associated with this method reference
1124      */
referenceKind(Symbol refSym)1125     private int referenceKind(Symbol refSym) {
1126         if (refSym.isConstructor()) {
1127             return ClassFile.REF_newInvokeSpecial;
1128         } else {
1129             if (refSym.isStatic()) {
1130                 return ClassFile.REF_invokeStatic;
1131             } else if ((refSym.flags() & PRIVATE) != 0) {
1132                 return ClassFile.REF_invokeSpecial;
1133             } else if (refSym.enclClass().isInterface()) {
1134                 return ClassFile.REF_invokeInterface;
1135             } else {
1136                 return ClassFile.REF_invokeVirtual;
1137             }
1138         }
1139     }
1140 
1141     // <editor-fold defaultstate="collapsed" desc="Lambda/reference analyzer">
1142     /**
1143      * This visitor collects information about translation of a lambda expression.
1144      * More specifically, it keeps track of the enclosing contexts and captured locals
1145      * accessed by the lambda being translated (as well as other useful info).
1146      * It also translates away problems for LambdaToMethod.
1147      */
1148     class LambdaAnalyzerPreprocessor extends TreeTranslator {
1149 
1150         /** the frame stack - used to reconstruct translation info about enclosing scopes */
1151         private List<Frame> frameStack;
1152 
1153         /**
1154          * keep the count of lambda expression (used to generate unambiguous
1155          * names)
1156          */
1157         private int lambdaCount = 0;
1158 
1159         /**
1160          * List of types undergoing construction via explicit constructor chaining.
1161          */
1162         private List<ClassSymbol> typesUnderConstruction;
1163 
1164         /**
1165          * keep the count of lambda expression defined in given context (used to
1166          * generate unambiguous names for serializable lambdas)
1167          */
1168         private class SyntheticMethodNameCounter {
1169             private Map<String, Integer> map = new HashMap<>();
getIndex(StringBuilder buf)1170             int getIndex(StringBuilder buf) {
1171                 String temp = buf.toString();
1172                 Integer count = map.get(temp);
1173                 if (count == null) {
1174                     count = 0;
1175                 }
1176                 ++count;
1177                 map.put(temp, count);
1178                 return count;
1179             }
1180         }
1181         private SyntheticMethodNameCounter syntheticMethodNameCounts =
1182                 new SyntheticMethodNameCounter();
1183 
1184         private Map<Symbol, JCClassDecl> localClassDefs;
1185 
1186         /**
1187          * maps for fake clinit symbols to be used as owners of lambda occurring in
1188          * a static var init context
1189          */
1190         private Map<ClassSymbol, Symbol> clinits =
1191                 new HashMap<ClassSymbol, Symbol>();
1192 
analyzeAndPreprocessClass(JCClassDecl tree)1193         private JCClassDecl analyzeAndPreprocessClass(JCClassDecl tree) {
1194             frameStack = List.nil();
1195             typesUnderConstruction = List.nil();
1196             localClassDefs = new HashMap<Symbol, JCClassDecl>();
1197             return translate(tree);
1198         }
1199 
1200         @Override
visitApply(JCMethodInvocation tree)1201         public void visitApply(JCMethodInvocation tree) {
1202             List<ClassSymbol> previousNascentTypes = typesUnderConstruction;
1203             try {
1204                 Name methName = TreeInfo.name(tree.meth);
1205                 if (methName == names._this || methName == names._super) {
1206                     typesUnderConstruction = typesUnderConstruction.prepend(currentClass());
1207                 }
1208                 super.visitApply(tree);
1209             } finally {
1210                 typesUnderConstruction = previousNascentTypes;
1211             }
1212         }
1213             // where
currentClass()1214             private ClassSymbol currentClass() {
1215                 for (Frame frame : frameStack) {
1216                     if (frame.tree.hasTag(JCTree.Tag.CLASSDEF)) {
1217                         JCClassDecl cdef = (JCClassDecl) frame.tree;
1218                         return cdef.sym;
1219                     }
1220                 }
1221                 return null;
1222             }
1223 
1224         @Override
visitBlock(JCBlock tree)1225         public void visitBlock(JCBlock tree) {
1226             List<Frame> prevStack = frameStack;
1227             try {
1228                 if (frameStack.nonEmpty() && frameStack.head.tree.hasTag(CLASSDEF)) {
1229                     frameStack = frameStack.prepend(new Frame(tree));
1230                 }
1231                 super.visitBlock(tree);
1232             }
1233             finally {
1234                 frameStack = prevStack;
1235             }
1236         }
1237 
1238         @Override
visitClassDef(JCClassDecl tree)1239         public void visitClassDef(JCClassDecl tree) {
1240             List<Frame> prevStack = frameStack;
1241             int prevLambdaCount = lambdaCount;
1242             SyntheticMethodNameCounter prevSyntheticMethodNameCounts =
1243                     syntheticMethodNameCounts;
1244             Map<ClassSymbol, Symbol> prevClinits = clinits;
1245             DiagnosticSource prevSource = log.currentSource();
1246             try {
1247                 log.useSource(tree.sym.sourcefile);
1248                 lambdaCount = 0;
1249                 syntheticMethodNameCounts = new SyntheticMethodNameCounter();
1250                 prevClinits = new HashMap<ClassSymbol, Symbol>();
1251                 if (tree.sym.owner.kind == MTH) {
1252                     localClassDefs.put(tree.sym, tree);
1253                 }
1254                 if (directlyEnclosingLambda() != null) {
1255                     tree.sym.owner = owner();
1256                     if (tree.sym.hasOuterInstance()) {
1257                         //if a class is defined within a lambda, the lambda must capture
1258                         //its enclosing instance (if any)
1259                         TranslationContext<?> localContext = context();
1260                         while (localContext != null) {
1261                             if (localContext.tree.getTag() == LAMBDA) {
1262                                 ((LambdaTranslationContext)localContext)
1263                                         .addSymbol(tree.sym.type.getEnclosingType().tsym, CAPTURED_THIS);
1264                             }
1265                             localContext = localContext.prev;
1266                         }
1267                     }
1268                 }
1269                 frameStack = frameStack.prepend(new Frame(tree));
1270                 super.visitClassDef(tree);
1271             }
1272             finally {
1273                 log.useSource(prevSource.getFile());
1274                 frameStack = prevStack;
1275                 lambdaCount = prevLambdaCount;
1276                 syntheticMethodNameCounts = prevSyntheticMethodNameCounts;
1277                 clinits = prevClinits;
1278             }
1279         }
1280 
1281         @Override
visitIdent(JCIdent tree)1282         public void visitIdent(JCIdent tree) {
1283             if (context() != null && lambdaIdentSymbolFilter(tree.sym)) {
1284                 if (tree.sym.kind == VAR &&
1285                         tree.sym.owner.kind == MTH &&
1286                         tree.type.constValue() == null) {
1287                     TranslationContext<?> localContext = context();
1288                     while (localContext != null) {
1289                         if (localContext.tree.getTag() == LAMBDA) {
1290                             JCTree block = capturedDecl(localContext.depth, tree.sym);
1291                             if (block == null) break;
1292                             ((LambdaTranslationContext)localContext)
1293                                     .addSymbol(tree.sym, CAPTURED_VAR);
1294                         }
1295                         localContext = localContext.prev;
1296                     }
1297                 } else if (tree.sym.owner.kind == TYP) {
1298                     TranslationContext<?> localContext = context();
1299                     while (localContext != null) {
1300                         if (localContext.tree.hasTag(LAMBDA)) {
1301                             JCTree block = capturedDecl(localContext.depth, tree.sym);
1302                             if (block == null) break;
1303                             switch (block.getTag()) {
1304                                 case CLASSDEF:
1305                                     JCClassDecl cdecl = (JCClassDecl)block;
1306                                     ((LambdaTranslationContext)localContext)
1307                                             .addSymbol(cdecl.sym, CAPTURED_THIS);
1308                                     break;
1309                                 default:
1310                                     Assert.error("bad block kind");
1311                             }
1312                         }
1313                         localContext = localContext.prev;
1314                     }
1315                 }
1316             }
1317             super.visitIdent(tree);
1318         }
1319 
1320         @Override
visitLambda(JCLambda tree)1321         public void visitLambda(JCLambda tree) {
1322             analyzeLambda(tree, "lambda.stat");
1323         }
1324 
analyzeLambda(JCLambda tree, JCExpression methodReferenceReceiver)1325         private void analyzeLambda(JCLambda tree, JCExpression methodReferenceReceiver) {
1326             // Translation of the receiver expression must occur first
1327             JCExpression rcvr = translate(methodReferenceReceiver);
1328             LambdaTranslationContext context = analyzeLambda(tree, "mref.stat.1");
1329             if (rcvr != null) {
1330                 context.methodReferenceReceiver = rcvr;
1331             }
1332         }
1333 
analyzeLambda(JCLambda tree, String statKey)1334         private LambdaTranslationContext analyzeLambda(JCLambda tree, String statKey) {
1335             List<Frame> prevStack = frameStack;
1336             try {
1337                 LambdaTranslationContext context = new LambdaTranslationContext(tree);
1338                 if (dumpLambdaToMethodStats) {
1339                     log.note(tree, statKey, context.needsAltMetafactory(), context.translatedSym);
1340                 }
1341                 frameStack = frameStack.prepend(new Frame(tree));
1342                 for (JCVariableDecl param : tree.params) {
1343                     context.addSymbol(param.sym, PARAM);
1344                     frameStack.head.addLocal(param.sym);
1345                 }
1346                 contextMap.put(tree, context);
1347                 super.visitLambda(tree);
1348                 context.complete();
1349                 return context;
1350             }
1351             finally {
1352                 frameStack = prevStack;
1353             }
1354         }
1355 
1356         @Override
visitMethodDef(JCMethodDecl tree)1357         public void visitMethodDef(JCMethodDecl tree) {
1358             List<Frame> prevStack = frameStack;
1359             try {
1360                 frameStack = frameStack.prepend(new Frame(tree));
1361                 super.visitMethodDef(tree);
1362             }
1363             finally {
1364                 frameStack = prevStack;
1365             }
1366         }
1367 
1368         @Override
visitNewClass(JCNewClass tree)1369         public void visitNewClass(JCNewClass tree) {
1370             TypeSymbol def = tree.type.tsym;
1371             boolean inReferencedClass = currentlyInClass(def);
1372             boolean isLocal = def.isLocal();
1373             if ((inReferencedClass && isLocal || lambdaNewClassFilter(context(), tree))) {
1374                 TranslationContext<?> localContext = context();
1375                 while (localContext != null) {
1376                     if (localContext.tree.getTag() == LAMBDA) {
1377                         ((LambdaTranslationContext)localContext)
1378                                 .addSymbol(tree.type.getEnclosingType().tsym, CAPTURED_THIS);
1379                     }
1380                     localContext = localContext.prev;
1381                 }
1382             }
1383             if (context() != null && !inReferencedClass && isLocal) {
1384                 LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context();
1385                 captureLocalClassDefs(def, lambdaContext);
1386             }
1387             super.visitNewClass(tree);
1388         }
1389         //where
captureLocalClassDefs(Symbol csym, final LambdaTranslationContext lambdaContext)1390             void captureLocalClassDefs(Symbol csym, final LambdaTranslationContext lambdaContext) {
1391                 JCClassDecl localCDef = localClassDefs.get(csym);
1392                 if (localCDef != null && lambdaContext.freeVarProcessedLocalClasses.add(csym)) {
1393                     BasicFreeVarCollector fvc = lower.new BasicFreeVarCollector() {
1394                         @Override
1395                         void addFreeVars(ClassSymbol c) {
1396                             captureLocalClassDefs(c, lambdaContext);
1397                         }
1398                         @Override
1399                         void visitSymbol(Symbol sym) {
1400                             if (sym.kind == VAR &&
1401                                     sym.owner.kind == MTH &&
1402                                     ((VarSymbol)sym).getConstValue() == null) {
1403                                 TranslationContext<?> localContext = context();
1404                                 while (localContext != null) {
1405                                     if (localContext.tree.getTag() == LAMBDA) {
1406                                         JCTree block = capturedDecl(localContext.depth, sym);
1407                                         if (block == null) break;
1408                                         ((LambdaTranslationContext)localContext).addSymbol(sym, CAPTURED_VAR);
1409                                     }
1410                                     localContext = localContext.prev;
1411                                 }
1412                             }
1413                         }
1414                     };
1415                     fvc.scan(localCDef);
1416                 }
1417         }
1418         //where
currentlyInClass(Symbol csym)1419         boolean currentlyInClass(Symbol csym) {
1420             for (Frame frame : frameStack) {
1421                 if (frame.tree.hasTag(JCTree.Tag.CLASSDEF)) {
1422                     JCClassDecl cdef = (JCClassDecl) frame.tree;
1423                     if (cdef.sym == csym) {
1424                         return true;
1425                     }
1426                 }
1427             }
1428             return false;
1429         }
1430 
1431         /**
1432          * Method references to local class constructors, may, if the local
1433          * class references local variables, have implicit constructor
1434          * parameters added in Lower; As a result, the invokedynamic bootstrap
1435          * information added in the LambdaToMethod pass will have the wrong
1436          * signature. Hooks between Lower and LambdaToMethod have been added to
1437          * handle normal "new" in this case. This visitor converts potentially
1438          * affected method references into a lambda containing a normal
1439          * expression.
1440          *
1441          * @param tree
1442          */
1443         @Override
visitReference(JCMemberReference tree)1444         public void visitReference(JCMemberReference tree) {
1445             ReferenceTranslationContext rcontext = new ReferenceTranslationContext(tree);
1446             contextMap.put(tree, rcontext);
1447             if (rcontext.needsConversionToLambda()) {
1448                  // Convert to a lambda, and process as such
1449                 MemberReferenceToLambda conv = new MemberReferenceToLambda(tree, rcontext, owner());
1450                 analyzeLambda(conv.lambda(), conv.getReceiverExpression());
1451             } else {
1452                 super.visitReference(tree);
1453                 if (dumpLambdaToMethodStats) {
1454                     log.note(tree, "mref.stat", rcontext.needsAltMetafactory(), null);
1455                 }
1456             }
1457         }
1458 
1459         @Override
visitSelect(JCFieldAccess tree)1460         public void visitSelect(JCFieldAccess tree) {
1461             if (context() != null && tree.sym.kind == VAR &&
1462                         (tree.sym.name == names._this ||
1463                          tree.sym.name == names._super)) {
1464                 // A select of this or super means, if we are in a lambda,
1465                 // we much have an instance context
1466                 TranslationContext<?> localContext = context();
1467                 while (localContext != null) {
1468                     if (localContext.tree.hasTag(LAMBDA)) {
1469                         JCClassDecl clazz = (JCClassDecl)capturedDecl(localContext.depth, tree.sym);
1470                         if (clazz == null) break;
1471                         ((LambdaTranslationContext)localContext).addSymbol(clazz.sym, CAPTURED_THIS);
1472                     }
1473                     localContext = localContext.prev;
1474                 }
1475             }
1476             super.visitSelect(tree);
1477         }
1478 
1479         @Override
visitVarDef(JCVariableDecl tree)1480         public void visitVarDef(JCVariableDecl tree) {
1481             TranslationContext<?> context = context();
1482             LambdaTranslationContext ltc = (context != null && context instanceof LambdaTranslationContext)?
1483                     (LambdaTranslationContext)context :
1484                     null;
1485             if (ltc != null) {
1486                 if (frameStack.head.tree.hasTag(LAMBDA)) {
1487                     ltc.addSymbol(tree.sym, LOCAL_VAR);
1488                 }
1489                 // Check for type variables (including as type arguments).
1490                 // If they occur within class nested in a lambda, mark for erasure
1491                 Type type = tree.sym.asType();
1492                 if (inClassWithinLambda() && !types.isSameType(types.erasure(type), type)) {
1493                     ltc.addSymbol(tree.sym, TYPE_VAR);
1494                 }
1495             }
1496 
1497             List<Frame> prevStack = frameStack;
1498             try {
1499                 if (tree.sym.owner.kind == MTH) {
1500                     frameStack.head.addLocal(tree.sym);
1501                 }
1502                 frameStack = frameStack.prepend(new Frame(tree));
1503                 super.visitVarDef(tree);
1504             }
1505             finally {
1506                 frameStack = prevStack;
1507             }
1508         }
1509 
1510         /**
1511          * Return a valid owner given the current declaration stack
1512          * (required to skip synthetic lambda symbols)
1513          */
owner()1514         private Symbol owner() {
1515             return owner(false);
1516         }
1517 
1518         @SuppressWarnings("fallthrough")
owner(boolean skipLambda)1519         private Symbol owner(boolean skipLambda) {
1520             List<Frame> frameStack2 = frameStack;
1521             while (frameStack2.nonEmpty()) {
1522                 switch (frameStack2.head.tree.getTag()) {
1523                     case VARDEF:
1524                         if (((JCVariableDecl)frameStack2.head.tree).sym.isLocal()) {
1525                             frameStack2 = frameStack2.tail;
1526                             break;
1527                         }
1528                         JCClassDecl cdecl = (JCClassDecl)frameStack2.tail.head.tree;
1529                         return initSym(cdecl.sym,
1530                                 ((JCVariableDecl)frameStack2.head.tree).sym.flags() & STATIC);
1531                     case BLOCK:
1532                         JCClassDecl cdecl2 = (JCClassDecl)frameStack2.tail.head.tree;
1533                         return initSym(cdecl2.sym,
1534                                 ((JCBlock)frameStack2.head.tree).flags & STATIC);
1535                     case CLASSDEF:
1536                         return ((JCClassDecl)frameStack2.head.tree).sym;
1537                     case METHODDEF:
1538                         return ((JCMethodDecl)frameStack2.head.tree).sym;
1539                     case LAMBDA:
1540                         if (!skipLambda)
1541                             return ((LambdaTranslationContext)contextMap
1542                                     .get(frameStack2.head.tree)).translatedSym;
1543                     default:
1544                         frameStack2 = frameStack2.tail;
1545                 }
1546             }
1547             Assert.error();
1548             return null;
1549         }
1550 
initSym(ClassSymbol csym, long flags)1551         private Symbol initSym(ClassSymbol csym, long flags) {
1552             boolean isStatic = (flags & STATIC) != 0;
1553             if (isStatic) {
1554                 /* static clinits are generated in Gen, so we need to use a fake
1555                  * one. Attr creates a fake clinit method while attributing
1556                  * lambda expressions used as initializers of static fields, so
1557                  * let's use that one.
1558                  */
1559                 MethodSymbol clinit = attr.removeClinit(csym);
1560                 if (clinit != null) {
1561                     clinits.put(csym, clinit);
1562                     return clinit;
1563                 }
1564 
1565                 /* if no clinit is found at Attr, then let's try at clinits.
1566                  */
1567                 clinit = (MethodSymbol)clinits.get(csym);
1568                 if (clinit == null) {
1569                     /* no luck, let's create a new one
1570                      */
1571                     clinit = makePrivateSyntheticMethod(STATIC,
1572                             names.clinit,
1573                             new MethodType(List.<Type>nil(), syms.voidType,
1574                                 List.<Type>nil(), syms.methodClass),
1575                             csym);
1576                     clinits.put(csym, clinit);
1577                 }
1578                 return clinit;
1579             } else {
1580                 //get the first constructor and treat it as the instance init sym
1581                 for (Symbol s : csym.members_field.getElementsByName(names.init)) {
1582                     return s;
1583                 }
1584             }
1585             Assert.error("init not found");
1586             return null;
1587         }
1588 
directlyEnclosingLambda()1589         private JCTree directlyEnclosingLambda() {
1590             if (frameStack.isEmpty()) {
1591                 return null;
1592             }
1593             List<Frame> frameStack2 = frameStack;
1594             while (frameStack2.nonEmpty()) {
1595                 switch (frameStack2.head.tree.getTag()) {
1596                     case CLASSDEF:
1597                     case METHODDEF:
1598                         return null;
1599                     case LAMBDA:
1600                         return frameStack2.head.tree;
1601                     default:
1602                         frameStack2 = frameStack2.tail;
1603                 }
1604             }
1605             Assert.error();
1606             return null;
1607         }
1608 
inClassWithinLambda()1609         private boolean inClassWithinLambda() {
1610             if (frameStack.isEmpty()) {
1611                 return false;
1612             }
1613             List<Frame> frameStack2 = frameStack;
1614             boolean classFound = false;
1615             while (frameStack2.nonEmpty()) {
1616                 switch (frameStack2.head.tree.getTag()) {
1617                     case LAMBDA:
1618                         return classFound;
1619                     case CLASSDEF:
1620                         classFound = true;
1621                         frameStack2 = frameStack2.tail;
1622                         break;
1623                     default:
1624                         frameStack2 = frameStack2.tail;
1625                 }
1626             }
1627             // No lambda
1628             return false;
1629         }
1630 
1631         /**
1632          * Return the declaration corresponding to a symbol in the enclosing
1633          * scope; the depth parameter is used to filter out symbols defined
1634          * in nested scopes (which do not need to undergo capture).
1635          */
capturedDecl(int depth, Symbol sym)1636         private JCTree capturedDecl(int depth, Symbol sym) {
1637             int currentDepth = frameStack.size() - 1;
1638             for (Frame block : frameStack) {
1639                 switch (block.tree.getTag()) {
1640                     case CLASSDEF:
1641                         ClassSymbol clazz = ((JCClassDecl)block.tree).sym;
1642                         if (sym.isMemberOf(clazz, types)) {
1643                             return currentDepth > depth ? null : block.tree;
1644                         }
1645                         break;
1646                     case VARDEF:
1647                         if (((JCVariableDecl)block.tree).sym == sym &&
1648                                 sym.owner.kind == MTH) { //only locals are captured
1649                             return currentDepth > depth ? null : block.tree;
1650                         }
1651                         break;
1652                     case BLOCK:
1653                     case METHODDEF:
1654                     case LAMBDA:
1655                         if (block.locals != null && block.locals.contains(sym)) {
1656                             return currentDepth > depth ? null : block.tree;
1657                         }
1658                         break;
1659                     default:
1660                         Assert.error("bad decl kind " + block.tree.getTag());
1661                 }
1662                 currentDepth--;
1663             }
1664             return null;
1665         }
1666 
context()1667         private TranslationContext<?> context() {
1668             for (Frame frame : frameStack) {
1669                 TranslationContext<?> context = contextMap.get(frame.tree);
1670                 if (context != null) {
1671                     return context;
1672                 }
1673             }
1674             return null;
1675         }
1676 
1677         /**
1678          *  This is used to filter out those identifiers that needs to be adjusted
1679          *  when translating away lambda expressions
1680          */
lambdaIdentSymbolFilter(Symbol sym)1681         private boolean lambdaIdentSymbolFilter(Symbol sym) {
1682             return (sym.kind == VAR || sym.kind == MTH)
1683                     && !sym.isStatic()
1684                     && sym.name != names.init;
1685         }
1686 
1687         /**
1688          *  This is used to filter out those select nodes that need to be adjusted
1689          *  when translating away lambda expressions - at the moment, this is the
1690          *  set of nodes that select `this' (qualified this)
1691          */
lambdaFieldAccessFilter(JCFieldAccess fAccess)1692         private boolean lambdaFieldAccessFilter(JCFieldAccess fAccess) {
1693             LambdaTranslationContext lambdaContext =
1694                     context instanceof LambdaTranslationContext ?
1695                             (LambdaTranslationContext) context : null;
1696             return lambdaContext != null
1697                     && !fAccess.sym.isStatic()
1698                     && fAccess.name == names._this
1699                     && (fAccess.sym.owner.kind == TYP)
1700                     && !lambdaContext.translatedSymbols.get(CAPTURED_OUTER_THIS).isEmpty();
1701         }
1702 
1703         /**
1704          * This is used to filter out those new class expressions that need to
1705          * be qualified with an enclosing tree
1706          */
lambdaNewClassFilter(TranslationContext<?> context, JCNewClass tree)1707         private boolean lambdaNewClassFilter(TranslationContext<?> context, JCNewClass tree) {
1708             if (context != null
1709                     && tree.encl == null
1710                     && tree.def == null
1711                     && !tree.type.getEnclosingType().hasTag(NONE)) {
1712                 Type encl = tree.type.getEnclosingType();
1713                 Type current = context.owner.enclClass().type;
1714                 while (!current.hasTag(NONE)) {
1715                     if (current.tsym.isSubClass(encl.tsym, types)) {
1716                         return true;
1717                     }
1718                     current = current.getEnclosingType();
1719                 }
1720                 return false;
1721             } else {
1722                 return false;
1723             }
1724         }
1725 
1726         private class Frame {
1727             final JCTree tree;
1728             List<Symbol> locals;
1729 
Frame(JCTree tree)1730             public Frame(JCTree tree) {
1731                 this.tree = tree;
1732             }
1733 
addLocal(Symbol sym)1734             void addLocal(Symbol sym) {
1735                 if (locals == null) {
1736                     locals = List.nil();
1737                 }
1738                 locals = locals.prepend(sym);
1739             }
1740         }
1741 
1742         /**
1743          * This class is used to store important information regarding translation of
1744          * lambda expression/method references (see subclasses).
1745          */
1746         private abstract class TranslationContext<T extends JCFunctionalExpression> {
1747 
1748             /** the underlying (untranslated) tree */
1749             final T tree;
1750 
1751             /** points to the adjusted enclosing scope in which this lambda/mref expression occurs */
1752             final Symbol owner;
1753 
1754             /** the depth of this lambda expression in the frame stack */
1755             final int depth;
1756 
1757             /** the enclosing translation context (set for nested lambdas/mref) */
1758             final TranslationContext<?> prev;
1759 
1760             /** list of methods to be bridged by the meta-factory */
1761             final List<Symbol> bridges;
1762 
TranslationContext(T tree)1763             TranslationContext(T tree) {
1764                 this.tree = tree;
1765                 this.owner = owner();
1766                 this.depth = frameStack.size() - 1;
1767                 this.prev = context();
1768                 ClassSymbol csym =
1769                         types.makeFunctionalInterfaceClass(attrEnv, names.empty, tree.targets, ABSTRACT | INTERFACE);
1770                 this.bridges = types.functionalInterfaceBridges(csym);
1771             }
1772 
1773             /** does this functional expression need to be created using alternate metafactory? */
needsAltMetafactory()1774             boolean needsAltMetafactory() {
1775                 return tree.targets.length() > 1 ||
1776                         isSerializable() ||
1777                         bridges.length() > 1;
1778             }
1779 
1780             /** does this functional expression require serialization support? */
isSerializable()1781             boolean isSerializable() {
1782                 if (forceSerializable) {
1783                     return true;
1784                 }
1785                 for (Type target : tree.targets) {
1786                     if (types.asSuper(target, syms.serializableType.tsym) != null) {
1787                         return true;
1788                     }
1789                 }
1790                 return false;
1791             }
1792 
1793             /**
1794              * @return Name of the enclosing method to be folded into synthetic
1795              * method name
1796              */
enclosingMethodName()1797             String enclosingMethodName() {
1798                 return syntheticMethodNameComponent(owner.name);
1799             }
1800 
1801             /**
1802              * @return Method name in a form that can be folded into a
1803              * component of a synthetic method name
1804              */
syntheticMethodNameComponent(Name name)1805             String syntheticMethodNameComponent(Name name) {
1806                 if (name == null) {
1807                     return "null";
1808                 }
1809                 String methodName = name.toString();
1810                 if (methodName.equals("<clinit>")) {
1811                     methodName = "static";
1812                 } else if (methodName.equals("<init>")) {
1813                     methodName = "new";
1814                 }
1815                 return methodName;
1816             }
1817         }
1818 
1819         /**
1820          * This class retains all the useful information about a lambda expression;
1821          * the contents of this class are filled by the LambdaAnalyzer visitor,
1822          * and the used by the main translation routines in order to adjust references
1823          * to captured locals/members, etc.
1824          */
1825         private class LambdaTranslationContext extends TranslationContext<JCLambda> {
1826 
1827             /** variable in the enclosing context to which this lambda is assigned */
1828             final Symbol self;
1829 
1830             /** variable in the enclosing context to which this lambda is assigned */
1831             final Symbol assignedTo;
1832 
1833             Map<LambdaSymbolKind, Map<Symbol, Symbol>> translatedSymbols;
1834 
1835             /** the synthetic symbol for the method hoisting the translated lambda */
1836             MethodSymbol translatedSym;
1837 
1838             List<JCVariableDecl> syntheticParams;
1839 
1840             /**
1841              * to prevent recursion, track local classes processed
1842              */
1843             final Set<Symbol> freeVarProcessedLocalClasses;
1844 
1845             /**
1846              * For method references converted to lambdas.  The method
1847              * reference receiver expression. Must be treated like a captured
1848              * variable.
1849              */
1850             JCExpression methodReferenceReceiver;
1851 
LambdaTranslationContext(JCLambda tree)1852             LambdaTranslationContext(JCLambda tree) {
1853                 super(tree);
1854                 Frame frame = frameStack.head;
1855                 switch (frame.tree.getTag()) {
1856                     case VARDEF:
1857                         assignedTo = self = ((JCVariableDecl) frame.tree).sym;
1858                         break;
1859                     case ASSIGN:
1860                         self = null;
1861                         assignedTo = TreeInfo.symbol(((JCAssign) frame.tree).getVariable());
1862                         break;
1863                     default:
1864                         assignedTo = self = null;
1865                         break;
1866                  }
1867 
1868                 // This symbol will be filled-in in complete
1869                 this.translatedSym = makePrivateSyntheticMethod(0, null, null, owner.enclClass());
1870 
1871                 translatedSymbols = new EnumMap<>(LambdaSymbolKind.class);
1872 
1873                 translatedSymbols.put(PARAM, new LinkedHashMap<Symbol, Symbol>());
1874                 translatedSymbols.put(LOCAL_VAR, new LinkedHashMap<Symbol, Symbol>());
1875                 translatedSymbols.put(CAPTURED_VAR, new LinkedHashMap<Symbol, Symbol>());
1876                 translatedSymbols.put(CAPTURED_THIS, new LinkedHashMap<Symbol, Symbol>());
1877                 translatedSymbols.put(CAPTURED_OUTER_THIS, new LinkedHashMap<Symbol, Symbol>());
1878                 translatedSymbols.put(TYPE_VAR, new LinkedHashMap<Symbol, Symbol>());
1879 
1880                 freeVarProcessedLocalClasses = new HashSet<>();
1881             }
1882 
1883              /**
1884              * For a serializable lambda, generate a disambiguating string
1885              * which maximizes stability across deserialization.
1886              *
1887              * @return String to differentiate synthetic lambda method names
1888              */
serializedLambdaDisambiguation()1889             private String serializedLambdaDisambiguation() {
1890                 StringBuilder buf = new StringBuilder();
1891                 // Append the enclosing method signature to differentiate
1892                 // overloaded enclosing methods.  For lambdas enclosed in
1893                 // lambdas, the generated lambda method will not have type yet,
1894                 // but the enclosing method's name will have been generated
1895                 // with this same method, so it will be unique and never be
1896                 // overloaded.
1897                 Assert.check(
1898                         owner.type != null ||
1899                         directlyEnclosingLambda() != null);
1900                 if (owner.type != null) {
1901                     buf.append(typeSig(owner.type));
1902                     buf.append(":");
1903                 }
1904 
1905                 // Add target type info
1906                 buf.append(types.findDescriptorSymbol(tree.type.tsym).owner.flatName());
1907                 buf.append(" ");
1908 
1909                 // Add variable assigned to
1910                 if (assignedTo != null) {
1911                     buf.append(assignedTo.flatName());
1912                     buf.append("=");
1913                 }
1914                 //add captured locals info: type, name, order
1915                 for (Symbol fv : getSymbolMap(CAPTURED_VAR).keySet()) {
1916                     if (fv != self) {
1917                         buf.append(typeSig(fv.type));
1918                         buf.append(" ");
1919                         buf.append(fv.flatName());
1920                         buf.append(",");
1921                     }
1922                 }
1923 
1924                 return buf.toString();
1925             }
1926 
1927             /**
1928              * For a non-serializable lambda, generate a simple method.
1929              *
1930              * @return Name to use for the synthetic lambda method name
1931              */
lambdaName()1932             private Name lambdaName() {
1933                 return names.lambda.append(names.fromString(enclosingMethodName() + "$" + lambdaCount++));
1934             }
1935 
1936             /**
1937              * For a serializable lambda, generate a method name which maximizes
1938              * name stability across deserialization.
1939              *
1940              * @return Name to use for the synthetic lambda method name
1941              */
serializedLambdaName()1942             private Name serializedLambdaName() {
1943                 StringBuilder buf = new StringBuilder();
1944                 buf.append(names.lambda);
1945                 // Append the name of the method enclosing the lambda.
1946                 buf.append(enclosingMethodName());
1947                 buf.append('$');
1948                 // Append a hash of the disambiguating string : enclosing method
1949                 // signature, etc.
1950                 String disam = serializedLambdaDisambiguation();
1951                 buf.append(Integer.toHexString(disam.hashCode()));
1952                 buf.append('$');
1953                 // The above appended name components may not be unique, append
1954                 // a count based on the above name components.
1955                 buf.append(syntheticMethodNameCounts.getIndex(buf));
1956                 String result = buf.toString();
1957                 //System.err.printf("serializedLambdaName: %s -- %s\n", result, disam);
1958                 return names.fromString(result);
1959             }
1960 
1961             /**
1962              * Translate a symbol of a given kind into something suitable for the
1963              * synthetic lambda body
1964              */
translate(final Symbol sym, LambdaSymbolKind skind)1965             Symbol translate(final Symbol sym, LambdaSymbolKind skind) {
1966                 Symbol ret;
1967                 switch (skind) {
1968                     case CAPTURED_THIS:
1969                         ret = sym;  // self represented
1970                         break;
1971                     case TYPE_VAR:
1972                         // Just erase the type var
1973                         ret = new VarSymbol(sym.flags(), sym.name,
1974                                 types.erasure(sym.type), sym.owner);
1975 
1976                         /* this information should also be kept for LVT generation at Gen
1977                          * a Symbol with pos < startPos won't be tracked.
1978                          */
1979                         ((VarSymbol)ret).pos = ((VarSymbol)sym).pos;
1980                         break;
1981                     case CAPTURED_VAR:
1982                         ret = new VarSymbol(SYNTHETIC | FINAL | PARAMETER, sym.name, types.erasure(sym.type), translatedSym) {
1983                             @Override
1984                             public Symbol baseSymbol() {
1985                                 //keep mapping with original captured symbol
1986                                 return sym;
1987                             }
1988                         };
1989                         break;
1990                     case CAPTURED_OUTER_THIS:
1991                         Name name = names.fromString(new String(sym.flatName().toString().replace('.', '$') + names.dollarThis));
1992                         ret = new VarSymbol(SYNTHETIC | FINAL | PARAMETER, name, types.erasure(sym.type), translatedSym) {
1993                             @Override
1994                             public Symbol baseSymbol() {
1995                                 //keep mapping with original captured symbol
1996                                 return sym;
1997                             }
1998                         };
1999                         break;
2000                     case LOCAL_VAR:
2001                         ret = new VarSymbol(sym.flags() & FINAL, sym.name, sym.type, translatedSym);
2002                         ((VarSymbol) ret).pos = ((VarSymbol) sym).pos;
2003                         break;
2004                     case PARAM:
2005                         ret = new VarSymbol((sym.flags() & FINAL) | PARAMETER, sym.name, types.erasure(sym.type), translatedSym);
2006                         ((VarSymbol) ret).pos = ((VarSymbol) sym).pos;
2007                         break;
2008                     default:
2009                         Assert.error(skind.name());
2010                         throw new AssertionError();
2011                 }
2012                 if (ret != sym && skind.propagateAnnotations()) {
2013                     ret.setDeclarationAttributes(sym.getRawAttributes());
2014                     ret.setTypeAttributes(sym.getRawTypeAttributes());
2015                 }
2016                 return ret;
2017             }
2018 
addSymbol(Symbol sym, LambdaSymbolKind skind)2019             void addSymbol(Symbol sym, LambdaSymbolKind skind) {
2020                 if (skind == CAPTURED_THIS && sym != null && sym.kind == TYP && !typesUnderConstruction.isEmpty()) {
2021                     ClassSymbol currentClass = currentClass();
2022                     if (currentClass != null && typesUnderConstruction.contains(currentClass)) {
2023                         // reference must be to enclosing outer instance, mutate capture kind.
2024                         Assert.check(sym != currentClass); // should have been caught right in Attr
2025                         skind = CAPTURED_OUTER_THIS;
2026                     }
2027                 }
2028                 Map<Symbol, Symbol> transMap = getSymbolMap(skind);
2029                 if (!transMap.containsKey(sym)) {
2030                     transMap.put(sym, translate(sym, skind));
2031                 }
2032             }
2033 
getSymbolMap(LambdaSymbolKind skind)2034             Map<Symbol, Symbol> getSymbolMap(LambdaSymbolKind skind) {
2035                 Map<Symbol, Symbol> m = translatedSymbols.get(skind);
2036                 Assert.checkNonNull(m);
2037                 return m;
2038             }
2039 
translate(JCIdent lambdaIdent)2040             JCTree translate(JCIdent lambdaIdent) {
2041                 for (LambdaSymbolKind kind : LambdaSymbolKind.values()) {
2042                     Map<Symbol, Symbol> m = getSymbolMap(kind);
2043                     switch(kind) {
2044                         default:
2045                             if (m.containsKey(lambdaIdent.sym)) {
2046                                 Symbol tSym = m.get(lambdaIdent.sym);
2047                                 JCTree t = make.Ident(tSym).setType(lambdaIdent.type);
2048                                 return t;
2049                             }
2050                             break;
2051                         case CAPTURED_OUTER_THIS:
2052                             if (lambdaIdent.sym.owner.kind == TYP && m.containsKey(lambdaIdent.sym.owner)) {
2053                                 // Transform outer instance variable references anchoring them to the captured synthetic.
2054                                 Symbol tSym = m.get(lambdaIdent.sym.owner);
2055                                 JCExpression t = make.Ident(tSym).setType(lambdaIdent.sym.owner.type);
2056                                 t = make.Select(t, lambdaIdent.name);
2057                                 t.setType(lambdaIdent.type);
2058                                 TreeInfo.setSymbol(t, lambdaIdent.sym);
2059                                 return t;
2060                             }
2061                             break;
2062                     }
2063                 }
2064                 return null;
2065             }
2066 
2067             /* Translate away qualified this expressions, anchoring them to synthetic parameters that
2068                capture the qualified this handle. `fieldAccess' is guaranteed to one such.
2069             */
translate(JCFieldAccess fieldAccess)2070             public JCTree translate(JCFieldAccess fieldAccess) {
2071                 Assert.check(fieldAccess.name == names._this);
2072                 Map<Symbol, Symbol> m = translatedSymbols.get(LambdaSymbolKind.CAPTURED_OUTER_THIS);
2073                 if (m.containsKey(fieldAccess.sym.owner)) {
2074                     Symbol tSym = m.get(fieldAccess.sym.owner);
2075                     JCExpression t = make.Ident(tSym).setType(fieldAccess.sym.owner.type);
2076                     return t;
2077                 }
2078                 return null;
2079             }
2080 
2081             /**
2082              * The translatedSym is not complete/accurate until the analysis is
2083              * finished.  Once the analysis is finished, the translatedSym is
2084              * "completed" -- updated with type information, access modifiers,
2085              * and full parameter list.
2086              */
complete()2087             void complete() {
2088                 if (syntheticParams != null) {
2089                     return;
2090                 }
2091                 boolean inInterface = translatedSym.owner.isInterface();
2092                 boolean thisReferenced = !getSymbolMap(CAPTURED_THIS).isEmpty();
2093 
2094                 // If instance access isn't needed, make it static.
2095                 // Interface instance methods must be default methods.
2096                 // Lambda methods are private synthetic.
2097                 // Inherit ACC_STRICT from the enclosing method, or, for clinit,
2098                 // from the class.
2099                 translatedSym.flags_field = SYNTHETIC | LAMBDA_METHOD |
2100                         owner.flags_field & STRICTFP |
2101                         owner.owner.flags_field & STRICTFP |
2102                         PRIVATE |
2103                         (thisReferenced? (inInterface? DEFAULT : 0) : STATIC);
2104 
2105                 //compute synthetic params
2106                 ListBuffer<JCVariableDecl> params = new ListBuffer<>();
2107                 ListBuffer<VarSymbol> parameterSymbols = new ListBuffer<>();
2108 
2109                 // The signature of the method is augmented with the following
2110                 // synthetic parameters:
2111                 //
2112                 // 1) reference to enclosing contexts captured by the lambda expression
2113                 // 2) enclosing locals captured by the lambda expression
2114                 for (Symbol thisSym : getSymbolMap(CAPTURED_VAR).values()) {
2115                     params.append(make.VarDef((VarSymbol) thisSym, null));
2116                     parameterSymbols.append((VarSymbol) thisSym);
2117                 }
2118                 for (Symbol thisSym : getSymbolMap(CAPTURED_OUTER_THIS).values()) {
2119                     params.append(make.VarDef((VarSymbol) thisSym, null));
2120                     parameterSymbols.append((VarSymbol) thisSym);
2121                 }
2122                 for (Symbol thisSym : getSymbolMap(PARAM).values()) {
2123                     params.append(make.VarDef((VarSymbol) thisSym, null));
2124                     parameterSymbols.append((VarSymbol) thisSym);
2125                 }
2126                 syntheticParams = params.toList();
2127 
2128                 translatedSym.params = parameterSymbols.toList();
2129 
2130                 // Compute and set the lambda name
2131                 translatedSym.name = isSerializable()
2132                         ? serializedLambdaName()
2133                         : lambdaName();
2134 
2135                 //prepend synthetic args to translated lambda method signature
2136                 translatedSym.type = types.createMethodTypeWithParameters(
2137                         generatedLambdaSig(),
2138                         TreeInfo.types(syntheticParams));
2139             }
2140 
generatedLambdaSig()2141             Type generatedLambdaSig() {
2142                 return types.erasure(tree.getDescriptorType(types));
2143             }
2144         }
2145 
2146         /**
2147          * This class retains all the useful information about a method reference;
2148          * the contents of this class are filled by the LambdaAnalyzer visitor,
2149          * and the used by the main translation routines in order to adjust method
2150          * references (i.e. in case a bridge is needed)
2151          */
2152         private final class ReferenceTranslationContext extends TranslationContext<JCMemberReference> {
2153 
2154             final boolean isSuper;
2155             final Symbol sigPolySym;
2156 
ReferenceTranslationContext(JCMemberReference tree)2157             ReferenceTranslationContext(JCMemberReference tree) {
2158                 super(tree);
2159                 this.isSuper = tree.hasKind(ReferenceKind.SUPER);
2160                 this.sigPolySym = isSignaturePolymorphic()
2161                         ? makePrivateSyntheticMethod(tree.sym.flags(),
2162                                               tree.sym.name,
2163                                               bridgedRefSig(),
2164                                               tree.sym.enclClass())
2165                         : null;
2166             }
2167 
2168             /**
2169              * Get the opcode associated with this method reference
2170              */
referenceKind()2171             int referenceKind() {
2172                 return LambdaToMethod.this.referenceKind(tree.sym);
2173             }
2174 
needsVarArgsConversion()2175             boolean needsVarArgsConversion() {
2176                 return tree.varargsElement != null;
2177             }
2178 
2179             /**
2180              * @return Is this an array operation like clone()
2181              */
isArrayOp()2182             boolean isArrayOp() {
2183                 return tree.sym.owner == syms.arrayClass;
2184             }
2185 
receiverAccessible()2186             boolean receiverAccessible() {
2187                 //hack needed to workaround 292 bug (7087658)
2188                 //when 292 issue is fixed we should remove this and change the backend
2189                 //code to always generate a method handle to an accessible method
2190                 return tree.ownerAccessible;
2191             }
2192 
2193             /**
2194              * The VM does not support access across nested classes (8010319).
2195              * Were that ever to change, this should be removed.
2196              */
isPrivateInOtherClass()2197             boolean isPrivateInOtherClass() {
2198                 return  (tree.sym.flags() & PRIVATE) != 0 &&
2199                         !types.isSameType(
2200                               types.erasure(tree.sym.enclClass().asType()),
2201                               types.erasure(owner.enclClass().asType()));
2202             }
2203 
2204             /**
2205              * Signature polymorphic methods need special handling.
2206              * e.g. MethodHandle.invoke() MethodHandle.invokeExact()
2207              */
isSignaturePolymorphic()2208             final boolean isSignaturePolymorphic() {
2209                 return  tree.sym.kind == MTH &&
2210                         types.isSignaturePolymorphic((MethodSymbol)tree.sym);
2211             }
2212 
2213             /**
2214              * Erasure destroys the implementation parameter subtype
2215              * relationship for intersection types
2216              */
interfaceParameterIsIntersectionType()2217             boolean interfaceParameterIsIntersectionType() {
2218                 List<Type> tl = tree.getDescriptorType(types).getParameterTypes();
2219                 if (tree.kind == ReferenceKind.UNBOUND) {
2220                     tl = tl.tail;
2221                 }
2222                 for (; tl.nonEmpty(); tl = tl.tail) {
2223                     Type pt = tl.head;
2224                     if (pt.getKind() == TypeKind.TYPEVAR) {
2225                         TypeVar tv = (TypeVar) pt;
2226                         if (tv.bound.getKind() == TypeKind.INTERSECTION) {
2227                             return true;
2228                         }
2229                     }
2230                 }
2231                 return false;
2232             }
2233 
2234             /**
2235              * Does this reference need to be converted to a lambda
2236              * (i.e. var args need to be expanded or "super" is used)
2237              */
needsConversionToLambda()2238             final boolean needsConversionToLambda() {
2239                 return interfaceParameterIsIntersectionType() ||
2240                         isSuper ||
2241                         needsVarArgsConversion() ||
2242                         isArrayOp() ||
2243                         isPrivateInOtherClass() ||
2244                         !receiverAccessible() ||
2245                         (tree.getMode() == ReferenceMode.NEW &&
2246                           tree.kind != ReferenceKind.ARRAY_CTOR &&
2247                           (tree.sym.owner.isLocal() || tree.sym.owner.isInner()));
2248             }
2249 
generatedRefSig()2250             Type generatedRefSig() {
2251                 return types.erasure(tree.sym.type);
2252             }
2253 
bridgedRefSig()2254             Type bridgedRefSig() {
2255                 return types.erasure(types.findDescriptorSymbol(tree.targets.head.tsym).type);
2256             }
2257         }
2258     }
2259     // </editor-fold>
2260 
2261     /*
2262      * These keys provide mappings for various translated lambda symbols
2263      * and the prevailing order must be maintained.
2264      */
2265     enum LambdaSymbolKind {
2266         PARAM,          // original to translated lambda parameters
2267         LOCAL_VAR,      // original to translated lambda locals
2268         CAPTURED_VAR,   // variables in enclosing scope to translated synthetic parameters
2269         CAPTURED_THIS,  // class symbols to translated synthetic parameters (for captured member access)
2270         CAPTURED_OUTER_THIS, // used when `this' capture is illegal, but outer this capture is legit (JDK-8129740)
2271         TYPE_VAR;       // original to translated lambda type variables
2272 
propagateAnnotations()2273         boolean propagateAnnotations() {
2274             switch (this) {
2275                 case CAPTURED_VAR:
2276                 case CAPTURED_THIS:
2277                 case CAPTURED_OUTER_THIS:
2278                     return false;
2279                 default:
2280                     return true;
2281            }
2282         }
2283     }
2284 
2285     /**
2286      * ****************************************************************
2287      * Signature Generation
2288      * ****************************************************************
2289      */
2290 
typeSig(Type type)2291     private String typeSig(Type type) {
2292         L2MSignatureGenerator sg = new L2MSignatureGenerator();
2293         sg.assembleSig(type);
2294         return sg.toString();
2295     }
2296 
classSig(Type type)2297     private String classSig(Type type) {
2298         L2MSignatureGenerator sg = new L2MSignatureGenerator();
2299         sg.assembleClassSig(type);
2300         return sg.toString();
2301     }
2302 
2303     /**
2304      * Signature Generation
2305      */
2306     private class L2MSignatureGenerator extends Types.SignatureGenerator {
2307 
2308         /**
2309          * An output buffer for type signatures.
2310          */
2311         StringBuilder sb = new StringBuilder();
2312 
L2MSignatureGenerator()2313         L2MSignatureGenerator() {
2314             super(types);
2315         }
2316 
2317         @Override
append(char ch)2318         protected void append(char ch) {
2319             sb.append(ch);
2320         }
2321 
2322         @Override
append(byte[] ba)2323         protected void append(byte[] ba) {
2324             sb.append(new String(ba));
2325         }
2326 
2327         @Override
append(Name name)2328         protected void append(Name name) {
2329             sb.append(name.toString());
2330         }
2331 
2332         @Override
toString()2333         public String toString() {
2334             return sb.toString();
2335         }
2336     }
2337 }
2338