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