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