Fri, 13 Dec 2013 14:13:03 +0000
8029721: javac crash for annotated parameter type of lambda in a field
Reviewed-by: rfield, jfranck
1 /*
2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25 package com.sun.tools.javac.comp;
27 import com.sun.tools.javac.tree.*;
28 import com.sun.tools.javac.tree.JCTree.*;
29 import com.sun.tools.javac.tree.JCTree.JCMemberReference.ReferenceKind;
30 import com.sun.tools.javac.tree.TreeMaker;
31 import com.sun.tools.javac.tree.TreeTranslator;
32 import com.sun.tools.javac.code.Attribute;
33 import com.sun.tools.javac.code.Kinds;
34 import com.sun.tools.javac.code.Scope;
35 import com.sun.tools.javac.code.Symbol;
36 import com.sun.tools.javac.code.Symbol.ClassSymbol;
37 import com.sun.tools.javac.code.Symbol.DynamicMethodSymbol;
38 import com.sun.tools.javac.code.Symbol.MethodSymbol;
39 import com.sun.tools.javac.code.Symbol.VarSymbol;
40 import com.sun.tools.javac.code.Symtab;
41 import com.sun.tools.javac.code.Type;
42 import com.sun.tools.javac.code.Type.MethodType;
43 import com.sun.tools.javac.code.Types;
44 import com.sun.tools.javac.comp.LambdaToMethod.LambdaAnalyzerPreprocessor.*;
45 import com.sun.tools.javac.comp.Lower.BasicFreeVarCollector;
46 import com.sun.tools.javac.jvm.*;
47 import com.sun.tools.javac.util.*;
48 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
49 import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
51 import java.util.EnumMap;
52 import java.util.HashMap;
53 import java.util.LinkedHashMap;
54 import java.util.Map;
56 import static com.sun.tools.javac.comp.LambdaToMethod.LambdaSymbolKind.*;
57 import static com.sun.tools.javac.code.Flags.*;
58 import static com.sun.tools.javac.code.Kinds.*;
59 import static com.sun.tools.javac.code.TypeTag.*;
60 import static com.sun.tools.javac.tree.JCTree.Tag.*;
62 /**
63 * This pass desugars lambda expressions into static methods
64 *
65 * <p><b>This is NOT part of any supported API.
66 * If you write code that depends on this, you do so at your own risk.
67 * This code and its internal interfaces are subject to change or
68 * deletion without notice.</b>
69 */
70 public class LambdaToMethod extends TreeTranslator {
72 private Attr attr;
73 private JCDiagnostic.Factory diags;
74 private Log log;
75 private Lower lower;
76 private Names names;
77 private Symtab syms;
78 private Resolve rs;
79 private TreeMaker make;
80 private Types types;
81 private TransTypes transTypes;
82 private Env<AttrContext> attrEnv;
84 /** the analyzer scanner */
85 private LambdaAnalyzerPreprocessor analyzer;
87 /** map from lambda trees to translation contexts */
88 private Map<JCTree, TranslationContext<?>> contextMap;
90 /** current translation context (visitor argument) */
91 private TranslationContext<?> context;
93 /** info about the current class being processed */
94 private KlassInfo kInfo;
96 /** dump statistics about lambda code generation */
97 private boolean dumpLambdaToMethodStats;
99 /** Flag for alternate metafactories indicating the lambda object is intended to be serializable */
100 public static final int FLAG_SERIALIZABLE = 1 << 0;
102 /** Flag for alternate metafactories indicating the lambda object has multiple targets */
103 public static final int FLAG_MARKERS = 1 << 1;
105 /** Flag for alternate metafactories indicating the lambda object requires multiple bridges */
106 public static final int FLAG_BRIDGES = 1 << 2;
108 // <editor-fold defaultstate="collapsed" desc="Instantiating">
109 protected static final Context.Key<LambdaToMethod> unlambdaKey =
110 new Context.Key<LambdaToMethod>();
112 public static LambdaToMethod instance(Context context) {
113 LambdaToMethod instance = context.get(unlambdaKey);
114 if (instance == null) {
115 instance = new LambdaToMethod(context);
116 }
117 return instance;
118 }
119 private LambdaToMethod(Context context) {
120 context.put(unlambdaKey, this);
121 diags = JCDiagnostic.Factory.instance(context);
122 log = Log.instance(context);
123 lower = Lower.instance(context);
124 names = Names.instance(context);
125 syms = Symtab.instance(context);
126 rs = Resolve.instance(context);
127 make = TreeMaker.instance(context);
128 types = Types.instance(context);
129 transTypes = TransTypes.instance(context);
130 analyzer = new LambdaAnalyzerPreprocessor();
131 Options options = Options.instance(context);
132 dumpLambdaToMethodStats = options.isSet("dumpLambdaToMethodStats");
133 attr = Attr.instance(context);
134 }
135 // </editor-fold>
137 private class KlassInfo {
139 /**
140 * list of methods to append
141 */
142 private ListBuffer<JCTree> appendedMethodList;
144 /**
145 * list of deserialization cases
146 */
147 private final Map<String, ListBuffer<JCStatement>> deserializeCases;
149 /**
150 * deserialize method symbol
151 */
152 private final MethodSymbol deserMethodSym;
154 /**
155 * deserialize method parameter symbol
156 */
157 private final VarSymbol deserParamSym;
159 private final JCClassDecl clazz;
161 private KlassInfo(JCClassDecl clazz) {
162 this.clazz = clazz;
163 appendedMethodList = new ListBuffer<>();
164 deserializeCases = new HashMap<String, ListBuffer<JCStatement>>();
165 MethodType type = new MethodType(List.of(syms.serializedLambdaType), syms.objectType,
166 List.<Type>nil(), syms.methodClass);
167 deserMethodSym = makePrivateSyntheticMethod(STATIC, names.deserializeLambda, type, clazz.sym);
168 deserParamSym = new VarSymbol(FINAL, names.fromString("lambda"),
169 syms.serializedLambdaType, deserMethodSym);
170 }
172 private void addMethod(JCTree decl) {
173 appendedMethodList = appendedMethodList.prepend(decl);
174 }
175 }
177 // <editor-fold defaultstate="collapsed" desc="translate methods">
178 @Override
179 public <T extends JCTree> T translate(T tree) {
180 TranslationContext<?> newContext = contextMap.get(tree);
181 return translate(tree, newContext != null ? newContext : context);
182 }
184 <T extends JCTree> T translate(T tree, TranslationContext<?> newContext) {
185 TranslationContext<?> prevContext = context;
186 try {
187 context = newContext;
188 return super.translate(tree);
189 }
190 finally {
191 context = prevContext;
192 }
193 }
195 <T extends JCTree> List<T> translate(List<T> trees, TranslationContext<?> newContext) {
196 ListBuffer<T> buf = new ListBuffer<>();
197 for (T tree : trees) {
198 buf.append(translate(tree, newContext));
199 }
200 return buf.toList();
201 }
203 public JCTree translateTopLevelClass(Env<AttrContext> env, JCTree cdef, TreeMaker make) {
204 this.make = make;
205 this.attrEnv = env;
206 this.context = null;
207 this.contextMap = new HashMap<JCTree, TranslationContext<?>>();
208 return translate(cdef);
209 }
210 // </editor-fold>
212 // <editor-fold defaultstate="collapsed" desc="visitor methods">
213 /**
214 * Visit a class.
215 * Maintain the translatedMethodList across nested classes.
216 * Append the translatedMethodList to the class after it is translated.
217 * @param tree
218 */
219 @Override
220 public void visitClassDef(JCClassDecl tree) {
221 if (tree.sym.owner.kind == PCK) {
222 //analyze class
223 tree = analyzer.analyzeAndPreprocessClass(tree);
224 }
225 KlassInfo prevKlassInfo = kInfo;
226 try {
227 kInfo = new KlassInfo(tree);
228 super.visitClassDef(tree);
229 if (!kInfo.deserializeCases.isEmpty()) {
230 int prevPos = make.pos;
231 try {
232 make.at(tree);
233 kInfo.addMethod(makeDeserializeMethod(tree.sym));
234 } finally {
235 make.at(prevPos);
236 }
237 }
238 //add all translated instance methods here
239 List<JCTree> newMethods = kInfo.appendedMethodList.toList();
240 tree.defs = tree.defs.appendList(newMethods);
241 for (JCTree lambda : newMethods) {
242 tree.sym.members().enter(((JCMethodDecl)lambda).sym);
243 }
244 result = tree;
245 } finally {
246 kInfo = prevKlassInfo;
247 }
248 }
250 /**
251 * Translate a lambda into a method to be inserted into the class.
252 * Then replace the lambda site with an invokedynamic call of to lambda
253 * meta-factory, which will use the lambda method.
254 * @param tree
255 */
256 @Override
257 public void visitLambda(JCLambda tree) {
258 LambdaTranslationContext localContext = (LambdaTranslationContext)context;
259 MethodSymbol sym = (MethodSymbol)localContext.translatedSym;
260 MethodType lambdaType = (MethodType) sym.type;
262 {
263 Symbol owner = localContext.owner;
264 ListBuffer<Attribute.TypeCompound> ownerTypeAnnos = new ListBuffer<Attribute.TypeCompound>();
265 ListBuffer<Attribute.TypeCompound> lambdaTypeAnnos = new ListBuffer<Attribute.TypeCompound>();
267 for (Attribute.TypeCompound tc : owner.getRawTypeAttributes()) {
268 if (tc.position.onLambda == tree) {
269 lambdaTypeAnnos.append(tc);
270 } else {
271 ownerTypeAnnos.append(tc);
272 }
273 }
274 if (lambdaTypeAnnos.nonEmpty()) {
275 owner.setTypeAttributes(ownerTypeAnnos.toList());
276 sym.setTypeAttributes(lambdaTypeAnnos.toList());
277 }
278 }
280 //create the method declaration hoisting the lambda body
281 JCMethodDecl lambdaDecl = make.MethodDef(make.Modifiers(sym.flags_field),
282 sym.name,
283 make.QualIdent(lambdaType.getReturnType().tsym),
284 List.<JCTypeParameter>nil(),
285 localContext.syntheticParams,
286 lambdaType.getThrownTypes() == null ?
287 List.<JCExpression>nil() :
288 make.Types(lambdaType.getThrownTypes()),
289 null,
290 null);
291 lambdaDecl.sym = sym;
292 lambdaDecl.type = lambdaType;
294 //translate lambda body
295 //As the lambda body is translated, all references to lambda locals,
296 //captured variables, enclosing members are adjusted accordingly
297 //to refer to the static method parameters (rather than i.e. acessing to
298 //captured members directly).
299 lambdaDecl.body = translate(makeLambdaBody(tree, lambdaDecl));
301 //Add the method to the list of methods to be added to this class.
302 kInfo.addMethod(lambdaDecl);
304 //now that we have generated a method for the lambda expression,
305 //we can translate the lambda into a method reference pointing to the newly
306 //created method.
307 //
308 //Note that we need to adjust the method handle so that it will match the
309 //signature of the SAM descriptor - this means that the method reference
310 //should be added the following synthetic arguments:
311 //
312 // * the "this" argument if it is an instance method
313 // * enclosing locals captured by the lambda expression
315 ListBuffer<JCExpression> syntheticInits = new ListBuffer<>();
317 if (!sym.isStatic()) {
318 syntheticInits.append(makeThis(
319 sym.owner.enclClass().asType(),
320 localContext.owner.enclClass()));
321 }
323 //add captured locals
324 for (Symbol fv : localContext.getSymbolMap(CAPTURED_VAR).keySet()) {
325 if (fv != localContext.self) {
326 JCTree captured_local = make.Ident(fv).setType(fv.type);
327 syntheticInits.append((JCExpression) captured_local);
328 }
329 }
331 //then, determine the arguments to the indy call
332 List<JCExpression> indy_args = translate(syntheticInits.toList(), localContext.prev);
334 //build a sam instance using an indy call to the meta-factory
335 int refKind = referenceKind(sym);
337 //convert to an invokedynamic call
338 result = makeMetafactoryIndyCall(context, refKind, sym, indy_args);
339 }
341 private JCIdent makeThis(Type type, Symbol owner) {
342 VarSymbol _this = new VarSymbol(PARAMETER | FINAL | SYNTHETIC,
343 names._this,
344 type,
345 owner);
346 return make.Ident(_this);
347 }
349 /**
350 * Translate a method reference into an invokedynamic call to the
351 * meta-factory.
352 * @param tree
353 */
354 @Override
355 public void visitReference(JCMemberReference tree) {
356 ReferenceTranslationContext localContext = (ReferenceTranslationContext)context;
358 //first determine the method symbol to be used to generate the sam instance
359 //this is either the method reference symbol, or the bridged reference symbol
360 Symbol refSym = localContext.needsBridge()
361 ? localContext.bridgeSym
362 : localContext.isSignaturePolymorphic()
363 ? localContext.sigPolySym
364 : tree.sym;
366 //build the bridge method, if needed
367 if (localContext.needsBridge()) {
368 bridgeMemberReference(tree, localContext);
369 }
371 //the qualifying expression is treated as a special captured arg
372 JCExpression init;
373 switch(tree.kind) {
375 case IMPLICIT_INNER: /** Inner :: new */
376 case SUPER: /** super :: instMethod */
377 init = makeThis(
378 localContext.owner.enclClass().asType(),
379 localContext.owner.enclClass());
380 break;
382 case BOUND: /** Expr :: instMethod */
383 init = tree.getQualifierExpression();
384 init = attr.makeNullCheck(init);
385 break;
387 case UNBOUND: /** Type :: instMethod */
388 case STATIC: /** Type :: staticMethod */
389 case TOPLEVEL: /** Top level :: new */
390 case ARRAY_CTOR: /** ArrayType :: new */
391 init = null;
392 break;
394 default:
395 throw new InternalError("Should not have an invalid kind");
396 }
398 List<JCExpression> indy_args = init==null? List.<JCExpression>nil() : translate(List.of(init), localContext.prev);
401 //build a sam instance using an indy call to the meta-factory
402 result = makeMetafactoryIndyCall(localContext, localContext.referenceKind(), refSym, indy_args);
403 }
405 /**
406 * Translate identifiers within a lambda to the mapped identifier
407 * @param tree
408 */
409 @Override
410 public void visitIdent(JCIdent tree) {
411 if (context == null || !analyzer.lambdaIdentSymbolFilter(tree.sym)) {
412 super.visitIdent(tree);
413 } else {
414 int prevPos = make.pos;
415 try {
416 make.at(tree);
418 LambdaTranslationContext lambdaContext = (LambdaTranslationContext) context;
419 JCTree ltree = lambdaContext.translate(tree);
420 if (ltree != null) {
421 result = ltree;
422 } else {
423 //access to untranslated symbols (i.e. compile-time constants,
424 //members defined inside the lambda body, etc.) )
425 super.visitIdent(tree);
426 }
427 } finally {
428 make.at(prevPos);
429 }
430 }
431 }
433 @Override
434 public void visitVarDef(JCVariableDecl tree) {
435 LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context;
436 if (context != null && lambdaContext.getSymbolMap(LOCAL_VAR).containsKey(tree.sym)) {
437 JCExpression init = translate(tree.init);
438 int prevPos = make.pos;
439 try {
440 result = make.at(tree).VarDef((VarSymbol)lambdaContext.getSymbolMap(LOCAL_VAR).get(tree.sym), init);
441 } finally {
442 make.at(prevPos);
443 }
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 Scope 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 }
464 // </editor-fold>
466 // <editor-fold defaultstate="collapsed" desc="Translation helper methods">
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 }
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 }
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);
509 class LambdaBodyTranslator extends TreeTranslator {
511 @Override
512 public void visitClassDef(JCClassDecl tree) {
513 //do NOT recurse on any inner classes
514 result = tree;
515 }
517 @Override
518 public void visitLambda(JCLambda tree) {
519 //do NOT recurse on any nested lambdas
520 result = tree;
521 }
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 }
541 }
542 }
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 }
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 }
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 }
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 }
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));
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 }
657 private JCExpression eqTest(Type argType, JCExpression arg1, JCExpression arg2) {
658 JCBinary testExpr = make.Binary(JCTree.Tag.EQ, arg1, arg2);
659 testExpr.operator = rs.resolveBinaryOperator(null, JCTree.Tag.EQ, attrEnv, argType, argType);
660 testExpr.setType(syms.booleanType);
661 return testExpr;
662 }
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 = rs.resolveBinaryOperator(null, JCTree.Tag.AND, attrEnv, syms.booleanType, syms.booleanType);
674 compound.setType(syms.booleanType);
675 return compound;
676 }
678 private JCExpression deserGetter(String func, Type type) {
679 return deserGetter(func, type, List.<Type>nil(), List.<JCExpression>nil());
680 }
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 }
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 }
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 }
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 }
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 }
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 == Kinds.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 }
741 // </editor-fold>
743 /**
744 * Generate an adapter method "bridge" for a method reference which cannot
745 * be used directly.
746 */
747 private class MemberReferenceBridger {
749 private final JCMemberReference tree;
750 private final ReferenceTranslationContext localContext;
751 private final ListBuffer<JCExpression> args = new ListBuffer<>();
752 private final ListBuffer<JCVariableDecl> params = new ListBuffer<>();
754 MemberReferenceBridger(JCMemberReference tree, ReferenceTranslationContext localContext) {
755 this.tree = tree;
756 this.localContext = localContext;
757 }
759 /**
760 * Generate the bridge
761 */
762 JCMethodDecl bridge() {
763 int prevPos = make.pos;
764 try {
765 make.at(tree);
766 Type samDesc = localContext.bridgedRefSig();
767 List<Type> samPTypes = samDesc.getParameterTypes();
769 //an extra argument is prepended to the signature of the bridge in case
770 //the member reference is an instance method reference (in which case
771 //the receiver expression is passed to the bridge itself).
772 Type recType = null;
773 switch (tree.kind) {
774 case IMPLICIT_INNER:
775 recType = tree.sym.owner.type.getEnclosingType();
776 break;
777 case BOUND:
778 recType = tree.getQualifierExpression().type;
779 break;
780 case UNBOUND:
781 recType = samPTypes.head;
782 samPTypes = samPTypes.tail;
783 break;
784 }
786 //generate the parameter list for the bridged member reference - the
787 //bridge signature will match the signature of the target sam descriptor
789 VarSymbol rcvr = (recType == null)
790 ? null
791 : addParameter("rec$", recType, false);
793 List<Type> refPTypes = tree.sym.type.getParameterTypes();
794 int refSize = refPTypes.size();
795 int samSize = samPTypes.size();
796 // Last parameter to copy from referenced method
797 int last = localContext.needsVarArgsConversion() ? refSize - 1 : refSize;
799 List<Type> l = refPTypes;
800 // Use parameter types of the referenced method, excluding final var args
801 for (int i = 0; l.nonEmpty() && i < last; ++i) {
802 addParameter("x$" + i, l.head, true);
803 l = l.tail;
804 }
805 // Flatten out the var args
806 for (int i = last; i < samSize; ++i) {
807 addParameter("xva$" + i, tree.varargsElement, true);
808 }
810 //generate the bridge method declaration
811 JCMethodDecl bridgeDecl = make.MethodDef(make.Modifiers(localContext.bridgeSym.flags()),
812 localContext.bridgeSym.name,
813 make.QualIdent(samDesc.getReturnType().tsym),
814 List.<JCTypeParameter>nil(),
815 params.toList(),
816 tree.sym.type.getThrownTypes() == null
817 ? List.<JCExpression>nil()
818 : make.Types(tree.sym.type.getThrownTypes()),
819 null,
820 null);
821 bridgeDecl.sym = (MethodSymbol) localContext.bridgeSym;
822 bridgeDecl.type = localContext.bridgeSym.type =
823 types.createMethodTypeWithParameters(samDesc, TreeInfo.types(params.toList()));
825 //bridge method body generation - this can be either a method call or a
826 //new instance creation expression, depending on the member reference kind
827 JCExpression bridgeExpr = (tree.getMode() == ReferenceMode.INVOKE)
828 ? bridgeExpressionInvoke(makeReceiver(rcvr))
829 : bridgeExpressionNew();
831 //the body is either a return expression containing a method call,
832 //or the method call itself, depending on whether the return type of
833 //the bridge is non-void/void.
834 bridgeDecl.body = makeLambdaExpressionBody(bridgeExpr, bridgeDecl);
836 return bridgeDecl;
837 } finally {
838 make.at(prevPos);
839 }
840 }
841 //where
842 private JCExpression makeReceiver(VarSymbol rcvr) {
843 if (rcvr == null) return null;
844 JCExpression rcvrExpr = make.Ident(rcvr);
845 Type rcvrType = tree.sym.enclClass().type;
846 if (!rcvr.type.tsym.isSubClass(rcvrType.tsym, types)) {
847 rcvrExpr = make.TypeCast(make.Type(rcvrType), rcvrExpr).setType(rcvrType);
848 }
849 return rcvrExpr;
850 }
852 /**
853 * determine the receiver of the bridged method call - the receiver can
854 * be either the synthetic receiver parameter or a type qualifier; the
855 * original qualifier expression is never used here, as it might refer
856 * to symbols not available in the static context of the bridge
857 */
858 private JCExpression bridgeExpressionInvoke(JCExpression rcvr) {
859 JCExpression qualifier =
860 tree.sym.isStatic() ?
861 make.Type(tree.sym.owner.type) :
862 (rcvr != null) ?
863 rcvr :
864 tree.getQualifierExpression();
866 //create the qualifier expression
867 JCFieldAccess select = make.Select(qualifier, tree.sym.name);
868 select.sym = tree.sym;
869 select.type = tree.sym.erasure(types);
871 //create the method call expression
872 JCExpression apply = make.Apply(List.<JCExpression>nil(), select,
873 convertArgs(tree.sym, args.toList(), tree.varargsElement)).
874 setType(tree.sym.erasure(types).getReturnType());
876 apply = transTypes.coerce(apply, localContext.generatedRefSig().getReturnType());
877 setVarargsIfNeeded(apply, tree.varargsElement);
878 return apply;
879 }
881 /**
882 * the enclosing expression is either 'null' (no enclosing type) or set
883 * to the first bridge synthetic parameter
884 */
885 private JCExpression bridgeExpressionNew() {
886 if (tree.kind == ReferenceKind.ARRAY_CTOR) {
887 //create the array creation expression
888 JCNewArray newArr = make.NewArray(
889 make.Type(types.elemtype(tree.getQualifierExpression().type)),
890 List.of(make.Ident(params.first())),
891 null);
892 newArr.type = tree.getQualifierExpression().type;
893 return newArr;
894 } else {
895 JCExpression encl = null;
896 switch (tree.kind) {
897 case UNBOUND:
898 case IMPLICIT_INNER:
899 encl = make.Ident(params.first());
900 }
902 //create the instance creation expression
903 JCNewClass newClass = make.NewClass(encl,
904 List.<JCExpression>nil(),
905 make.Type(tree.getQualifierExpression().type),
906 convertArgs(tree.sym, args.toList(), tree.varargsElement),
907 null);
908 newClass.constructor = tree.sym;
909 newClass.constructorType = tree.sym.erasure(types);
910 newClass.type = tree.getQualifierExpression().type;
911 setVarargsIfNeeded(newClass, tree.varargsElement);
912 return newClass;
913 }
914 }
916 private VarSymbol addParameter(String name, Type p, boolean genArg) {
917 VarSymbol vsym = new VarSymbol(0, names.fromString(name), p, localContext.bridgeSym);
918 params.append(make.VarDef(vsym, null));
919 if (genArg) {
920 args.append(make.Ident(vsym));
921 }
922 return vsym;
923 }
924 }
926 /**
927 * Bridges a member reference - this is needed when:
928 * * Var args in the referenced method need to be flattened away
929 * * super is used
930 */
931 private void bridgeMemberReference(JCMemberReference tree, ReferenceTranslationContext localContext) {
932 kInfo.addMethod(new MemberReferenceBridger(tree, localContext).bridge());
933 }
935 private MethodType typeToMethodType(Type mt) {
936 Type type = types.erasure(mt);
937 return new MethodType(type.getParameterTypes(),
938 type.getReturnType(),
939 type.getThrownTypes(),
940 syms.methodClass);
941 }
943 /**
944 * Generate an indy method call to the meta factory
945 */
946 private JCExpression makeMetafactoryIndyCall(TranslationContext<?> context,
947 int refKind, Symbol refSym, List<JCExpression> indy_args) {
948 JCFunctionalExpression tree = context.tree;
949 //determine the static bsm args
950 MethodSymbol samSym = (MethodSymbol) types.findDescriptorSymbol(tree.type.tsym);
951 List<Object> staticArgs = List.<Object>of(
952 typeToMethodType(samSym.type),
953 new Pool.MethodHandle(refKind, refSym, types),
954 typeToMethodType(tree.getDescriptorType(types)));
956 //computed indy arg types
957 ListBuffer<Type> indy_args_types = new ListBuffer<>();
958 for (JCExpression arg : indy_args) {
959 indy_args_types.append(arg.type);
960 }
962 //finally, compute the type of the indy call
963 MethodType indyType = new MethodType(indy_args_types.toList(),
964 tree.type,
965 List.<Type>nil(),
966 syms.methodClass);
968 Name metafactoryName = context.needsAltMetafactory() ?
969 names.altMetafactory : names.metafactory;
971 if (context.needsAltMetafactory()) {
972 ListBuffer<Object> markers = new ListBuffer<>();
973 for (Type t : tree.targets.tail) {
974 if (t.tsym != syms.serializableType.tsym) {
975 markers.append(t.tsym);
976 }
977 }
978 int flags = context.isSerializable() ? FLAG_SERIALIZABLE : 0;
979 boolean hasMarkers = markers.nonEmpty();
980 boolean hasBridges = context.bridges.nonEmpty();
981 if (hasMarkers) {
982 flags |= FLAG_MARKERS;
983 }
984 if (hasBridges) {
985 flags |= FLAG_BRIDGES;
986 }
987 staticArgs = staticArgs.append(flags);
988 if (hasMarkers) {
989 staticArgs = staticArgs.append(markers.length());
990 staticArgs = staticArgs.appendList(markers.toList());
991 }
992 if (hasBridges) {
993 staticArgs = staticArgs.append(context.bridges.length() - 1);
994 for (Symbol s : context.bridges) {
995 Type s_erasure = s.erasure(types);
996 if (!types.isSameType(s_erasure, samSym.erasure(types))) {
997 staticArgs = staticArgs.append(s.erasure(types));
998 }
999 }
1000 }
1001 if (context.isSerializable()) {
1002 int prevPos = make.pos;
1003 try {
1004 make.at(kInfo.clazz);
1005 addDeserializationCase(refKind, refSym, tree.type, samSym,
1006 tree, staticArgs, indyType);
1007 } finally {
1008 make.at(prevPos);
1009 }
1010 }
1011 }
1013 return makeIndyCall(tree, syms.lambdaMetafactory, metafactoryName, staticArgs, indyType, indy_args, samSym.name);
1014 }
1016 /**
1017 * Generate an indy method call with given name, type and static bootstrap
1018 * arguments types
1019 */
1020 private JCExpression makeIndyCall(DiagnosticPosition pos, Type site, Name bsmName,
1021 List<Object> staticArgs, MethodType indyType, List<JCExpression> indyArgs,
1022 Name methName) {
1023 int prevPos = make.pos;
1024 try {
1025 make.at(pos);
1026 List<Type> bsm_staticArgs = List.of(syms.methodHandleLookupType,
1027 syms.stringType,
1028 syms.methodTypeType).appendList(bsmStaticArgToTypes(staticArgs));
1030 Symbol bsm = rs.resolveInternalMethod(pos, attrEnv, site,
1031 bsmName, bsm_staticArgs, List.<Type>nil());
1033 DynamicMethodSymbol dynSym =
1034 new DynamicMethodSymbol(methName,
1035 syms.noSymbol,
1036 bsm.isStatic() ?
1037 ClassFile.REF_invokeStatic :
1038 ClassFile.REF_invokeVirtual,
1039 (MethodSymbol)bsm,
1040 indyType,
1041 staticArgs.toArray());
1043 JCFieldAccess qualifier = make.Select(make.QualIdent(site.tsym), bsmName);
1044 qualifier.sym = dynSym;
1045 qualifier.type = indyType.getReturnType();
1047 JCMethodInvocation proxyCall = make.Apply(List.<JCExpression>nil(), qualifier, indyArgs);
1048 proxyCall.type = indyType.getReturnType();
1049 return proxyCall;
1050 } finally {
1051 make.at(prevPos);
1052 }
1053 }
1054 //where
1055 private List<Type> bsmStaticArgToTypes(List<Object> args) {
1056 ListBuffer<Type> argtypes = new ListBuffer<>();
1057 for (Object arg : args) {
1058 argtypes.append(bsmStaticArgToType(arg));
1059 }
1060 return argtypes.toList();
1061 }
1063 private Type bsmStaticArgToType(Object arg) {
1064 Assert.checkNonNull(arg);
1065 if (arg instanceof ClassSymbol) {
1066 return syms.classType;
1067 } else if (arg instanceof Integer) {
1068 return syms.intType;
1069 } else if (arg instanceof Long) {
1070 return syms.longType;
1071 } else if (arg instanceof Float) {
1072 return syms.floatType;
1073 } else if (arg instanceof Double) {
1074 return syms.doubleType;
1075 } else if (arg instanceof String) {
1076 return syms.stringType;
1077 } else if (arg instanceof Pool.MethodHandle) {
1078 return syms.methodHandleType;
1079 } else if (arg instanceof MethodType) {
1080 return syms.methodTypeType;
1081 } else {
1082 Assert.error("bad static arg " + arg.getClass());
1083 return null;
1084 }
1085 }
1087 /**
1088 * Get the opcode associated with this method reference
1089 */
1090 private int referenceKind(Symbol refSym) {
1091 if (refSym.isConstructor()) {
1092 return ClassFile.REF_newInvokeSpecial;
1093 } else {
1094 if (refSym.isStatic()) {
1095 return ClassFile.REF_invokeStatic;
1096 } else if ((refSym.flags() & PRIVATE) != 0) {
1097 return ClassFile.REF_invokeSpecial;
1098 } else if (refSym.enclClass().isInterface()) {
1099 return ClassFile.REF_invokeInterface;
1100 } else {
1101 return ClassFile.REF_invokeVirtual;
1102 }
1103 }
1104 }
1106 // <editor-fold defaultstate="collapsed" desc="Lambda/reference analyzer">
1107 /**
1108 * This visitor collects information about translation of a lambda expression.
1109 * More specifically, it keeps track of the enclosing contexts and captured locals
1110 * accessed by the lambda being translated (as well as other useful info).
1111 * It also translates away problems for LambdaToMethod.
1112 */
1113 class LambdaAnalyzerPreprocessor extends TreeTranslator {
1115 /** the frame stack - used to reconstruct translation info about enclosing scopes */
1116 private List<Frame> frameStack;
1118 /**
1119 * keep the count of lambda expression (used to generate unambiguous
1120 * names)
1121 */
1122 private int lambdaCount = 0;
1124 /**
1125 * keep the count of lambda expression defined in given context (used to
1126 * generate unambiguous names for serializable lambdas)
1127 */
1128 private class SyntheticMethodNameCounter {
1129 private Map<String, Integer> map = new HashMap<>();
1130 int getIndex(StringBuilder buf) {
1131 String temp = buf.toString();
1132 Integer count = map.get(temp);
1133 if (count == null) {
1134 count = 0;
1135 }
1136 ++count;
1137 map.put(temp, count);
1138 return count;
1139 }
1140 }
1141 private SyntheticMethodNameCounter syntheticMethodNameCounts =
1142 new SyntheticMethodNameCounter();
1144 private Map<Symbol, JCClassDecl> localClassDefs;
1146 /**
1147 * maps for fake clinit symbols to be used as owners of lambda occurring in
1148 * a static var init context
1149 */
1150 private Map<ClassSymbol, Symbol> clinits =
1151 new HashMap<ClassSymbol, Symbol>();
1153 private JCClassDecl analyzeAndPreprocessClass(JCClassDecl tree) {
1154 frameStack = List.nil();
1155 localClassDefs = new HashMap<Symbol, JCClassDecl>();
1156 return translate(tree);
1157 }
1159 @Override
1160 public void visitBlock(JCBlock tree) {
1161 List<Frame> prevStack = frameStack;
1162 try {
1163 if (frameStack.nonEmpty() && frameStack.head.tree.hasTag(CLASSDEF)) {
1164 frameStack = frameStack.prepend(new Frame(tree));
1165 }
1166 super.visitBlock(tree);
1167 }
1168 finally {
1169 frameStack = prevStack;
1170 }
1171 }
1173 @Override
1174 public void visitClassDef(JCClassDecl tree) {
1175 List<Frame> prevStack = frameStack;
1176 SyntheticMethodNameCounter prevSyntheticMethodNameCounts =
1177 syntheticMethodNameCounts;
1178 Map<ClassSymbol, Symbol> prevClinits = clinits;
1179 DiagnosticSource prevSource = log.currentSource();
1180 try {
1181 log.useSource(tree.sym.sourcefile);
1182 syntheticMethodNameCounts = new SyntheticMethodNameCounter();
1183 prevClinits = new HashMap<ClassSymbol, Symbol>();
1184 if (tree.sym.owner.kind == MTH) {
1185 localClassDefs.put(tree.sym, tree);
1186 }
1187 if (directlyEnclosingLambda() != null) {
1188 tree.sym.owner = owner();
1189 if (tree.sym.hasOuterInstance()) {
1190 //if a class is defined within a lambda, the lambda must capture
1191 //its enclosing instance (if any)
1192 TranslationContext<?> localContext = context();
1193 while (localContext != null) {
1194 if (localContext.tree.getTag() == LAMBDA) {
1195 ((LambdaTranslationContext)localContext)
1196 .addSymbol(tree.sym.type.getEnclosingType().tsym, CAPTURED_THIS);
1197 }
1198 localContext = localContext.prev;
1199 }
1200 }
1201 }
1202 frameStack = frameStack.prepend(new Frame(tree));
1203 super.visitClassDef(tree);
1204 }
1205 finally {
1206 log.useSource(prevSource.getFile());
1207 frameStack = prevStack;
1208 syntheticMethodNameCounts = prevSyntheticMethodNameCounts;
1209 clinits = prevClinits;
1210 }
1211 }
1213 @Override
1214 public void visitIdent(JCIdent tree) {
1215 if (context() != null && lambdaIdentSymbolFilter(tree.sym)) {
1216 if (tree.sym.kind == VAR &&
1217 tree.sym.owner.kind == MTH &&
1218 tree.type.constValue() == null) {
1219 TranslationContext<?> localContext = context();
1220 while (localContext != null) {
1221 if (localContext.tree.getTag() == LAMBDA) {
1222 JCTree block = capturedDecl(localContext.depth, tree.sym);
1223 if (block == null) break;
1224 ((LambdaTranslationContext)localContext)
1225 .addSymbol(tree.sym, CAPTURED_VAR);
1226 }
1227 localContext = localContext.prev;
1228 }
1229 } else if (tree.sym.owner.kind == TYP) {
1230 TranslationContext<?> localContext = context();
1231 while (localContext != null) {
1232 if (localContext.tree.hasTag(LAMBDA)) {
1233 JCTree block = capturedDecl(localContext.depth, tree.sym);
1234 if (block == null) break;
1235 switch (block.getTag()) {
1236 case CLASSDEF:
1237 JCClassDecl cdecl = (JCClassDecl)block;
1238 ((LambdaTranslationContext)localContext)
1239 .addSymbol(cdecl.sym, CAPTURED_THIS);
1240 break;
1241 default:
1242 Assert.error("bad block kind");
1243 }
1244 }
1245 localContext = localContext.prev;
1246 }
1247 }
1248 }
1249 super.visitIdent(tree);
1250 }
1252 @Override
1253 public void visitLambda(JCLambda tree) {
1254 List<Frame> prevStack = frameStack;
1255 try {
1256 LambdaTranslationContext context = (LambdaTranslationContext)makeLambdaContext(tree);
1257 frameStack = frameStack.prepend(new Frame(tree));
1258 for (JCVariableDecl param : tree.params) {
1259 context.addSymbol(param.sym, PARAM);
1260 frameStack.head.addLocal(param.sym);
1261 }
1262 contextMap.put(tree, context);
1263 super.visitLambda(tree);
1264 context.complete();
1265 }
1266 finally {
1267 frameStack = prevStack;
1268 }
1269 }
1271 @Override
1272 public void visitMethodDef(JCMethodDecl tree) {
1273 List<Frame> prevStack = frameStack;
1274 try {
1275 frameStack = frameStack.prepend(new Frame(tree));
1276 super.visitMethodDef(tree);
1277 }
1278 finally {
1279 frameStack = prevStack;
1280 }
1281 }
1283 @Override
1284 public void visitNewClass(JCNewClass tree) {
1285 if (lambdaNewClassFilter(context(), tree)) {
1286 TranslationContext<?> localContext = context();
1287 while (localContext != null) {
1288 if (localContext.tree.getTag() == LAMBDA) {
1289 ((LambdaTranslationContext)localContext)
1290 .addSymbol(tree.type.getEnclosingType().tsym, CAPTURED_THIS);
1291 }
1292 localContext = localContext.prev;
1293 }
1294 }
1295 if (context() != null && tree.type.tsym.owner.kind == MTH) {
1296 LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context();
1297 captureLocalClassDefs(tree.type.tsym, lambdaContext);
1298 }
1299 super.visitNewClass(tree);
1300 }
1301 //where
1302 void captureLocalClassDefs(Symbol csym, final LambdaTranslationContext lambdaContext) {
1303 JCClassDecl localCDef = localClassDefs.get(csym);
1304 if (localCDef != null && localCDef.pos < lambdaContext.tree.pos) {
1305 BasicFreeVarCollector fvc = lower.new BasicFreeVarCollector() {
1306 @Override
1307 void addFreeVars(ClassSymbol c) {
1308 captureLocalClassDefs(c, lambdaContext);
1309 }
1310 @Override
1311 void visitSymbol(Symbol sym) {
1312 if (sym.kind == VAR &&
1313 sym.owner.kind == MTH &&
1314 ((VarSymbol)sym).getConstValue() == null) {
1315 TranslationContext<?> localContext = context();
1316 while (localContext != null) {
1317 if (localContext.tree.getTag() == LAMBDA) {
1318 JCTree block = capturedDecl(localContext.depth, sym);
1319 if (block == null) break;
1320 ((LambdaTranslationContext)localContext).addSymbol(sym, CAPTURED_VAR);
1321 }
1322 localContext = localContext.prev;
1323 }
1324 }
1325 }
1326 };
1327 fvc.scan(localCDef);
1328 }
1329 }
1331 /**
1332 * Method references to local class constructors, may, if the local
1333 * class references local variables, have implicit constructor
1334 * parameters added in Lower; As a result, the invokedynamic bootstrap
1335 * information added in the LambdaToMethod pass will have the wrong
1336 * signature. Hooks between Lower and LambdaToMethod have been added to
1337 * handle normal "new" in this case. This visitor converts potentially
1338 * effected method references into a lambda containing a normal "new" of
1339 * the class.
1340 *
1341 * @param tree
1342 */
1343 @Override
1344 public void visitReference(JCMemberReference tree) {
1345 if (tree.getMode() == ReferenceMode.NEW
1346 && tree.kind != ReferenceKind.ARRAY_CTOR
1347 && tree.sym.owner.isLocal()) {
1348 MethodSymbol consSym = (MethodSymbol) tree.sym;
1349 List<Type> ptypes = ((MethodType) consSym.type).getParameterTypes();
1350 Type classType = consSym.owner.type;
1352 // Build lambda parameters
1353 // partially cloned from TreeMaker.Params until 8014021 is fixed
1354 Symbol owner = owner();
1355 ListBuffer<JCVariableDecl> paramBuff = new ListBuffer<JCVariableDecl>();
1356 int i = 0;
1357 for (List<Type> l = ptypes; l.nonEmpty(); l = l.tail) {
1358 JCVariableDecl param = make.Param(make.paramName(i++), l.head, owner);
1359 param.sym.pos = tree.pos;
1360 paramBuff.append(param);
1361 }
1362 List<JCVariableDecl> params = paramBuff.toList();
1364 // Make new-class call
1365 JCNewClass nc = makeNewClass(classType, make.Idents(params));
1366 nc.pos = tree.pos;
1368 // Make lambda holding the new-class call
1369 JCLambda slam = make.Lambda(params, nc);
1370 slam.targets = tree.targets;
1371 slam.type = tree.type;
1372 slam.pos = tree.pos;
1374 // Now it is a lambda, process as such
1375 visitLambda(slam);
1376 } else {
1377 super.visitReference(tree);
1378 contextMap.put(tree, makeReferenceContext(tree));
1379 }
1380 }
1382 @Override
1383 public void visitSelect(JCFieldAccess tree) {
1384 if (context() != null && tree.sym.kind == VAR &&
1385 (tree.sym.name == names._this ||
1386 tree.sym.name == names._super)) {
1387 // A select of this or super means, if we are in a lambda,
1388 // we much have an instance context
1389 TranslationContext<?> localContext = context();
1390 while (localContext != null) {
1391 if (localContext.tree.hasTag(LAMBDA)) {
1392 JCClassDecl clazz = (JCClassDecl)capturedDecl(localContext.depth, tree.sym);
1393 if (clazz == null) break;
1394 ((LambdaTranslationContext)localContext).addSymbol(clazz.sym, CAPTURED_THIS);
1395 }
1396 localContext = localContext.prev;
1397 }
1398 }
1399 super.visitSelect(tree);
1400 }
1402 @Override
1403 public void visitVarDef(JCVariableDecl tree) {
1404 TranslationContext<?> context = context();
1405 LambdaTranslationContext ltc = (context != null && context instanceof LambdaTranslationContext)?
1406 (LambdaTranslationContext)context :
1407 null;
1408 if (ltc != null) {
1409 if (frameStack.head.tree.hasTag(LAMBDA)) {
1410 ltc.addSymbol(tree.sym, LOCAL_VAR);
1411 }
1412 // Check for type variables (including as type arguments).
1413 // If they occur within class nested in a lambda, mark for erasure
1414 Type type = tree.sym.asType();
1415 if (inClassWithinLambda() && !types.isSameType(types.erasure(type), type)) {
1416 ltc.addSymbol(tree.sym, TYPE_VAR);
1417 }
1418 }
1420 List<Frame> prevStack = frameStack;
1421 try {
1422 if (tree.sym.owner.kind == MTH) {
1423 frameStack.head.addLocal(tree.sym);
1424 }
1425 frameStack = frameStack.prepend(new Frame(tree));
1426 super.visitVarDef(tree);
1427 }
1428 finally {
1429 frameStack = prevStack;
1430 }
1431 }
1433 /**
1434 * Return a valid owner given the current declaration stack
1435 * (required to skip synthetic lambda symbols)
1436 */
1437 private Symbol owner() {
1438 return owner(false);
1439 }
1441 @SuppressWarnings("fallthrough")
1442 private Symbol owner(boolean skipLambda) {
1443 List<Frame> frameStack2 = frameStack;
1444 while (frameStack2.nonEmpty()) {
1445 switch (frameStack2.head.tree.getTag()) {
1446 case VARDEF:
1447 if (((JCVariableDecl)frameStack2.head.tree).sym.isLocal()) {
1448 frameStack2 = frameStack2.tail;
1449 break;
1450 }
1451 JCClassDecl cdecl = (JCClassDecl)frameStack2.tail.head.tree;
1452 return initSym(cdecl.sym,
1453 ((JCVariableDecl)frameStack2.head.tree).sym.flags() & STATIC);
1454 case BLOCK:
1455 JCClassDecl cdecl2 = (JCClassDecl)frameStack2.tail.head.tree;
1456 return initSym(cdecl2.sym,
1457 ((JCBlock)frameStack2.head.tree).flags & STATIC);
1458 case CLASSDEF:
1459 return ((JCClassDecl)frameStack2.head.tree).sym;
1460 case METHODDEF:
1461 return ((JCMethodDecl)frameStack2.head.tree).sym;
1462 case LAMBDA:
1463 if (!skipLambda)
1464 return ((LambdaTranslationContext)contextMap
1465 .get(frameStack2.head.tree)).translatedSym;
1466 default:
1467 frameStack2 = frameStack2.tail;
1468 }
1469 }
1470 Assert.error();
1471 return null;
1472 }
1474 private Symbol initSym(ClassSymbol csym, long flags) {
1475 boolean isStatic = (flags & STATIC) != 0;
1476 if (isStatic) {
1477 /* static clinits are generated in Gen, so we need to use a fake
1478 * one. Attr creates a fake clinit method while attributing
1479 * lambda expressions used as initializers of static fields, so
1480 * let's use that one.
1481 */
1482 MethodSymbol clinit = attr.removeClinit(csym);
1483 if (clinit != null) {
1484 clinits.put(csym, clinit);
1485 return clinit;
1486 }
1488 /* if no clinit is found at Attr, then let's try at clinits.
1489 */
1490 clinit = (MethodSymbol)clinits.get(csym);
1491 if (clinit == null) {
1492 /* no luck, let's create a new one
1493 */
1494 clinit = makePrivateSyntheticMethod(STATIC,
1495 names.clinit,
1496 new MethodType(List.<Type>nil(), syms.voidType,
1497 List.<Type>nil(), syms.methodClass),
1498 csym);
1499 clinits.put(csym, clinit);
1500 }
1501 return clinit;
1502 } else {
1503 //get the first constructor and treat it as the instance init sym
1504 for (Symbol s : csym.members_field.getElementsByName(names.init)) {
1505 return s;
1506 }
1507 }
1508 Assert.error("init not found");
1509 return null;
1510 }
1512 private JCTree directlyEnclosingLambda() {
1513 if (frameStack.isEmpty()) {
1514 return null;
1515 }
1516 List<Frame> frameStack2 = frameStack;
1517 while (frameStack2.nonEmpty()) {
1518 switch (frameStack2.head.tree.getTag()) {
1519 case CLASSDEF:
1520 case METHODDEF:
1521 return null;
1522 case LAMBDA:
1523 return frameStack2.head.tree;
1524 default:
1525 frameStack2 = frameStack2.tail;
1526 }
1527 }
1528 Assert.error();
1529 return null;
1530 }
1532 private boolean inClassWithinLambda() {
1533 if (frameStack.isEmpty()) {
1534 return false;
1535 }
1536 List<Frame> frameStack2 = frameStack;
1537 boolean classFound = false;
1538 while (frameStack2.nonEmpty()) {
1539 switch (frameStack2.head.tree.getTag()) {
1540 case LAMBDA:
1541 return classFound;
1542 case CLASSDEF:
1543 classFound = true;
1544 frameStack2 = frameStack2.tail;
1545 break;
1546 default:
1547 frameStack2 = frameStack2.tail;
1548 }
1549 }
1550 // No lambda
1551 return false;
1552 }
1554 /**
1555 * Return the declaration corresponding to a symbol in the enclosing
1556 * scope; the depth parameter is used to filter out symbols defined
1557 * in nested scopes (which do not need to undergo capture).
1558 */
1559 private JCTree capturedDecl(int depth, Symbol sym) {
1560 int currentDepth = frameStack.size() - 1;
1561 for (Frame block : frameStack) {
1562 switch (block.tree.getTag()) {
1563 case CLASSDEF:
1564 ClassSymbol clazz = ((JCClassDecl)block.tree).sym;
1565 if (sym.isMemberOf(clazz, types)) {
1566 return currentDepth > depth ? null : block.tree;
1567 }
1568 break;
1569 case VARDEF:
1570 if (((JCVariableDecl)block.tree).sym == sym &&
1571 sym.owner.kind == MTH) { //only locals are captured
1572 return currentDepth > depth ? null : block.tree;
1573 }
1574 break;
1575 case BLOCK:
1576 case METHODDEF:
1577 case LAMBDA:
1578 if (block.locals != null && block.locals.contains(sym)) {
1579 return currentDepth > depth ? null : block.tree;
1580 }
1581 break;
1582 default:
1583 Assert.error("bad decl kind " + block.tree.getTag());
1584 }
1585 currentDepth--;
1586 }
1587 return null;
1588 }
1590 private TranslationContext<?> context() {
1591 for (Frame frame : frameStack) {
1592 TranslationContext<?> context = contextMap.get(frame.tree);
1593 if (context != null) {
1594 return context;
1595 }
1596 }
1597 return null;
1598 }
1600 /**
1601 * This is used to filter out those identifiers that needs to be adjusted
1602 * when translating away lambda expressions
1603 */
1604 private boolean lambdaIdentSymbolFilter(Symbol sym) {
1605 return (sym.kind == VAR || sym.kind == MTH)
1606 && !sym.isStatic()
1607 && sym.name != names.init;
1608 }
1610 /**
1611 * This is used to filter out those new class expressions that need to
1612 * be qualified with an enclosing tree
1613 */
1614 private boolean lambdaNewClassFilter(TranslationContext<?> context, JCNewClass tree) {
1615 if (context != null
1616 && tree.encl == null
1617 && tree.def == null
1618 && !tree.type.getEnclosingType().hasTag(NONE)) {
1619 Type encl = tree.type.getEnclosingType();
1620 Type current = context.owner.enclClass().type;
1621 while (!current.hasTag(NONE)) {
1622 if (current.tsym.isSubClass(encl.tsym, types)) {
1623 return true;
1624 }
1625 current = current.getEnclosingType();
1626 }
1627 return false;
1628 } else {
1629 return false;
1630 }
1631 }
1633 private TranslationContext<JCLambda> makeLambdaContext(JCLambda tree) {
1634 return new LambdaTranslationContext(tree);
1635 }
1637 private TranslationContext<JCMemberReference> makeReferenceContext(JCMemberReference tree) {
1638 return new ReferenceTranslationContext(tree);
1639 }
1641 private class Frame {
1642 final JCTree tree;
1643 List<Symbol> locals;
1645 public Frame(JCTree tree) {
1646 this.tree = tree;
1647 }
1649 void addLocal(Symbol sym) {
1650 if (locals == null) {
1651 locals = List.nil();
1652 }
1653 locals = locals.prepend(sym);
1654 }
1655 }
1657 /**
1658 * This class is used to store important information regarding translation of
1659 * lambda expression/method references (see subclasses).
1660 */
1661 private abstract class TranslationContext<T extends JCFunctionalExpression> {
1663 /** the underlying (untranslated) tree */
1664 final T tree;
1666 /** points to the adjusted enclosing scope in which this lambda/mref expression occurs */
1667 final Symbol owner;
1669 /** the depth of this lambda expression in the frame stack */
1670 final int depth;
1672 /** the enclosing translation context (set for nested lambdas/mref) */
1673 final TranslationContext<?> prev;
1675 /** list of methods to be bridged by the meta-factory */
1676 final List<Symbol> bridges;
1678 TranslationContext(T tree) {
1679 this.tree = tree;
1680 this.owner = owner();
1681 this.depth = frameStack.size() - 1;
1682 this.prev = context();
1683 ClassSymbol csym =
1684 types.makeFunctionalInterfaceClass(attrEnv, names.empty, tree.targets, ABSTRACT | INTERFACE);
1685 this.bridges = types.functionalInterfaceBridges(csym);
1686 }
1688 /** does this functional expression need to be created using alternate metafactory? */
1689 boolean needsAltMetafactory() {
1690 return tree.targets.length() > 1 ||
1691 isSerializable() ||
1692 bridges.length() > 1;
1693 }
1695 /** does this functional expression require serialization support? */
1696 boolean isSerializable() {
1697 for (Type target : tree.targets) {
1698 if (types.asSuper(target, syms.serializableType.tsym) != null) {
1699 return true;
1700 }
1701 }
1702 return false;
1703 }
1705 /**
1706 * @return Name of the enclosing method to be folded into synthetic
1707 * method name
1708 */
1709 String enclosingMethodName() {
1710 return syntheticMethodNameComponent(owner.name);
1711 }
1713 /**
1714 * @return Method name in a form that can be folded into a
1715 * component of a synthetic method name
1716 */
1717 String syntheticMethodNameComponent(Name name) {
1718 if (name == null) {
1719 return "null";
1720 }
1721 String methodName = name.toString();
1722 if (methodName.equals("<clinit>")) {
1723 methodName = "static";
1724 } else if (methodName.equals("<init>")) {
1725 methodName = "new";
1726 }
1727 return methodName;
1728 }
1729 }
1731 /**
1732 * This class retains all the useful information about a lambda expression;
1733 * the contents of this class are filled by the LambdaAnalyzer visitor,
1734 * and the used by the main translation routines in order to adjust references
1735 * to captured locals/members, etc.
1736 */
1737 private class LambdaTranslationContext extends TranslationContext<JCLambda> {
1739 /** variable in the enclosing context to which this lambda is assigned */
1740 final Symbol self;
1742 /** variable in the enclosing context to which this lambda is assigned */
1743 final Symbol assignedTo;
1745 Map<LambdaSymbolKind, Map<Symbol, Symbol>> translatedSymbols;
1747 /** the synthetic symbol for the method hoisting the translated lambda */
1748 Symbol translatedSym;
1750 List<JCVariableDecl> syntheticParams;
1752 LambdaTranslationContext(JCLambda tree) {
1753 super(tree);
1754 Frame frame = frameStack.head;
1755 switch (frame.tree.getTag()) {
1756 case VARDEF:
1757 assignedTo = self = ((JCVariableDecl) frame.tree).sym;
1758 break;
1759 case ASSIGN:
1760 self = null;
1761 assignedTo = TreeInfo.symbol(((JCAssign) frame.tree).getVariable());
1762 break;
1763 default:
1764 assignedTo = self = null;
1765 break;
1766 }
1768 // This symbol will be filled-in in complete
1769 this.translatedSym = makePrivateSyntheticMethod(0, null, null, owner.enclClass());
1771 if (dumpLambdaToMethodStats) {
1772 log.note(tree, "lambda.stat", needsAltMetafactory(), translatedSym);
1773 }
1774 translatedSymbols = new EnumMap<>(LambdaSymbolKind.class);
1776 translatedSymbols.put(PARAM, new LinkedHashMap<Symbol, Symbol>());
1777 translatedSymbols.put(LOCAL_VAR, new LinkedHashMap<Symbol, Symbol>());
1778 translatedSymbols.put(CAPTURED_VAR, new LinkedHashMap<Symbol, Symbol>());
1779 translatedSymbols.put(CAPTURED_THIS, new LinkedHashMap<Symbol, Symbol>());
1780 translatedSymbols.put(TYPE_VAR, new LinkedHashMap<Symbol, Symbol>());
1781 }
1783 /**
1784 * For a serializable lambda, generate a disambiguating string
1785 * which maximizes stability across deserialization.
1786 *
1787 * @return String to differentiate synthetic lambda method names
1788 */
1789 private String serializedLambdaDisambiguation() {
1790 StringBuilder buf = new StringBuilder();
1791 // Append the enclosing method signature to differentiate
1792 // overloaded enclosing methods. For lambdas enclosed in
1793 // lambdas, the generated lambda method will not have type yet,
1794 // but the enclosing method's name will have been generated
1795 // with this same method, so it will be unique and never be
1796 // overloaded.
1797 Assert.check(
1798 owner.type != null ||
1799 directlyEnclosingLambda() != null);
1800 if (owner.type != null) {
1801 buf.append(typeSig(owner.type));
1802 buf.append(":");
1803 }
1805 // Add target type info
1806 buf.append(types.findDescriptorSymbol(tree.type.tsym).owner.flatName());
1807 buf.append(" ");
1809 // Add variable assigned to
1810 if (assignedTo != null) {
1811 buf.append(assignedTo.flatName());
1812 buf.append("=");
1813 }
1814 //add captured locals info: type, name, order
1815 for (Symbol fv : getSymbolMap(CAPTURED_VAR).keySet()) {
1816 if (fv != self) {
1817 buf.append(typeSig(fv.type));
1818 buf.append(" ");
1819 buf.append(fv.flatName());
1820 buf.append(",");
1821 }
1822 }
1824 return buf.toString();
1825 }
1827 /**
1828 * For a non-serializable lambda, generate a simple method.
1829 *
1830 * @return Name to use for the synthetic lambda method name
1831 */
1832 private Name lambdaName() {
1833 return names.lambda.append(names.fromString(enclosingMethodName() + "$" + lambdaCount++));
1834 }
1836 /**
1837 * For a serializable lambda, generate a method name which maximizes
1838 * name stability across deserialization.
1839 *
1840 * @return Name to use for the synthetic lambda method name
1841 */
1842 private Name serializedLambdaName() {
1843 StringBuilder buf = new StringBuilder();
1844 buf.append(names.lambda);
1845 // Append the name of the method enclosing the lambda.
1846 buf.append(enclosingMethodName());
1847 buf.append('$');
1848 // Append a hash of the disambiguating string : enclosing method
1849 // signature, etc.
1850 String disam = serializedLambdaDisambiguation();
1851 buf.append(Integer.toHexString(disam.hashCode()));
1852 buf.append('$');
1853 // The above appended name components may not be unique, append
1854 // a count based on the above name components.
1855 buf.append(syntheticMethodNameCounts.getIndex(buf));
1856 String result = buf.toString();
1857 //System.err.printf("serializedLambdaName: %s -- %s\n", result, disam);
1858 return names.fromString(result);
1859 }
1861 /**
1862 * Translate a symbol of a given kind into something suitable for the
1863 * synthetic lambda body
1864 */
1865 Symbol translate(Name name, final Symbol sym, LambdaSymbolKind skind) {
1866 Symbol ret;
1867 switch (skind) {
1868 case CAPTURED_THIS:
1869 ret = sym; // self represented
1870 break;
1871 case TYPE_VAR:
1872 // Just erase the type var
1873 ret = new VarSymbol(sym.flags(), name,
1874 types.erasure(sym.type), sym.owner);
1876 /* this information should also be kept for LVT generation at Gen
1877 * a Symbol with pos < startPos won't be tracked.
1878 */
1879 ((VarSymbol)ret).pos = ((VarSymbol)sym).pos;
1880 break;
1881 case CAPTURED_VAR:
1882 ret = new VarSymbol(SYNTHETIC | FINAL | PARAMETER, name, types.erasure(sym.type), translatedSym) {
1883 @Override
1884 public Symbol baseSymbol() {
1885 //keep mapping with original captured symbol
1886 return sym;
1887 }
1888 };
1889 break;
1890 case LOCAL_VAR:
1891 ret = new VarSymbol(FINAL, name, types.erasure(sym.type), translatedSym);
1892 ((VarSymbol) ret).pos = ((VarSymbol) sym).pos;
1893 break;
1894 case PARAM:
1895 ret = new VarSymbol(FINAL | PARAMETER, name, types.erasure(sym.type), translatedSym);
1896 ((VarSymbol) ret).pos = ((VarSymbol) sym).pos;
1897 break;
1898 default:
1899 ret = makeSyntheticVar(FINAL, name, types.erasure(sym.type), translatedSym);
1900 ((VarSymbol) ret).pos = ((VarSymbol) sym).pos;
1901 }
1902 if (ret != sym) {
1903 ret.setDeclarationAttributes(sym.getRawAttributes());
1904 ret.setTypeAttributes(sym.getRawTypeAttributes());
1905 }
1906 return ret;
1907 }
1909 void addSymbol(Symbol sym, LambdaSymbolKind skind) {
1910 Map<Symbol, Symbol> transMap = getSymbolMap(skind);
1911 Name preferredName;
1912 switch (skind) {
1913 case CAPTURED_THIS:
1914 preferredName = names.fromString("encl$" + transMap.size());
1915 break;
1916 case CAPTURED_VAR:
1917 preferredName = names.fromString("cap$" + transMap.size());
1918 break;
1919 case LOCAL_VAR:
1920 preferredName = sym.name;
1921 break;
1922 case PARAM:
1923 preferredName = sym.name;
1924 break;
1925 case TYPE_VAR:
1926 preferredName = sym.name;
1927 break;
1928 default: throw new AssertionError();
1929 }
1930 if (!transMap.containsKey(sym)) {
1931 transMap.put(sym, translate(preferredName, sym, skind));
1932 }
1933 }
1935 Map<Symbol, Symbol> getSymbolMap(LambdaSymbolKind skind) {
1936 Map<Symbol, Symbol> m = translatedSymbols.get(skind);
1937 Assert.checkNonNull(m);
1938 return m;
1939 }
1941 JCTree translate(JCIdent lambdaIdent) {
1942 for (Map<Symbol, Symbol> m : translatedSymbols.values()) {
1943 if (m.containsKey(lambdaIdent.sym)) {
1944 Symbol tSym = m.get(lambdaIdent.sym);
1945 JCTree t = make.Ident(tSym).setType(lambdaIdent.type);
1946 tSym.setTypeAttributes(lambdaIdent.sym.getRawTypeAttributes());
1947 return t;
1948 }
1949 }
1950 return null;
1951 }
1953 /**
1954 * The translatedSym is not complete/accurate until the analysis is
1955 * finished. Once the analysis is finished, the translatedSym is
1956 * "completed" -- updated with type information, access modifiers,
1957 * and full parameter list.
1958 */
1959 void complete() {
1960 if (syntheticParams != null) {
1961 return;
1962 }
1963 boolean inInterface = translatedSym.owner.isInterface();
1964 boolean thisReferenced = !getSymbolMap(CAPTURED_THIS).isEmpty();
1966 // If instance access isn't needed, make it static.
1967 // Interface instance methods must be default methods.
1968 // Lambda methods are private synthetic.
1969 translatedSym.flags_field = SYNTHETIC | LAMBDA_METHOD |
1970 PRIVATE |
1971 (thisReferenced? (inInterface? DEFAULT : 0) : STATIC);
1973 //compute synthetic params
1974 ListBuffer<JCVariableDecl> params = new ListBuffer<>();
1976 // The signature of the method is augmented with the following
1977 // synthetic parameters:
1978 //
1979 // 1) reference to enclosing contexts captured by the lambda expression
1980 // 2) enclosing locals captured by the lambda expression
1981 for (Symbol thisSym : getSymbolMap(CAPTURED_VAR).values()) {
1982 params.append(make.VarDef((VarSymbol) thisSym, null));
1983 }
1984 for (Symbol thisSym : getSymbolMap(PARAM).values()) {
1985 params.append(make.VarDef((VarSymbol) thisSym, null));
1986 }
1987 syntheticParams = params.toList();
1989 // Compute and set the lambda name
1990 translatedSym.name = isSerializable()
1991 ? serializedLambdaName()
1992 : lambdaName();
1994 //prepend synthetic args to translated lambda method signature
1995 translatedSym.type = types.createMethodTypeWithParameters(
1996 generatedLambdaSig(),
1997 TreeInfo.types(syntheticParams));
1998 }
2000 Type generatedLambdaSig() {
2001 return types.erasure(tree.getDescriptorType(types));
2002 }
2003 }
2005 /**
2006 * This class retains all the useful information about a method reference;
2007 * the contents of this class are filled by the LambdaAnalyzer visitor,
2008 * and the used by the main translation routines in order to adjust method
2009 * references (i.e. in case a bridge is needed)
2010 */
2011 private class ReferenceTranslationContext extends TranslationContext<JCMemberReference> {
2013 final boolean isSuper;
2014 final Symbol bridgeSym;
2015 final Symbol sigPolySym;
2017 ReferenceTranslationContext(JCMemberReference tree) {
2018 super(tree);
2019 this.isSuper = tree.hasKind(ReferenceKind.SUPER);
2020 this.bridgeSym = needsBridge()
2021 ? makePrivateSyntheticMethod(isSuper ? 0 : STATIC,
2022 referenceBridgeName(), null,
2023 owner.enclClass())
2024 : null;
2025 this.sigPolySym = isSignaturePolymorphic()
2026 ? makePrivateSyntheticMethod(tree.sym.flags(),
2027 tree.sym.name,
2028 bridgedRefSig(),
2029 tree.sym.enclClass())
2030 : null;
2031 if (dumpLambdaToMethodStats) {
2032 String key = bridgeSym == null ?
2033 "mref.stat" : "mref.stat.1";
2034 log.note(tree, key, needsAltMetafactory(), bridgeSym);
2035 }
2036 }
2038 /**
2039 * Get the opcode associated with this method reference
2040 */
2041 int referenceKind() {
2042 return LambdaToMethod.this.referenceKind(needsBridge()
2043 ? bridgeSym
2044 : tree.sym);
2045 }
2047 boolean needsVarArgsConversion() {
2048 return tree.varargsElement != null;
2049 }
2051 /**
2052 * Generate a disambiguating string to increase stability (important
2053 * if serialized)
2054 *
2055 * @return String to differentiate synthetic lambda method names
2056 */
2057 private String referenceBridgeDisambiguation() {
2058 StringBuilder buf = new StringBuilder();
2059 // Append the enclosing method signature to differentiate
2060 // overloaded enclosing methods.
2061 if (owner.type != null) {
2062 buf.append(typeSig(owner.type));
2063 buf.append(":");
2064 }
2066 // Append qualifier type
2067 buf.append(classSig(tree.sym.owner.type));
2069 // Note static/instance
2070 buf.append(tree.sym.isStatic()? " S " : " I ");
2072 // Append referenced signature
2073 buf.append(typeSig(tree.sym.erasure(types)));
2075 return buf.toString();
2076 }
2078 /**
2079 * Construct a unique stable name for the method reference bridge
2080 *
2081 * @return Name to use for the synthetic method name
2082 */
2083 private Name referenceBridgeName() {
2084 StringBuilder buf = new StringBuilder();
2085 // Append lambda ID, this is semantically significant
2086 buf.append(names.lambda);
2087 // Note that it is a method reference bridge
2088 buf.append("MR$");
2089 // Append the enclosing method name
2090 buf.append(enclosingMethodName());
2091 buf.append('$');
2092 // Append the referenced method name
2093 buf.append(syntheticMethodNameComponent(tree.sym.name));
2094 buf.append('$');
2095 // Append a hash of the disambiguating string : enclosing method
2096 // signature, etc.
2097 String disam = referenceBridgeDisambiguation();
2098 buf.append(Integer.toHexString(disam.hashCode()));
2099 buf.append('$');
2100 // The above appended name components may not be unique, append
2101 // a count based on the above name components.
2102 buf.append(syntheticMethodNameCounts.getIndex(buf));
2103 String result = buf.toString();
2104 return names.fromString(result);
2105 }
2107 /**
2108 * @return Is this an array operation like clone()
2109 */
2110 boolean isArrayOp() {
2111 return tree.sym.owner == syms.arrayClass;
2112 }
2114 boolean receiverAccessible() {
2115 //hack needed to workaround 292 bug (7087658)
2116 //when 292 issue is fixed we should remove this and change the backend
2117 //code to always generate a method handle to an accessible method
2118 return tree.ownerAccessible;
2119 }
2121 /**
2122 * The VM does not support access across nested classes (8010319).
2123 * Were that ever to change, this should be removed.
2124 */
2125 boolean isPrivateInOtherClass() {
2126 return (tree.sym.flags() & PRIVATE) != 0 &&
2127 !types.isSameType(
2128 types.erasure(tree.sym.enclClass().asType()),
2129 types.erasure(owner.enclClass().asType()));
2130 }
2132 /**
2133 * Signature polymorphic methods need special handling.
2134 * e.g. MethodHandle.invoke() MethodHandle.invokeExact()
2135 */
2136 final boolean isSignaturePolymorphic() {
2137 return tree.sym.kind == MTH &&
2138 types.isSignaturePolymorphic((MethodSymbol)tree.sym);
2139 }
2141 /**
2142 * Does this reference needs a bridge (i.e. var args need to be
2143 * expanded or "super" is used)
2144 */
2145 final boolean needsBridge() {
2146 return isSuper || needsVarArgsConversion() || isArrayOp() ||
2147 isPrivateInOtherClass() ||
2148 !receiverAccessible();
2149 }
2151 Type generatedRefSig() {
2152 return types.erasure(tree.sym.type);
2153 }
2155 Type bridgedRefSig() {
2156 return types.erasure(types.findDescriptorSymbol(tree.targets.head.tsym).type);
2157 }
2158 }
2159 }
2160 // </editor-fold>
2162 /*
2163 * These keys provide mappings for various translated lambda symbols
2164 * and the prevailing order must be maintained.
2165 */
2166 enum LambdaSymbolKind {
2167 PARAM, // original to translated lambda parameters
2168 LOCAL_VAR, // original to translated lambda locals
2169 CAPTURED_VAR, // variables in enclosing scope to translated synthetic parameters
2170 CAPTURED_THIS, // class symbols to translated synthetic parameters (for captured member access)
2171 TYPE_VAR; // original to translated lambda type variables
2172 }
2174 /**
2175 * ****************************************************************
2176 * Signature Generation
2177 * ****************************************************************
2178 */
2180 private String typeSig(Type type) {
2181 L2MSignatureGenerator sg = new L2MSignatureGenerator();
2182 sg.assembleSig(type);
2183 return sg.toString();
2184 }
2186 private String classSig(Type type) {
2187 L2MSignatureGenerator sg = new L2MSignatureGenerator();
2188 sg.assembleClassSig(type);
2189 return sg.toString();
2190 }
2192 /**
2193 * Signature Generation
2194 */
2195 private class L2MSignatureGenerator extends Types.SignatureGenerator {
2197 /**
2198 * An output buffer for type signatures.
2199 */
2200 StringBuilder sb = new StringBuilder();
2202 L2MSignatureGenerator() {
2203 super(types);
2204 }
2206 @Override
2207 protected void append(char ch) {
2208 sb.append(ch);
2209 }
2211 @Override
2212 protected void append(byte[] ba) {
2213 sb.append(new String(ba));
2214 }
2216 @Override
2217 protected void append(Name name) {
2218 sb.append(name.toString());
2219 }
2221 @Override
2222 public String toString() {
2223 return sb.toString();
2224 }
2225 }
2226 }