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