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