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