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