Tue, 18 Jun 2013 19:02:48 +0100
8016267: javac, TypeTag refactoring has provoked performance issues
Reviewed-by: 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 = 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.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())),
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 /**
912 * Generate an indy method call to the meta factory
913 */
914 private JCExpression makeMetaFactoryIndyCall(TranslationContext<?> context,
915 int refKind, Symbol refSym, List<JCExpression> indy_args) {
916 JCFunctionalExpression tree = context.tree;
917 //determine the static bsm args
918 Type mtype = types.erasure(tree.getDescriptorType(types));
919 MethodSymbol samSym = (MethodSymbol) types.findDescriptorSymbol(tree.type.tsym);
920 List<Object> staticArgs = List.<Object>of(
921 new Pool.MethodHandle(ClassFile.REF_invokeInterface,
922 types.findDescriptorSymbol(tree.type.tsym), types),
923 new Pool.MethodHandle(refKind, refSym, types),
924 new MethodType(mtype.getParameterTypes(),
925 mtype.getReturnType(),
926 mtype.getThrownTypes(),
927 syms.methodClass));
929 //computed indy arg types
930 ListBuffer<Type> indy_args_types = ListBuffer.lb();
931 for (JCExpression arg : indy_args) {
932 indy_args_types.append(arg.type);
933 }
935 //finally, compute the type of the indy call
936 MethodType indyType = new MethodType(indy_args_types.toList(),
937 tree.type,
938 List.<Type>nil(),
939 syms.methodClass);
941 Name metafactoryName = context.needsAltMetafactory() ?
942 names.altMetaFactory : names.metaFactory;
944 if (context.needsAltMetafactory()) {
945 ListBuffer<Object> markers = ListBuffer.lb();
946 for (Type t : tree.targets.tail) {
947 if (t.tsym != syms.serializableType.tsym) {
948 markers.append(t.tsym);
949 }
950 }
951 int flags = context.isSerializable() ? FLAG_SERIALIZABLE : 0;
952 boolean hasMarkers = markers.nonEmpty();
953 boolean hasBridges = context.bridges.nonEmpty();
954 if (hasMarkers) {
955 flags |= FLAG_MARKERS;
956 }
957 if (hasBridges) {
958 flags |= FLAG_BRIDGES;
959 }
960 staticArgs = staticArgs.append(flags);
961 if (hasMarkers) {
962 staticArgs = staticArgs.append(markers.length());
963 staticArgs = staticArgs.appendList(markers.toList());
964 }
965 if (hasBridges) {
966 staticArgs = staticArgs.append(context.bridges.length() - 1);
967 for (Symbol s : context.bridges) {
968 Type s_erasure = s.erasure(types);
969 if (!types.isSameType(s_erasure, samSym.erasure(types))) {
970 staticArgs = staticArgs.append(s.erasure(types));
971 }
972 }
973 }
974 if (context.isSerializable()) {
975 addDeserializationCase(refKind, refSym, tree.type, samSym,
976 tree, staticArgs, indyType);
977 }
978 }
980 return makeIndyCall(tree, syms.lambdaMetafactory, metafactoryName, staticArgs, indyType, indy_args);
981 }
983 /**
984 * Generate an indy method call with given name, type and static bootstrap
985 * arguments types
986 */
987 private JCExpression makeIndyCall(DiagnosticPosition pos, Type site, Name bsmName,
988 List<Object> staticArgs, MethodType indyType, List<JCExpression> indyArgs) {
989 int prevPos = make.pos;
990 try {
991 make.at(pos);
992 List<Type> bsm_staticArgs = List.of(syms.methodHandleLookupType,
993 syms.stringType,
994 syms.methodTypeType).appendList(bsmStaticArgToTypes(staticArgs));
996 Symbol bsm = rs.resolveInternalMethod(pos, attrEnv, site,
997 bsmName, bsm_staticArgs, List.<Type>nil());
999 DynamicMethodSymbol dynSym =
1000 new DynamicMethodSymbol(names.lambda,
1001 syms.noSymbol,
1002 bsm.isStatic() ?
1003 ClassFile.REF_invokeStatic :
1004 ClassFile.REF_invokeVirtual,
1005 (MethodSymbol)bsm,
1006 indyType,
1007 staticArgs.toArray());
1009 JCFieldAccess qualifier = make.Select(make.QualIdent(site.tsym), bsmName);
1010 qualifier.sym = dynSym;
1011 qualifier.type = indyType.getReturnType();
1013 JCMethodInvocation proxyCall = make.Apply(List.<JCExpression>nil(), qualifier, indyArgs);
1014 proxyCall.type = indyType.getReturnType();
1015 return proxyCall;
1016 } finally {
1017 make.at(prevPos);
1018 }
1019 }
1020 //where
1021 private List<Type> bsmStaticArgToTypes(List<Object> args) {
1022 ListBuffer<Type> argtypes = ListBuffer.lb();
1023 for (Object arg : args) {
1024 argtypes.append(bsmStaticArgToType(arg));
1025 }
1026 return argtypes.toList();
1027 }
1029 private Type bsmStaticArgToType(Object arg) {
1030 Assert.checkNonNull(arg);
1031 if (arg instanceof ClassSymbol) {
1032 return syms.classType;
1033 } else if (arg instanceof Integer) {
1034 return syms.intType;
1035 } else if (arg instanceof Long) {
1036 return syms.longType;
1037 } else if (arg instanceof Float) {
1038 return syms.floatType;
1039 } else if (arg instanceof Double) {
1040 return syms.doubleType;
1041 } else if (arg instanceof String) {
1042 return syms.stringType;
1043 } else if (arg instanceof Pool.MethodHandle) {
1044 return syms.methodHandleType;
1045 } else if (arg instanceof MethodType) {
1046 return syms.methodTypeType;
1047 } else {
1048 Assert.error("bad static arg " + arg.getClass());
1049 return null;
1050 }
1051 }
1053 /**
1054 * Get the opcode associated with this method reference
1055 */
1056 private int referenceKind(Symbol refSym) {
1057 if (refSym.isConstructor()) {
1058 return ClassFile.REF_newInvokeSpecial;
1059 } else {
1060 if (refSym.isStatic()) {
1061 return ClassFile.REF_invokeStatic;
1062 } else if (refSym.enclClass().isInterface()) {
1063 return ClassFile.REF_invokeInterface;
1064 } else {
1065 return (refSym.flags() & PRIVATE) != 0 ?
1066 ClassFile.REF_invokeSpecial :
1067 ClassFile.REF_invokeVirtual;
1068 }
1069 }
1070 }
1072 // <editor-fold defaultstate="collapsed" desc="Lambda/reference analyzer">
1073 /**
1074 * This visitor collects information about translation of a lambda expression.
1075 * More specifically, it keeps track of the enclosing contexts and captured locals
1076 * accessed by the lambda being translated (as well as other useful info).
1077 * It also translates away problems for LambdaToMethod.
1078 */
1079 class LambdaAnalyzerPreprocessor extends TreeTranslator {
1081 /** the frame stack - used to reconstruct translation info about enclosing scopes */
1082 private List<Frame> frameStack;
1084 /**
1085 * keep the count of lambda expression (used to generate unambiguous
1086 * names)
1087 */
1088 private int lambdaCount = 0;
1090 /**
1091 * keep the count of lambda expression defined in given context (used to
1092 * generate unambiguous names for serializable lambdas)
1093 */
1094 private Map<String, Integer> serializableLambdaCounts =
1095 new HashMap<String, Integer>();
1097 private Map<Symbol, JCClassDecl> localClassDefs;
1099 /**
1100 * maps for fake clinit symbols to be used as owners of lambda occurring in
1101 * a static var init context
1102 */
1103 private Map<ClassSymbol, Symbol> clinits =
1104 new HashMap<ClassSymbol, Symbol>();
1106 private JCClassDecl analyzeAndPreprocessClass(JCClassDecl tree) {
1107 frameStack = List.nil();
1108 localClassDefs = new HashMap<Symbol, JCClassDecl>();
1109 return translate(tree);
1110 }
1112 @Override
1113 public void visitBlock(JCBlock tree) {
1114 List<Frame> prevStack = frameStack;
1115 try {
1116 if (frameStack.nonEmpty() && frameStack.head.tree.hasTag(CLASSDEF)) {
1117 frameStack = frameStack.prepend(new Frame(tree));
1118 }
1119 super.visitBlock(tree);
1120 }
1121 finally {
1122 frameStack = prevStack;
1123 }
1124 }
1126 @Override
1127 public void visitClassDef(JCClassDecl tree) {
1128 List<Frame> prevStack = frameStack;
1129 Map<String, Integer> prevSerializableLambdaCount =
1130 serializableLambdaCounts;
1131 Map<ClassSymbol, Symbol> prevClinits = clinits;
1132 DiagnosticSource prevSource = log.currentSource();
1133 try {
1134 log.useSource(tree.sym.sourcefile);
1135 serializableLambdaCounts = new HashMap<String, Integer>();
1136 prevClinits = new HashMap<ClassSymbol, Symbol>();
1137 if (tree.sym.owner.kind == MTH) {
1138 localClassDefs.put(tree.sym, tree);
1139 }
1140 if (directlyEnclosingLambda() != null) {
1141 tree.sym.owner = owner();
1142 if (tree.sym.hasOuterInstance()) {
1143 //if a class is defined within a lambda, the lambda must capture
1144 //its enclosing instance (if any)
1145 TranslationContext<?> localContext = context();
1146 while (localContext != null) {
1147 if (localContext.tree.getTag() == LAMBDA) {
1148 ((LambdaTranslationContext)localContext)
1149 .addSymbol(tree.sym.type.getEnclosingType().tsym, CAPTURED_THIS);
1150 }
1151 localContext = localContext.prev;
1152 }
1153 }
1154 }
1155 frameStack = frameStack.prepend(new Frame(tree));
1156 super.visitClassDef(tree);
1157 }
1158 finally {
1159 log.useSource(prevSource.getFile());
1160 frameStack = prevStack;
1161 serializableLambdaCounts = prevSerializableLambdaCount;
1162 clinits = prevClinits;
1163 }
1164 }
1166 @Override
1167 public void visitIdent(JCIdent tree) {
1168 if (context() != null && lambdaIdentSymbolFilter(tree.sym)) {
1169 if (tree.sym.kind == VAR &&
1170 tree.sym.owner.kind == MTH &&
1171 tree.type.constValue() == null) {
1172 TranslationContext<?> localContext = context();
1173 while (localContext != null) {
1174 if (localContext.tree.getTag() == LAMBDA) {
1175 JCTree block = capturedDecl(localContext.depth, tree.sym);
1176 if (block == null) break;
1177 ((LambdaTranslationContext)localContext)
1178 .addSymbol(tree.sym, CAPTURED_VAR);
1179 }
1180 localContext = localContext.prev;
1181 }
1182 } else if (tree.sym.owner.kind == TYP) {
1183 TranslationContext<?> localContext = context();
1184 while (localContext != null) {
1185 if (localContext.tree.hasTag(LAMBDA)) {
1186 JCTree block = capturedDecl(localContext.depth, tree.sym);
1187 if (block == null) break;
1188 switch (block.getTag()) {
1189 case CLASSDEF:
1190 JCClassDecl cdecl = (JCClassDecl)block;
1191 ((LambdaTranslationContext)localContext)
1192 .addSymbol(cdecl.sym, CAPTURED_THIS);
1193 break;
1194 default:
1195 Assert.error("bad block kind");
1196 }
1197 }
1198 localContext = localContext.prev;
1199 }
1200 }
1201 }
1202 super.visitIdent(tree);
1203 }
1205 @Override
1206 public void visitLambda(JCLambda tree) {
1207 List<Frame> prevStack = frameStack;
1208 try {
1209 LambdaTranslationContext context = (LambdaTranslationContext)makeLambdaContext(tree);
1210 frameStack = frameStack.prepend(new Frame(tree));
1211 for (JCVariableDecl param : tree.params) {
1212 context.addSymbol(param.sym, PARAM);
1213 frameStack.head.addLocal(param.sym);
1214 }
1215 contextMap.put(tree, context);
1216 super.visitLambda(tree);
1217 context.complete();
1218 }
1219 finally {
1220 frameStack = prevStack;
1221 }
1222 }
1224 @Override
1225 public void visitMethodDef(JCMethodDecl tree) {
1226 List<Frame> prevStack = frameStack;
1227 try {
1228 frameStack = frameStack.prepend(new Frame(tree));
1229 super.visitMethodDef(tree);
1230 }
1231 finally {
1232 frameStack = prevStack;
1233 }
1234 }
1236 @Override
1237 public void visitNewClass(JCNewClass tree) {
1238 if (lambdaNewClassFilter(context(), tree)) {
1239 TranslationContext<?> localContext = context();
1240 while (localContext != null) {
1241 if (localContext.tree.getTag() == LAMBDA) {
1242 ((LambdaTranslationContext)localContext)
1243 .addSymbol(tree.type.getEnclosingType().tsym, CAPTURED_THIS);
1244 }
1245 localContext = localContext.prev;
1246 }
1247 }
1248 if (context() != null && tree.type.tsym.owner.kind == MTH) {
1249 LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context();
1250 captureLocalClassDefs(tree.type.tsym, lambdaContext);
1251 }
1252 super.visitNewClass(tree);
1253 }
1254 //where
1255 void captureLocalClassDefs(Symbol csym, final LambdaTranslationContext lambdaContext) {
1256 JCClassDecl localCDef = localClassDefs.get(csym);
1257 if (localCDef != null && localCDef.pos < lambdaContext.tree.pos) {
1258 BasicFreeVarCollector fvc = lower.new BasicFreeVarCollector() {
1259 @Override
1260 void addFreeVars(ClassSymbol c) {
1261 captureLocalClassDefs(c, lambdaContext);
1262 }
1263 @Override
1264 void visitSymbol(Symbol sym) {
1265 if (sym.kind == VAR &&
1266 sym.owner.kind == MTH &&
1267 ((VarSymbol)sym).getConstValue() == null) {
1268 TranslationContext<?> localContext = context();
1269 while (localContext != null) {
1270 if (localContext.tree.getTag() == LAMBDA) {
1271 JCTree block = capturedDecl(localContext.depth, sym);
1272 if (block == null) break;
1273 ((LambdaTranslationContext)localContext).addSymbol(sym, CAPTURED_VAR);
1274 }
1275 localContext = localContext.prev;
1276 }
1277 }
1278 }
1279 };
1280 fvc.scan(localCDef);
1281 }
1282 }
1284 /**
1285 * Method references to local class constructors, may, if the local
1286 * class references local variables, have implicit constructor
1287 * parameters added in Lower; As a result, the invokedynamic bootstrap
1288 * information added in the LambdaToMethod pass will have the wrong
1289 * signature. Hooks between Lower and LambdaToMethod have been added to
1290 * handle normal "new" in this case. This visitor converts potentially
1291 * effected method references into a lambda containing a normal "new" of
1292 * the class.
1293 *
1294 * @param tree
1295 */
1296 @Override
1297 public void visitReference(JCMemberReference tree) {
1298 if (tree.getMode() == ReferenceMode.NEW
1299 && tree.kind != ReferenceKind.ARRAY_CTOR
1300 && tree.sym.owner.isLocal()) {
1301 MethodSymbol consSym = (MethodSymbol) tree.sym;
1302 List<Type> ptypes = ((MethodType) consSym.type).getParameterTypes();
1303 Type classType = consSym.owner.type;
1305 // Build lambda parameters
1306 // partially cloned from TreeMaker.Params until 8014021 is fixed
1307 Symbol owner = owner();
1308 ListBuffer<JCVariableDecl> paramBuff = new ListBuffer<JCVariableDecl>();
1309 int i = 0;
1310 for (List<Type> l = ptypes; l.nonEmpty(); l = l.tail) {
1311 paramBuff.append(make.Param(make.paramName(i++), l.head, owner));
1312 }
1313 List<JCVariableDecl> params = paramBuff.toList();
1315 // Make new-class call
1316 JCNewClass nc = makeNewClass(classType, make.Idents(params));
1317 nc.pos = tree.pos;
1319 // Make lambda holding the new-class call
1320 JCLambda slam = make.Lambda(params, nc);
1321 slam.targets = tree.targets;
1322 slam.type = tree.type;
1323 slam.pos = tree.pos;
1325 // Now it is a lambda, process as such
1326 visitLambda(slam);
1327 } else {
1328 super.visitReference(tree);
1329 contextMap.put(tree, makeReferenceContext(tree));
1330 }
1331 }
1333 @Override
1334 public void visitSelect(JCFieldAccess tree) {
1335 if (context() != null && tree.sym.kind == VAR &&
1336 (tree.sym.name == names._this ||
1337 tree.sym.name == names._super)) {
1338 // A select of this or super means, if we are in a lambda,
1339 // we much have an instance context
1340 TranslationContext<?> localContext = context();
1341 while (localContext != null) {
1342 if (localContext.tree.hasTag(LAMBDA)) {
1343 JCClassDecl clazz = (JCClassDecl)capturedDecl(localContext.depth, tree.sym);
1344 if (clazz == null) break;
1345 ((LambdaTranslationContext)localContext).addSymbol(clazz.sym, CAPTURED_THIS);
1346 }
1347 localContext = localContext.prev;
1348 }
1349 }
1350 super.visitSelect(tree);
1351 }
1353 @Override
1354 public void visitVarDef(JCVariableDecl tree) {
1355 TranslationContext<?> context = context();
1356 LambdaTranslationContext ltc = (context != null && context instanceof LambdaTranslationContext)?
1357 (LambdaTranslationContext)context :
1358 null;
1359 if (ltc != null) {
1360 if (frameStack.head.tree.hasTag(LAMBDA)) {
1361 ltc.addSymbol(tree.sym, LOCAL_VAR);
1362 }
1363 // Check for type variables (including as type arguments).
1364 // If they occur within class nested in a lambda, mark for erasure
1365 Type type = tree.sym.asType();
1366 if (inClassWithinLambda() && !types.isSameType(types.erasure(type), type)) {
1367 ltc.addSymbol(tree.sym, TYPE_VAR);
1368 }
1369 }
1371 List<Frame> prevStack = frameStack;
1372 try {
1373 if (tree.sym.owner.kind == MTH) {
1374 frameStack.head.addLocal(tree.sym);
1375 }
1376 frameStack = frameStack.prepend(new Frame(tree));
1377 super.visitVarDef(tree);
1378 }
1379 finally {
1380 frameStack = prevStack;
1381 }
1382 }
1384 private Name lambdaName() {
1385 return names.lambda.append(names.fromString("" + lambdaCount++));
1386 }
1388 /**
1389 * For a serializable lambda, generate a name which maximizes name
1390 * stability across deserialization.
1391 * @param owner
1392 * @return Name to use for the synthetic lambda method name
1393 */
1394 private Name serializedLambdaName(Symbol owner) {
1395 StringBuilder buf = new StringBuilder();
1396 buf.append(names.lambda);
1397 // Append the name of the method enclosing the lambda.
1398 String methodName = owner.name.toString();
1399 if (methodName.equals("<clinit>"))
1400 methodName = "static";
1401 else if (methodName.equals("<init>"))
1402 methodName = "new";
1403 buf.append(methodName);
1404 buf.append('$');
1405 // Append a hash of the enclosing method signature to differentiate
1406 // overloaded enclosing methods. For lambdas enclosed in lambdas,
1407 // the generated lambda method will not have type yet, but the
1408 // enclosing method's name will have been generated with this same
1409 // method, so it will be unique and never be overloaded.
1410 Assert.check(owner.type != null || directlyEnclosingLambda() != null);
1411 if (owner.type != null) {
1412 int methTypeHash = methodSig(owner.type).hashCode();
1413 buf.append(Integer.toHexString(methTypeHash));
1414 }
1415 buf.append('$');
1416 // The above appended name components may not be unique, append a
1417 // count based on the above name components.
1418 String temp = buf.toString();
1419 Integer count = serializableLambdaCounts.get(temp);
1420 if (count == null) {
1421 count = 0;
1422 }
1423 buf.append(count++);
1424 serializableLambdaCounts.put(temp, count);
1425 return names.fromString(buf.toString());
1426 }
1428 /**
1429 * Return a valid owner given the current declaration stack
1430 * (required to skip synthetic lambda symbols)
1431 */
1432 private Symbol owner() {
1433 return owner(false);
1434 }
1436 @SuppressWarnings("fallthrough")
1437 private Symbol owner(boolean skipLambda) {
1438 List<Frame> frameStack2 = frameStack;
1439 while (frameStack2.nonEmpty()) {
1440 switch (frameStack2.head.tree.getTag()) {
1441 case VARDEF:
1442 if (((JCVariableDecl)frameStack2.head.tree).sym.isLocal()) {
1443 frameStack2 = frameStack2.tail;
1444 break;
1445 }
1446 JCClassDecl cdecl = (JCClassDecl)frameStack2.tail.head.tree;
1447 return initSym(cdecl.sym,
1448 ((JCVariableDecl)frameStack2.head.tree).sym.flags() & STATIC);
1449 case BLOCK:
1450 JCClassDecl cdecl2 = (JCClassDecl)frameStack2.tail.head.tree;
1451 return initSym(cdecl2.sym,
1452 ((JCBlock)frameStack2.head.tree).flags & STATIC);
1453 case CLASSDEF:
1454 return ((JCClassDecl)frameStack2.head.tree).sym;
1455 case METHODDEF:
1456 return ((JCMethodDecl)frameStack2.head.tree).sym;
1457 case LAMBDA:
1458 if (!skipLambda)
1459 return ((LambdaTranslationContext)contextMap
1460 .get(frameStack2.head.tree)).translatedSym;
1461 default:
1462 frameStack2 = frameStack2.tail;
1463 }
1464 }
1465 Assert.error();
1466 return null;
1467 }
1469 private Symbol initSym(ClassSymbol csym, long flags) {
1470 boolean isStatic = (flags & STATIC) != 0;
1471 if (isStatic) {
1472 //static clinits are generated in Gen - so we need to fake them
1473 Symbol clinit = clinits.get(csym);
1474 if (clinit == null) {
1475 clinit = makeSyntheticMethod(STATIC,
1476 names.clinit,
1477 new MethodType(List.<Type>nil(), syms.voidType, List.<Type>nil(), syms.methodClass),
1478 csym);
1479 clinits.put(csym, clinit);
1480 }
1481 return clinit;
1482 } else {
1483 //get the first constructor and treat it as the instance init sym
1484 for (Symbol s : csym.members_field.getElementsByName(names.init)) {
1485 return s;
1486 }
1487 }
1488 Assert.error("init not found");
1489 return null;
1490 }
1492 private JCTree directlyEnclosingLambda() {
1493 if (frameStack.isEmpty()) {
1494 return null;
1495 }
1496 List<Frame> frameStack2 = frameStack;
1497 while (frameStack2.nonEmpty()) {
1498 switch (frameStack2.head.tree.getTag()) {
1499 case CLASSDEF:
1500 case METHODDEF:
1501 return null;
1502 case LAMBDA:
1503 return frameStack2.head.tree;
1504 default:
1505 frameStack2 = frameStack2.tail;
1506 }
1507 }
1508 Assert.error();
1509 return null;
1510 }
1512 private boolean inClassWithinLambda() {
1513 if (frameStack.isEmpty()) {
1514 return false;
1515 }
1516 List<Frame> frameStack2 = frameStack;
1517 boolean classFound = false;
1518 while (frameStack2.nonEmpty()) {
1519 switch (frameStack2.head.tree.getTag()) {
1520 case LAMBDA:
1521 return classFound;
1522 case CLASSDEF:
1523 classFound = true;
1524 frameStack2 = frameStack2.tail;
1525 break;
1526 default:
1527 frameStack2 = frameStack2.tail;
1528 }
1529 }
1530 // No lambda
1531 return false;
1532 }
1534 /**
1535 * Return the declaration corresponding to a symbol in the enclosing
1536 * scope; the depth parameter is used to filter out symbols defined
1537 * in nested scopes (which do not need to undergo capture).
1538 */
1539 private JCTree capturedDecl(int depth, Symbol sym) {
1540 int currentDepth = frameStack.size() - 1;
1541 for (Frame block : frameStack) {
1542 switch (block.tree.getTag()) {
1543 case CLASSDEF:
1544 ClassSymbol clazz = ((JCClassDecl)block.tree).sym;
1545 if (sym.isMemberOf(clazz, types)) {
1546 return currentDepth > depth ? null : block.tree;
1547 }
1548 break;
1549 case VARDEF:
1550 if (((JCVariableDecl)block.tree).sym == sym &&
1551 sym.owner.kind == MTH) { //only locals are captured
1552 return currentDepth > depth ? null : block.tree;
1553 }
1554 break;
1555 case BLOCK:
1556 case METHODDEF:
1557 case LAMBDA:
1558 if (block.locals != null && block.locals.contains(sym)) {
1559 return currentDepth > depth ? null : block.tree;
1560 }
1561 break;
1562 default:
1563 Assert.error("bad decl kind " + block.tree.getTag());
1564 }
1565 currentDepth--;
1566 }
1567 return null;
1568 }
1570 private TranslationContext<?> context() {
1571 for (Frame frame : frameStack) {
1572 TranslationContext<?> context = contextMap.get(frame.tree);
1573 if (context != null) {
1574 return context;
1575 }
1576 }
1577 return null;
1578 }
1580 /**
1581 * This is used to filter out those identifiers that needs to be adjusted
1582 * when translating away lambda expressions
1583 */
1584 private boolean lambdaIdentSymbolFilter(Symbol sym) {
1585 return (sym.kind == VAR || sym.kind == MTH)
1586 && !sym.isStatic()
1587 && sym.name != names.init;
1588 }
1590 /**
1591 * This is used to filter out those new class expressions that need to
1592 * be qualified with an enclosing tree
1593 */
1594 private boolean lambdaNewClassFilter(TranslationContext<?> context, JCNewClass tree) {
1595 if (context != null
1596 && tree.encl == null
1597 && tree.def == null
1598 && !tree.type.getEnclosingType().hasTag(NONE)) {
1599 Type encl = tree.type.getEnclosingType();
1600 Type current = context.owner.enclClass().type;
1601 while (!current.hasTag(NONE)) {
1602 if (current.tsym.isSubClass(encl.tsym, types)) {
1603 return true;
1604 }
1605 current = current.getEnclosingType();
1606 }
1607 return false;
1608 } else {
1609 return false;
1610 }
1611 }
1613 private TranslationContext<JCLambda> makeLambdaContext(JCLambda tree) {
1614 return new LambdaTranslationContext(tree);
1615 }
1617 private TranslationContext<JCMemberReference> makeReferenceContext(JCMemberReference tree) {
1618 return new ReferenceTranslationContext(tree);
1619 }
1621 private class Frame {
1622 final JCTree tree;
1623 List<Symbol> locals;
1625 public Frame(JCTree tree) {
1626 this.tree = tree;
1627 }
1629 void addLocal(Symbol sym) {
1630 if (locals == null) {
1631 locals = List.nil();
1632 }
1633 locals = locals.prepend(sym);
1634 }
1635 }
1637 /**
1638 * This class is used to store important information regarding translation of
1639 * lambda expression/method references (see subclasses).
1640 */
1641 private abstract class TranslationContext<T extends JCFunctionalExpression> {
1643 /** the underlying (untranslated) tree */
1644 T tree;
1646 /** points to the adjusted enclosing scope in which this lambda/mref expression occurs */
1647 Symbol owner;
1649 /** the depth of this lambda expression in the frame stack */
1650 int depth;
1652 /** the enclosing translation context (set for nested lambdas/mref) */
1653 TranslationContext<?> prev;
1655 /** list of methods to be bridged by the meta-factory */
1656 List<Symbol> bridges;
1658 TranslationContext(T tree) {
1659 this.tree = tree;
1660 this.owner = owner();
1661 this.depth = frameStack.size() - 1;
1662 this.prev = context();
1663 ClassSymbol csym =
1664 types.makeFunctionalInterfaceClass(attrEnv, names.empty, tree.targets, ABSTRACT | INTERFACE);
1665 this.bridges = types.functionalInterfaceBridges(csym);
1666 }
1668 /** does this functional expression need to be created using alternate metafactory? */
1669 boolean needsAltMetafactory() {
1670 return tree.targets.length() > 1 ||
1671 isSerializable() ||
1672 bridges.length() > 1;
1673 }
1675 /** does this functional expression require serialization support? */
1676 boolean isSerializable() {
1677 for (Type target : tree.targets) {
1678 if (types.asSuper(target, syms.serializableType.tsym) != null) {
1679 return true;
1680 }
1681 }
1682 return false;
1683 }
1684 }
1686 /**
1687 * This class retains all the useful information about a lambda expression;
1688 * the contents of this class are filled by the LambdaAnalyzer visitor,
1689 * and the used by the main translation routines in order to adjust references
1690 * to captured locals/members, etc.
1691 */
1692 private class LambdaTranslationContext extends TranslationContext<JCLambda> {
1694 /** variable in the enclosing context to which this lambda is assigned */
1695 Symbol self;
1697 /** map from original to translated lambda parameters */
1698 Map<Symbol, Symbol> lambdaParams = new LinkedHashMap<Symbol, Symbol>();
1700 /** map from original to translated lambda locals */
1701 Map<Symbol, Symbol> lambdaLocals = new LinkedHashMap<Symbol, Symbol>();
1703 /** map from variables in enclosing scope to translated synthetic parameters */
1704 Map<Symbol, Symbol> capturedLocals = new LinkedHashMap<Symbol, Symbol>();
1706 /** map from class symbols to translated synthetic parameters (for captured member access) */
1707 Map<Symbol, Symbol> capturedThis = new LinkedHashMap<Symbol, Symbol>();
1709 /** map from original to translated lambda locals */
1710 Map<Symbol, Symbol> typeVars = new LinkedHashMap<Symbol, Symbol>();
1712 /** the synthetic symbol for the method hoisting the translated lambda */
1713 Symbol translatedSym;
1715 List<JCVariableDecl> syntheticParams;
1717 LambdaTranslationContext(JCLambda tree) {
1718 super(tree);
1719 Frame frame = frameStack.head;
1720 if (frame.tree.hasTag(VARDEF)) {
1721 self = ((JCVariableDecl)frame.tree).sym;
1722 }
1723 Name name = isSerializable() ? serializedLambdaName(owner) : lambdaName();
1724 this.translatedSym = makeSyntheticMethod(0, name, null, owner.enclClass());
1725 if (dumpLambdaToMethodStats) {
1726 log.note(tree, "lambda.stat", needsAltMetafactory(), translatedSym);
1727 }
1728 }
1730 /**
1731 * Translate a symbol of a given kind into something suitable for the
1732 * synthetic lambda body
1733 */
1734 Symbol translate(Name name, final Symbol sym, LambdaSymbolKind skind) {
1735 Symbol ret;
1736 switch (skind) {
1737 case CAPTURED_THIS:
1738 ret = sym; // self represented
1739 break;
1740 case TYPE_VAR:
1741 // Just erase the type var
1742 ret = new VarSymbol(sym.flags(), name,
1743 types.erasure(sym.type), sym.owner);
1744 break;
1745 case CAPTURED_VAR:
1746 ret = new VarSymbol(SYNTHETIC | FINAL, name, types.erasure(sym.type), translatedSym) {
1747 @Override
1748 public Symbol baseSymbol() {
1749 //keep mapping with original captured symbol
1750 return sym;
1751 }
1752 };
1753 break;
1754 default:
1755 ret = makeSyntheticVar(FINAL, name, types.erasure(sym.type), translatedSym);
1756 }
1757 if (ret != sym) {
1758 ret.setDeclarationAttributes(sym.getRawAttributes());
1759 ret.setTypeAttributes(sym.getRawTypeAttributes());
1760 }
1761 return ret;
1762 }
1764 void addSymbol(Symbol sym, LambdaSymbolKind skind) {
1765 Map<Symbol, Symbol> transMap = null;
1766 Name preferredName;
1767 switch (skind) {
1768 case CAPTURED_THIS:
1769 transMap = capturedThis;
1770 preferredName = names.fromString("encl$" + capturedThis.size());
1771 break;
1772 case CAPTURED_VAR:
1773 transMap = capturedLocals;
1774 preferredName = names.fromString("cap$" + capturedLocals.size());
1775 break;
1776 case LOCAL_VAR:
1777 transMap = lambdaLocals;
1778 preferredName = sym.name;
1779 break;
1780 case PARAM:
1781 transMap = lambdaParams;
1782 preferredName = sym.name;
1783 break;
1784 case TYPE_VAR:
1785 transMap = typeVars;
1786 preferredName = sym.name;
1787 break;
1788 default: throw new AssertionError();
1789 }
1790 if (!transMap.containsKey(sym)) {
1791 transMap.put(sym, translate(preferredName, sym, skind));
1792 }
1793 }
1795 Map<Symbol, Symbol> getSymbolMap(LambdaSymbolKind... skinds) {
1796 LinkedHashMap<Symbol, Symbol> translationMap = new LinkedHashMap<Symbol, Symbol>();
1797 for (LambdaSymbolKind skind : skinds) {
1798 switch (skind) {
1799 case CAPTURED_THIS:
1800 translationMap.putAll(capturedThis);
1801 break;
1802 case CAPTURED_VAR:
1803 translationMap.putAll(capturedLocals);
1804 break;
1805 case LOCAL_VAR:
1806 translationMap.putAll(lambdaLocals);
1807 break;
1808 case PARAM:
1809 translationMap.putAll(lambdaParams);
1810 break;
1811 case TYPE_VAR:
1812 translationMap.putAll(typeVars);
1813 break;
1814 default: throw new AssertionError();
1815 }
1816 }
1817 return translationMap;
1818 }
1820 /**
1821 * The translatedSym is not complete/accurate until the analysis is
1822 * finished. Once the analysis is finished, the translatedSym is
1823 * "completed" -- updated with type information, access modifiers,
1824 * and full parameter list.
1825 */
1826 void complete() {
1827 if (syntheticParams != null) {
1828 return;
1829 }
1830 boolean inInterface = translatedSym.owner.isInterface();
1831 boolean thisReferenced = !getSymbolMap(CAPTURED_THIS).isEmpty();
1833 // If instance access isn't needed, make it static.
1834 // Interface instance methods must be default methods.
1835 // Awaiting VM channges, default methods are public
1836 translatedSym.flags_field = SYNTHETIC |
1837 ((inInterface && thisReferenced)? PUBLIC : PRIVATE) |
1838 (thisReferenced? (inInterface? DEFAULT : 0) : STATIC);
1840 //compute synthetic params
1841 ListBuffer<JCVariableDecl> params = ListBuffer.lb();
1843 // The signature of the method is augmented with the following
1844 // synthetic parameters:
1845 //
1846 // 1) reference to enclosing contexts captured by the lambda expression
1847 // 2) enclosing locals captured by the lambda expression
1848 for (Symbol thisSym : getSymbolMap(CAPTURED_VAR, PARAM).values()) {
1849 params.append(make.VarDef((VarSymbol) thisSym, null));
1850 }
1852 syntheticParams = params.toList();
1854 //prepend synthetic args to translated lambda method signature
1855 translatedSym.type = types.createMethodTypeWithParameters(
1856 generatedLambdaSig(),
1857 TreeInfo.types(syntheticParams));
1858 }
1860 Type generatedLambdaSig() {
1861 return types.erasure(tree.getDescriptorType(types));
1862 }
1863 }
1865 /**
1866 * This class retains all the useful information about a method reference;
1867 * the contents of this class are filled by the LambdaAnalyzer visitor,
1868 * and the used by the main translation routines in order to adjust method
1869 * references (i.e. in case a bridge is needed)
1870 */
1871 private class ReferenceTranslationContext extends TranslationContext<JCMemberReference> {
1873 final boolean isSuper;
1874 final Symbol bridgeSym;
1876 ReferenceTranslationContext(JCMemberReference tree) {
1877 super(tree);
1878 this.isSuper = tree.hasKind(ReferenceKind.SUPER);
1879 this.bridgeSym = needsBridge()
1880 ? makeSyntheticMethod(isSuper ? 0 : STATIC,
1881 lambdaName().append(names.fromString("$bridge")), null,
1882 owner.enclClass())
1883 : null;
1884 if (dumpLambdaToMethodStats) {
1885 String key = bridgeSym == null ?
1886 "mref.stat" : "mref.stat.1";
1887 log.note(tree, key, needsAltMetafactory(), bridgeSym);
1888 }
1889 }
1891 /**
1892 * Get the opcode associated with this method reference
1893 */
1894 int referenceKind() {
1895 return LambdaToMethod.this.referenceKind(needsBridge() ? bridgeSym : tree.sym);
1896 }
1898 boolean needsVarArgsConversion() {
1899 return tree.varargsElement != null;
1900 }
1902 /**
1903 * @return Is this an array operation like clone()
1904 */
1905 boolean isArrayOp() {
1906 return tree.sym.owner == syms.arrayClass;
1907 }
1909 boolean isPrivateConstructor() {
1910 //hack needed to workaround 292 bug (8005122)
1911 //when 292 issue is fixed we should simply remove this
1912 return tree.sym.name == names.init &&
1913 (tree.sym.flags() & PRIVATE) != 0;
1914 }
1916 boolean receiverAccessible() {
1917 //hack needed to workaround 292 bug (7087658)
1918 //when 292 issue is fixed we should remove this and change the backend
1919 //code to always generate a method handle to an accessible method
1920 return tree.ownerAccessible;
1921 }
1923 /**
1924 * Does this reference needs a bridge (i.e. var args need to be
1925 * expanded or "super" is used)
1926 */
1927 final boolean needsBridge() {
1928 return isSuper || needsVarArgsConversion() || isArrayOp() ||
1929 isPrivateConstructor() || !receiverAccessible();
1930 }
1932 Type generatedRefSig() {
1933 return types.erasure(tree.sym.type);
1934 }
1936 Type bridgedRefSig() {
1937 return types.erasure(types.findDescriptorSymbol(tree.targets.head.tsym).type);
1938 }
1939 }
1940 }
1941 // </editor-fold>
1943 enum LambdaSymbolKind {
1944 CAPTURED_VAR,
1945 CAPTURED_THIS,
1946 LOCAL_VAR,
1947 PARAM,
1948 TYPE_VAR;
1949 }
1951 /**
1952 * ****************************************************************
1953 * Signature Generation
1954 * ****************************************************************
1955 */
1957 private String methodSig(Type type) {
1958 L2MSignatureGenerator sg = new L2MSignatureGenerator();
1959 sg.assembleSig(type);
1960 return sg.toString();
1961 }
1963 private String classSig(Type type) {
1964 L2MSignatureGenerator sg = new L2MSignatureGenerator();
1965 sg.assembleClassSig(type);
1966 return sg.toString();
1967 }
1969 /**
1970 * Signature Generation
1971 */
1972 private class L2MSignatureGenerator extends Types.SignatureGenerator {
1974 /**
1975 * An output buffer for type signatures.
1976 */
1977 StringBuilder sb = new StringBuilder();
1979 L2MSignatureGenerator() {
1980 super(types);
1981 }
1983 @Override
1984 protected void append(char ch) {
1985 sb.append(ch);
1986 }
1988 @Override
1989 protected void append(byte[] ba) {
1990 sb.append(new String(ba));
1991 }
1993 @Override
1994 protected void append(Name name) {
1995 sb.append(name.toString());
1996 }
1998 @Override
1999 public String toString() {
2000 return sb.toString();
2001 }
2002 }
2003 }