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