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