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