1 /*
2 * Copyright (c) 2010, 2025, 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
26 package com.sun.tools.javac.comp;
27
28 import com.sun.tools.javac.code.Attribute;
29 import com.sun.tools.javac.code.Flags;
30 import com.sun.tools.javac.code.Symbol;
31 import com.sun.tools.javac.code.Symbol.ClassSymbol;
32 import com.sun.tools.javac.code.Symbol.DynamicMethodSymbol;
33 import com.sun.tools.javac.code.Symbol.MethodHandleSymbol;
34 import com.sun.tools.javac.code.Symbol.MethodSymbol;
35 import com.sun.tools.javac.code.Symbol.VarSymbol;
36 import com.sun.tools.javac.code.Symtab;
37 import com.sun.tools.javac.code.Type;
38 import com.sun.tools.javac.code.Type.MethodType;
39 import com.sun.tools.javac.code.Types;
40 import com.sun.tools.javac.code.Types.SignatureGenerator.InvalidSignatureException;
41 import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant;
42 import com.sun.tools.javac.main.Option;
43 import com.sun.tools.javac.resources.CompilerProperties.Errors;
44 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
45 import com.sun.tools.javac.resources.CompilerProperties.Notes;
46 import com.sun.tools.javac.tree.JCTree;
47 import com.sun.tools.javac.tree.JCTree.JCAnnotation;
48 import com.sun.tools.javac.tree.JCTree.JCBinary;
49 import com.sun.tools.javac.tree.JCTree.JCBlock;
50 import com.sun.tools.javac.tree.JCTree.JCBreak;
51 import com.sun.tools.javac.tree.JCTree.JCCase;
52 import com.sun.tools.javac.tree.JCTree.JCClassDecl;
53 import com.sun.tools.javac.tree.JCTree.JCExpression;
54 import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
55 import com.sun.tools.javac.tree.JCTree.JCFunctionalExpression;
56 import com.sun.tools.javac.tree.JCTree.JCIdent;
57 import com.sun.tools.javac.tree.JCTree.JCLambda;
58 import com.sun.tools.javac.tree.JCTree.JCMemberReference;
59 import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
60 import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
61 import com.sun.tools.javac.tree.JCTree.JCNewClass;
62 import com.sun.tools.javac.tree.JCTree.JCReturn;
63 import com.sun.tools.javac.tree.JCTree.JCStatement;
64 import com.sun.tools.javac.tree.JCTree.JCSwitch;
65 import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
66 import com.sun.tools.javac.tree.JCTree.Tag;
67 import com.sun.tools.javac.tree.TreeInfo;
68 import com.sun.tools.javac.tree.TreeMaker;
69 import com.sun.tools.javac.tree.TreeTranslator;
70 import com.sun.tools.javac.util.Assert;
71 import com.sun.tools.javac.util.Context;
72 import com.sun.tools.javac.util.DiagnosticSource;
73 import com.sun.tools.javac.util.InvalidUtfException;
74 import com.sun.tools.javac.util.JCDiagnostic;
75 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
76 import com.sun.tools.javac.util.List;
77 import com.sun.tools.javac.util.ListBuffer;
78 import com.sun.tools.javac.util.Log;
79 import com.sun.tools.javac.util.Name;
80 import com.sun.tools.javac.util.Names;
81 import com.sun.tools.javac.util.Options;
82
83 import javax.lang.model.element.ElementKind;
84 import java.lang.invoke.LambdaMetafactory;
85 import java.util.HashMap;
86 import java.util.HashSet;
87 import java.util.Map;
88 import java.util.Set;
89 import java.util.function.Consumer;
90 import java.util.function.Supplier;
91
92 import static com.sun.tools.javac.code.Flags.ABSTRACT;
93 import static com.sun.tools.javac.code.Flags.BLOCK;
94 import static com.sun.tools.javac.code.Flags.DEFAULT;
95 import static com.sun.tools.javac.code.Flags.FINAL;
96 import static com.sun.tools.javac.code.Flags.INTERFACE;
97 import static com.sun.tools.javac.code.Flags.LAMBDA_METHOD;
98 import static com.sun.tools.javac.code.Flags.LOCAL_CAPTURE_FIELD;
99 import static com.sun.tools.javac.code.Flags.PARAMETER;
100 import static com.sun.tools.javac.code.Flags.PRIVATE;
101 import static com.sun.tools.javac.code.Flags.STATIC;
102 import static com.sun.tools.javac.code.Flags.STRICTFP;
103 import static com.sun.tools.javac.code.Flags.SYNTHETIC;
104 import static com.sun.tools.javac.code.Kinds.Kind.MTH;
105 import static com.sun.tools.javac.code.Kinds.Kind.TYP;
106 import static com.sun.tools.javac.code.Kinds.Kind.VAR;
107 import static com.sun.tools.javac.code.TypeTag.BOT;
108 import static com.sun.tools.javac.code.TypeTag.VOID;
109
110 /**
111 * This pass desugars lambda expressions into static methods
112 *
113 * <p><b>This is NOT part of any supported API.
114 * If you write code that depends on this, you do so at your own risk.
115 * This code and its internal interfaces are subject to change or
116 * deletion without notice.</b>
117 */
118 public class LambdaToMethod extends TreeTranslator {
119
120 private final Attr attr;
121 private final JCDiagnostic.Factory diags;
122 private final Log log;
123 private final Lower lower;
124 private final Names names;
125 private final Symtab syms;
126 private final Resolve rs;
127 private final Operators operators;
128 private TreeMaker make;
129 private final Types types;
130 private final TransTypes transTypes;
131 private Env<AttrContext> attrEnv;
132
133 /** info about the current class being processed */
134 private KlassInfo kInfo;
135
136 /** translation context of the current lambda expression */
137 private LambdaTranslationContext lambdaContext;
138
139 /** the variable whose initializer is pending */
140 private VarSymbol pendingVar;
141
142 /** dump statistics about lambda code generation */
143 private final boolean dumpLambdaToMethodStats;
144
145 /** force serializable representation, for stress testing **/
146 private final boolean forceSerializable;
147
148 /** true if line or local variable debug info has been requested */
149 private final boolean debugLinesOrVars;
150
151 /** dump statistics about lambda method deduplication */
152 private final boolean verboseDeduplication;
153
154 /** deduplicate lambda implementation methods */
155 private final boolean deduplicateLambdas;
156
157 /** Flag for alternate metafactories indicating the lambda object is intended to be serializable */
158 public static final int FLAG_SERIALIZABLE = LambdaMetafactory.FLAG_SERIALIZABLE;
159
160 /** Flag for alternate metafactories indicating the lambda object has multiple targets */
161 public static final int FLAG_MARKERS = LambdaMetafactory.FLAG_MARKERS;
162
163 /** Flag for alternate metafactories indicating the lambda object requires multiple bridges */
164 public static final int FLAG_BRIDGES = LambdaMetafactory.FLAG_BRIDGES;
165
166 // <editor-fold defaultstate="collapsed" desc="Instantiating">
167 protected static final Context.Key<LambdaToMethod> unlambdaKey = new Context.Key<>();
168
169 public static LambdaToMethod instance(Context context) {
170 LambdaToMethod instance = context.get(unlambdaKey);
171 if (instance == null) {
172 instance = new LambdaToMethod(context);
173 }
174 return instance;
175 }
176 private LambdaToMethod(Context context) {
177 context.put(unlambdaKey, this);
178 diags = JCDiagnostic.Factory.instance(context);
179 log = Log.instance(context);
180 lower = Lower.instance(context);
181 names = Names.instance(context);
182 syms = Symtab.instance(context);
183 rs = Resolve.instance(context);
184 operators = Operators.instance(context);
185 make = TreeMaker.instance(context);
186 types = Types.instance(context);
187 transTypes = TransTypes.instance(context);
188 Options options = Options.instance(context);
189 dumpLambdaToMethodStats = options.isSet("debug.dumpLambdaToMethodStats");
190 attr = Attr.instance(context);
191 forceSerializable = options.isSet("forceSerializable");
192 boolean lineDebugInfo =
193 options.isUnset(Option.G_CUSTOM) ||
194 options.isSet(Option.G_CUSTOM, "lines");
195 boolean varDebugInfo =
196 options.isUnset(Option.G_CUSTOM)
197 ? options.isSet(Option.G)
198 : options.isSet(Option.G_CUSTOM, "vars");
199 debugLinesOrVars = lineDebugInfo || varDebugInfo;
200 verboseDeduplication = options.isSet("debug.dumpLambdaToMethodDeduplication");
201 deduplicateLambdas = options.getBoolean("deduplicateLambdas", true);
202 }
203 // </editor-fold>
204
205 class DedupedLambda {
206 private final MethodSymbol symbol;
207 private final JCTree tree;
208
209 private int hashCode;
210
211 DedupedLambda(MethodSymbol symbol, JCTree tree) {
212 this.symbol = symbol;
213 this.tree = tree;
214 }
215
216 @Override
217 public int hashCode() {
218 int hashCode = this.hashCode;
219 if (hashCode == 0) {
220 this.hashCode = hashCode = TreeHasher.hash(types, tree, symbol.params());
221 }
222 return hashCode;
223 }
224
225 @Override
226 public boolean equals(Object o) {
227 return (o instanceof DedupedLambda dedupedLambda)
228 && types.isSameType(symbol.asType(), dedupedLambda.symbol.asType())
229 && new TreeDiffer(types, symbol.params(), dedupedLambda.symbol.params()).scan(tree, dedupedLambda.tree);
230 }
231 }
232
233 private class KlassInfo {
234
235 /**
236 * list of methods to append
237 */
238 private ListBuffer<JCTree> appendedMethodList = new ListBuffer<>();
239
240 private final Map<DedupedLambda, DedupedLambda> dedupedLambdas = new HashMap<>();
241
242 private final Map<Object, DynamicMethodSymbol> dynMethSyms = new HashMap<>();
243
244 /**
245 * list of deserialization cases
246 */
247 private final Map<String, ListBuffer<JCStatement>> deserializeCases = new HashMap<>();
248
249 /**
250 * deserialize method symbol
251 */
252 private final MethodSymbol deserMethodSym;
253
254 /**
255 * deserialize method parameter symbol
256 */
257 private final VarSymbol deserParamSym;
258
259 private final JCClassDecl clazz;
260
261 private final Map<String, Integer> syntheticNames = new HashMap<>();
262
263 private KlassInfo(JCClassDecl clazz) {
264 this.clazz = clazz;
265 MethodType type = new MethodType(List.of(syms.serializedLambdaType), syms.objectType,
266 List.nil(), syms.methodClass);
267 deserMethodSym = makePrivateSyntheticMethod(STATIC, names.deserializeLambda, type, clazz.sym);
268 deserParamSym = new VarSymbol(FINAL, names.fromString("lambda"),
269 syms.serializedLambdaType, deserMethodSym);
270 }
271
272 private void addMethod(JCTree decl) {
273 appendedMethodList = appendedMethodList.prepend(decl);
274 }
275
276 int syntheticNameIndex(StringBuilder buf, int start) {
277 String temp = buf.toString();
278 Integer count = syntheticNames.get(temp);
279 if (count == null) {
280 count = start;
281 }
282 syntheticNames.put(temp, count + 1);
283 return count;
284 }
285 }
286
287 // <editor-fold defaultstate="collapsed" desc="visitor methods">
288 public JCTree translateTopLevelClass(Env<AttrContext> env, JCTree cdef, TreeMaker make) {
289 this.make = make;
290 this.attrEnv = env;
291 return translate(cdef);
292 }
293
294 /**
295 * Visit a class.
296 * Maintain the translatedMethodList across nested classes.
297 * Append the translatedMethodList to the class after it is translated.
298 */
299 @Override
300 public void visitClassDef(JCClassDecl tree) {
301 KlassInfo prevKlassInfo = kInfo;
302 DiagnosticSource prevSource = log.currentSource();
303 LambdaTranslationContext prevLambdaContext = lambdaContext;
304 VarSymbol prevPendingVar = pendingVar;
305 try {
306 kInfo = new KlassInfo(tree);
307 log.useSource(tree.sym.sourcefile);
308 lambdaContext = null;
309 pendingVar = null;
310 super.visitClassDef(tree);
311 if (prevLambdaContext != null) {
312 tree.sym.owner = prevLambdaContext.translatedSym;
313 }
314 if (!kInfo.deserializeCases.isEmpty()) {
315 int prevPos = make.pos;
316 try {
317 make.at(tree);
318 kInfo.addMethod(makeDeserializeMethod());
319 } finally {
320 make.at(prevPos);
321 }
322 }
323 //add all translated instance methods here
324 List<JCTree> newMethods = kInfo.appendedMethodList.toList();
325 tree.defs = tree.defs.appendList(newMethods);
326 for (JCTree lambda : newMethods) {
327 tree.sym.members().enter(((JCMethodDecl)lambda).sym);
328 }
329 result = tree;
330 } finally {
331 kInfo = prevKlassInfo;
332 log.useSource(prevSource.getFile());
333 lambdaContext = prevLambdaContext;
334 pendingVar = prevPendingVar;
335 }
336 }
337
338 /**
339 * Translate a lambda into a method to be inserted into the class.
340 * Then replace the lambda site with an invokedynamic call of to lambda
341 * meta-factory, which will use the lambda method.
342 */
343 @Override
344 public void visitLambda(JCLambda tree) {
345 LambdaTranslationContext localContext = new LambdaTranslationContext(tree);
346 MethodSymbol sym = localContext.translatedSym;
347 MethodType lambdaType = (MethodType) sym.type;
348
349 { /* Type annotation management: Based on where the lambda features, type annotations that
350 are interior to it, may at this point be attached to the enclosing method, or the first
351 constructor in the class, or in the enclosing class symbol or in the field whose
352 initializer is the lambda. In any event, gather up the annotations that belong to the
353 lambda and attach it to the implementation method.
354 */
355
356 Symbol owner = tree.owner;
357 apportionTypeAnnotations(tree,
358 owner::getRawTypeAttributes,
359 owner::setTypeAttributes,
360 sym::setTypeAttributes);
361
362 final long ownerFlags = owner.flags();
363 if ((ownerFlags & Flags.BLOCK) != 0) {
364 ClassSymbol cs = (ClassSymbol) owner.owner;
365 boolean isStaticInit = (ownerFlags & Flags.STATIC) != 0;
366 apportionTypeAnnotations(tree,
367 isStaticInit ? cs::getClassInitTypeAttributes : cs::getInitTypeAttributes,
368 isStaticInit ? cs::setClassInitTypeAttributes : cs::setInitTypeAttributes,
369 sym::appendUniqueTypeAttributes);
370 }
371
372 if (pendingVar != null && pendingVar.getKind() == ElementKind.FIELD) {
373 apportionTypeAnnotations(tree,
374 pendingVar::getRawTypeAttributes,
375 pendingVar::setTypeAttributes,
376 sym::appendUniqueTypeAttributes);
377 }
378 }
379
380 //create the method declaration hoisting the lambda body
381 JCMethodDecl lambdaDecl = make.MethodDef(make.Modifiers(sym.flags_field),
382 sym.name,
383 make.QualIdent(lambdaType.getReturnType().tsym),
384 List.nil(),
385 localContext.syntheticParams,
386 lambdaType.getThrownTypes() == null ?
387 List.nil() :
388 make.Types(lambdaType.getThrownTypes()),
389 null,
390 null);
391 lambdaDecl.sym = sym;
392 lambdaDecl.type = lambdaType;
393
394 //now that we have generated a method for the lambda expression,
395 //we can translate the lambda into a method reference pointing to the newly
396 //created method.
397 //
398 //Note that we need to adjust the method handle so that it will match the
399 //signature of the SAM descriptor - this means that the method reference
400 //should be added the following synthetic arguments:
401 //
402 // * the "this" argument if it is an instance method
403 // * enclosing locals captured by the lambda expression
404
405 ListBuffer<JCExpression> syntheticInits = new ListBuffer<>();
406
407 if (!sym.isStatic()) {
408 syntheticInits.append(makeThis(
409 sym.owner.enclClass().asType(),
410 tree.owner.enclClass()));
411 }
412
413 //add captured locals
414 for (Symbol fv : localContext.capturedVars) {
415 JCExpression captured_local = make.Ident(fv).setType(fv.type);
416 syntheticInits.append(captured_local);
417 }
418
419 //then, determine the arguments to the indy call
420 List<JCExpression> indy_args = translate(syntheticInits.toList());
421
422 LambdaTranslationContext prevLambdaContext = lambdaContext;
423 try {
424 lambdaContext = localContext;
425 //translate lambda body
426 //As the lambda body is translated, all references to lambda locals,
427 //captured variables, enclosing members are adjusted accordingly
428 //to refer to the static method parameters (rather than i.e. accessing
429 //captured members directly).
430 lambdaDecl.body = translate(makeLambdaBody(tree, lambdaDecl));
431 } finally {
432 lambdaContext = prevLambdaContext;
433 }
434
435 boolean dedupe = false;
436 if (deduplicateLambdas && !debugLinesOrVars && !isSerializable(tree)) {
437 DedupedLambda dedupedLambda = new DedupedLambda(lambdaDecl.sym, lambdaDecl.body);
438 DedupedLambda existing = kInfo.dedupedLambdas.putIfAbsent(dedupedLambda, dedupedLambda);
439 if (existing != null) {
440 sym = existing.symbol;
441 dedupe = true;
442 if (verboseDeduplication) log.note(tree, Notes.VerboseL2mDeduplicate(sym));
443 }
444 }
445 if (!dedupe) {
446 //Add the method to the list of methods to be added to this class.
447 kInfo.addMethod(lambdaDecl);
448 }
449
450 //convert to an invokedynamic call
451 result = makeMetafactoryIndyCall(tree, sym.asHandle(), localContext.translatedSym, indy_args);
452 }
453
454 // where
455 // Reassign type annotations from the source that should really belong to the lambda
456 private void apportionTypeAnnotations(JCLambda tree,
457 Supplier<List<Attribute.TypeCompound>> source,
458 Consumer<List<Attribute.TypeCompound>> owner,
459 Consumer<List<Attribute.TypeCompound>> lambda) {
460
461 ListBuffer<Attribute.TypeCompound> ownerTypeAnnos = new ListBuffer<>();
462 ListBuffer<Attribute.TypeCompound> lambdaTypeAnnos = new ListBuffer<>();
463
464 for (Attribute.TypeCompound tc : source.get()) {
465 if (tc.hasUnknownPosition()) {
466 // Handle container annotations
467 tc.tryFixPosition();
468 }
469 if (tc.position.onLambda == tree) {
470 lambdaTypeAnnos.append(tc);
471 } else {
472 ownerTypeAnnos.append(tc);
473 }
474 }
475 if (lambdaTypeAnnos.nonEmpty()) {
476 owner.accept(ownerTypeAnnos.toList());
477 lambda.accept(lambdaTypeAnnos.toList());
478 }
479 }
480
481 private JCIdent makeThis(Type type, Symbol owner) {
482 VarSymbol _this = new VarSymbol(PARAMETER | FINAL | SYNTHETIC,
483 names._this,
484 type,
485 owner);
486 return make.Ident(_this);
487 }
488
489 /**
490 * Translate a method reference into an invokedynamic call to the
491 * meta-factory.
492 */
493 @Override
494 public void visitReference(JCMemberReference tree) {
495 //first determine the method symbol to be used to generate the sam instance
496 //this is either the method reference symbol, or the bridged reference symbol
497 MethodSymbol refSym = (MethodSymbol)tree.sym;
498
499 //the qualifying expression is treated as a special captured arg
500 JCExpression init = switch (tree.kind) {
501 case IMPLICIT_INNER, /* Inner :: new */
502 SUPER -> /* super :: instMethod */
503 makeThis(tree.owner.enclClass().asType(), tree.owner.enclClass());
504 case BOUND -> /* Expr :: instMethod */
505 attr.makeNullCheck(transTypes.coerce(attrEnv, tree.getQualifierExpression(),
506 types.erasure(tree.sym.owner.type)));
507 case UNBOUND, /* Type :: instMethod */
508 STATIC, /* Type :: staticMethod */
509 TOPLEVEL, /* Top level :: new */
510 ARRAY_CTOR -> /* ArrayType :: new */
511 null;
512 };
513
514 List<JCExpression> indy_args = (init == null) ?
515 List.nil() : translate(List.of(init));
516
517 //build a sam instance using an indy call to the meta-factory
518 result = makeMetafactoryIndyCall(tree, refSym.asHandle(), refSym, indy_args);
519 }
520
521 /**
522 * Translate identifiers within a lambda to the mapped identifier
523 */
524 @Override
525 public void visitIdent(JCIdent tree) {
526 if (lambdaContext == null) {
527 super.visitIdent(tree);
528 } else {
529 int prevPos = make.pos;
530 try {
531 make.at(tree);
532 JCTree ltree = lambdaContext.translate(tree);
533 if (ltree != null) {
534 result = ltree;
535 } else {
536 //access to untranslated symbols (i.e. compile-time constants,
537 //members defined inside the lambda body, etc.) )
538 super.visitIdent(tree);
539 }
540 } finally {
541 make.at(prevPos);
542 }
543 }
544 }
545
546 @Override
547 public void visitVarDef(JCVariableDecl tree) {
548 VarSymbol prevPendingVar = pendingVar;
549 try {
550 pendingVar = tree.sym;
551 if (lambdaContext != null) {
552 tree.sym = lambdaContext.addLocal(tree.sym);
553 tree.init = translate(tree.init);
554 result = tree;
555 } else {
556 super.visitVarDef(tree);
557 }
558 } finally {
559 pendingVar = prevPendingVar;
560 }
561 }
562
563 // </editor-fold>
564
565 // <editor-fold defaultstate="collapsed" desc="Translation helper methods">
566
567 private JCBlock makeLambdaBody(JCLambda tree, JCMethodDecl lambdaMethodDecl) {
568 return tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION ?
569 makeLambdaExpressionBody((JCExpression)tree.body, lambdaMethodDecl) :
570 makeLambdaStatementBody((JCBlock)tree.body, lambdaMethodDecl, tree.canCompleteNormally);
571 }
572
573 private JCBlock makeLambdaExpressionBody(JCExpression expr, JCMethodDecl lambdaMethodDecl) {
574 Type restype = lambdaMethodDecl.type.getReturnType();
575 boolean isLambda_void = expr.type.hasTag(VOID);
576 boolean isTarget_void = restype.hasTag(VOID);
577 boolean isTarget_Void = types.isSameType(restype, types.boxedClass(syms.voidType).type);
578 int prevPos = make.pos;
579 try {
580 if (isTarget_void) {
581 //target is void:
582 // BODY;
583 JCStatement stat = make.at(expr).Exec(expr);
584 return make.Block(0, List.of(stat));
585 } else if (isLambda_void && isTarget_Void) {
586 //void to Void conversion:
587 // BODY; return null;
588 ListBuffer<JCStatement> stats = new ListBuffer<>();
589 stats.append(make.at(expr).Exec(expr));
590 stats.append(make.Return(make.Literal(BOT, null).setType(syms.botType)));
591 return make.Block(0, stats.toList());
592 } else {
593 //non-void to non-void conversion:
594 // return BODY;
595 return make.at(expr).Block(0, List.of(make.Return(expr)));
596 }
597 } finally {
598 make.at(prevPos);
599 }
600 }
601
602 private JCBlock makeLambdaStatementBody(JCBlock block, final JCMethodDecl lambdaMethodDecl, boolean completeNormally) {
603 final Type restype = lambdaMethodDecl.type.getReturnType();
604 final boolean isTarget_void = restype.hasTag(VOID);
605 boolean isTarget_Void = types.isSameType(restype, types.boxedClass(syms.voidType).type);
606
607 class LambdaBodyTranslator extends TreeTranslator {
608
609 @Override
610 public void visitClassDef(JCClassDecl tree) {
611 //do NOT recurse on any inner classes
612 result = tree;
613 }
614
615 @Override
616 public void visitLambda(JCLambda tree) {
617 //do NOT recurse on any nested lambdas
618 result = tree;
619 }
620
621 @Override
622 public void visitReturn(JCReturn tree) {
623 boolean isLambda_void = tree.expr == null;
624 if (isTarget_void && !isLambda_void) {
625 //Void to void conversion:
626 // { TYPE $loc = RET-EXPR; return; }
627 VarSymbol loc = new VarSymbol(SYNTHETIC, names.fromString("$loc"), tree.expr.type, lambdaMethodDecl.sym);
628 JCVariableDecl varDef = make.VarDef(loc, tree.expr);
629 result = make.Block(0, List.of(varDef, make.Return(null)));
630 } else {
631 result = tree;
632 }
633
634 }
635 }
636
637 JCBlock trans_block = new LambdaBodyTranslator().translate(block);
638 if (completeNormally && isTarget_Void) {
639 //there's no return statement and the lambda (possibly inferred)
640 //return type is java.lang.Void; emit a synthetic return statement
641 trans_block.stats = trans_block.stats.append(make.Return(make.Literal(BOT, null).setType(syms.botType)));
642 }
643 return trans_block;
644 }
645
646 private JCMethodDecl makeDeserializeMethod() {
647 ListBuffer<JCCase> cases = new ListBuffer<>();
648 ListBuffer<JCBreak> breaks = new ListBuffer<>();
649 for (Map.Entry<String, ListBuffer<JCStatement>> entry : kInfo.deserializeCases.entrySet()) {
650 JCBreak br = make.Break(null);
651 breaks.add(br);
652 List<JCStatement> stmts = entry.getValue().append(br).toList();
653 cases.add(make.Case(JCCase.STATEMENT, List.of(make.ConstantCaseLabel(make.Literal(entry.getKey()))), null, stmts, null));
654 }
655 JCSwitch sw = make.Switch(deserGetter("getImplMethodName", syms.stringType), cases.toList());
656 for (JCBreak br : breaks) {
657 br.target = sw;
658 }
659 JCBlock body = make.Block(0L, List.of(
660 sw,
661 make.Throw(makeNewClass(
662 syms.illegalArgumentExceptionType,
663 List.of(make.Literal("Invalid lambda deserialization"))))));
664 JCMethodDecl deser = make.MethodDef(make.Modifiers(kInfo.deserMethodSym.flags()),
665 names.deserializeLambda,
666 make.QualIdent(kInfo.deserMethodSym.getReturnType().tsym),
667 List.nil(),
668 List.of(make.VarDef(kInfo.deserParamSym, null)),
669 List.nil(),
670 body,
671 null);
672 deser.sym = kInfo.deserMethodSym;
673 deser.type = kInfo.deserMethodSym.type;
674 //System.err.printf("DESER: '%s'\n", deser);
675 return lower.translateMethod(attrEnv, deser, make);
676 }
677
678 /** Make an attributed class instance creation expression.
679 * @param ctype The class type.
680 * @param args The constructor arguments.
681 * @param cons The constructor symbol
682 */
683 JCNewClass makeNewClass(Type ctype, List<JCExpression> args, Symbol cons) {
684 JCNewClass tree = make.NewClass(null,
685 null, make.QualIdent(ctype.tsym), args, null);
686 tree.constructor = cons;
687 tree.type = ctype;
688 return tree;
689 }
690
691 /** Make an attributed class instance creation expression.
692 * @param ctype The class type.
693 * @param args The constructor arguments.
694 */
695 JCNewClass makeNewClass(Type ctype, List<JCExpression> args) {
696 return makeNewClass(ctype, args,
697 rs.resolveConstructor(null, attrEnv, ctype, TreeInfo.types(args), List.nil()));
698 }
699
700 private void addDeserializationCase(MethodHandleSymbol refSym, Type targetType, MethodSymbol samSym,
701 DiagnosticPosition pos, List<LoadableConstant> staticArgs, MethodType indyType) {
702 String functionalInterfaceClass = classSig(targetType);
703 String functionalInterfaceMethodName = samSym.getSimpleName().toString();
704 String functionalInterfaceMethodSignature = typeSig(types.erasure(samSym.type));
705 Symbol baseMethod = refSym.baseSymbol();
706 Symbol origMethod = baseMethod.baseSymbol();
707 if (baseMethod != origMethod && origMethod.owner == syms.objectType.tsym) {
708 //the implementation method is a java.lang.Object method transferred to an
709 //interface that does not declare it. Runtime will refer to this method as to
710 //a java.lang.Object method, so do the same:
711 refSym = ((MethodSymbol) origMethod).asHandle();
712 }
713 String implClass = classSig(types.erasure(refSym.owner.type));
714 String implMethodName = refSym.getQualifiedName().toString();
715 String implMethodSignature = typeSig(types.erasure(refSym.type));
716
717 JCExpression kindTest = eqTest(syms.intType, deserGetter("getImplMethodKind", syms.intType),
718 make.Literal(refSym.referenceKind()));
719 ListBuffer<JCExpression> serArgs = new ListBuffer<>();
720 int i = 0;
721 for (Type t : indyType.getParameterTypes()) {
722 List<JCExpression> indexAsArg = new ListBuffer<JCExpression>().append(make.Literal(i)).toList();
723 List<Type> argTypes = new ListBuffer<Type>().append(syms.intType).toList();
724 serArgs.add(make.TypeCast(types.erasure(t), deserGetter("getCapturedArg", syms.objectType, argTypes, indexAsArg)));
725 ++i;
726 }
727 JCStatement stmt = make.If(
728 deserTest(deserTest(deserTest(deserTest(deserTest(
729 kindTest,
730 "getFunctionalInterfaceClass", functionalInterfaceClass),
731 "getFunctionalInterfaceMethodName", functionalInterfaceMethodName),
732 "getFunctionalInterfaceMethodSignature", functionalInterfaceMethodSignature),
733 "getImplClass", implClass),
734 "getImplMethodSignature", implMethodSignature),
735 make.Return(makeIndyCall(
736 pos,
737 syms.lambdaMetafactory,
738 names.altMetafactory,
739 staticArgs, indyType, serArgs.toList(), samSym.name)),
740 null);
741 ListBuffer<JCStatement> stmts = kInfo.deserializeCases.get(implMethodName);
742 if (stmts == null) {
743 stmts = new ListBuffer<>();
744 kInfo.deserializeCases.put(implMethodName, stmts);
745 }
746 /* **
747 System.err.printf("+++++++++++++++++\n");
748 System.err.printf("*functionalInterfaceClass: '%s'\n", functionalInterfaceClass);
749 System.err.printf("*functionalInterfaceMethodName: '%s'\n", functionalInterfaceMethodName);
750 System.err.printf("*functionalInterfaceMethodSignature: '%s'\n", functionalInterfaceMethodSignature);
751 System.err.printf("*implMethodKind: %d\n", implMethodKind);
752 System.err.printf("*implClass: '%s'\n", implClass);
753 System.err.printf("*implMethodName: '%s'\n", implMethodName);
754 System.err.printf("*implMethodSignature: '%s'\n", implMethodSignature);
755 ****/
756 stmts.append(stmt);
757 }
758
759 private JCExpression eqTest(Type argType, JCExpression arg1, JCExpression arg2) {
760 JCBinary testExpr = make.Binary(Tag.EQ, arg1, arg2);
761 testExpr.operator = operators.resolveBinary(testExpr, Tag.EQ, argType, argType);
762 testExpr.setType(syms.booleanType);
763 return testExpr;
764 }
765
766 private JCExpression deserTest(JCExpression prev, String func, String lit) {
767 MethodType eqmt = new MethodType(List.of(syms.objectType), syms.booleanType, List.nil(), syms.methodClass);
768 Symbol eqsym = rs.resolveQualifiedMethod(null, attrEnv, syms.objectType, names.equals, List.of(syms.objectType), List.nil());
769 JCMethodInvocation eqtest = make.Apply(
770 List.nil(),
771 make.Select(deserGetter(func, syms.stringType), eqsym).setType(eqmt),
772 List.of(make.Literal(lit)));
773 eqtest.setType(syms.booleanType);
774 JCBinary compound = make.Binary(Tag.AND, prev, eqtest);
775 compound.operator = operators.resolveBinary(compound, Tag.AND, syms.booleanType, syms.booleanType);
776 compound.setType(syms.booleanType);
777 return compound;
778 }
779
780 private JCExpression deserGetter(String func, Type type) {
781 return deserGetter(func, type, List.nil(), List.nil());
782 }
783
784 private JCExpression deserGetter(String func, Type type, List<Type> argTypes, List<JCExpression> args) {
785 MethodType getmt = new MethodType(argTypes, type, List.nil(), syms.methodClass);
786 Symbol getsym = rs.resolveQualifiedMethod(null, attrEnv, syms.serializedLambdaType, names.fromString(func), argTypes, List.nil());
787 return make.Apply(
788 List.nil(),
789 make.Select(make.Ident(kInfo.deserParamSym).setType(syms.serializedLambdaType), getsym).setType(getmt),
790 args).setType(type);
791 }
792
793 /**
794 * Create new synthetic method with given flags, name, type, owner
795 */
796 private MethodSymbol makePrivateSyntheticMethod(long flags, Name name, Type type, Symbol owner) {
797 return new MethodSymbol(flags | SYNTHETIC | PRIVATE, name, type, owner);
798 }
799
800 private MethodType typeToMethodType(Type mt) {
801 Type type = types.erasure(mt);
802 return new MethodType(type.getParameterTypes(),
803 type.getReturnType(),
804 type.getThrownTypes(),
805 syms.methodClass);
806 }
807
808 /**
809 * Generate an indy method call to the meta factory
810 */
811 private JCExpression makeMetafactoryIndyCall(JCFunctionalExpression tree,
812 MethodHandleSymbol refSym, MethodSymbol nonDedupedRefSym,
813 List<JCExpression> indy_args) {
814 //determine the static bsm args
815 MethodSymbol samSym = (MethodSymbol) types.findDescriptorSymbol(tree.target.tsym);
816 List<LoadableConstant> staticArgs = List.of(
817 typeToMethodType(samSym.type),
818 refSym.asHandle(),
819 typeToMethodType(tree.getDescriptorType(types)));
820
821 //computed indy arg types
822 ListBuffer<Type> indy_args_types = new ListBuffer<>();
823 for (JCExpression arg : indy_args) {
824 indy_args_types.append(arg.type);
825 }
826
827 //finally, compute the type of the indy call
828 MethodType indyType = new MethodType(indy_args_types.toList(),
829 tree.type,
830 List.nil(),
831 syms.methodClass);
832
833 List<Symbol> bridges = bridges(tree);
834 boolean isSerializable = isSerializable(tree);
835 boolean needsAltMetafactory = tree.target.isIntersection() ||
836 isSerializable || bridges.length() > 1;
837
838 dumpStats(tree, needsAltMetafactory, nonDedupedRefSym);
839
840 Name metafactoryName = needsAltMetafactory ?
841 names.altMetafactory : names.metafactory;
842
843 if (needsAltMetafactory) {
844 ListBuffer<Type> markers = new ListBuffer<>();
845 List<Type> targets = tree.target.isIntersection() ?
846 types.directSupertypes(tree.target) :
847 List.nil();
848 for (Type t : targets) {
849 t = types.erasure(t);
850 if (t.tsym != syms.serializableType.tsym &&
851 t.tsym != tree.type.tsym &&
852 t.tsym != syms.objectType.tsym) {
853 markers.append(t);
854 }
855 }
856 int flags = isSerializable ? FLAG_SERIALIZABLE : 0;
857 boolean hasMarkers = markers.nonEmpty();
858 boolean hasBridges = bridges.nonEmpty();
859 if (hasMarkers) {
860 flags |= FLAG_MARKERS;
861 }
862 if (hasBridges) {
863 flags |= FLAG_BRIDGES;
864 }
865 staticArgs = staticArgs.append(LoadableConstant.Int(flags));
866 if (hasMarkers) {
867 staticArgs = staticArgs.append(LoadableConstant.Int(markers.length()));
868 staticArgs = staticArgs.appendList(List.convert(LoadableConstant.class, markers.toList()));
869 }
870 if (hasBridges) {
871 staticArgs = staticArgs.append(LoadableConstant.Int(bridges.length() - 1));
872 for (Symbol s : bridges) {
873 Type s_erasure = s.erasure(types);
874 if (!types.isSameType(s_erasure, samSym.erasure(types))) {
875 staticArgs = staticArgs.append(((MethodType)s.erasure(types)));
876 }
877 }
878 }
879 if (isSerializable) {
880 int prevPos = make.pos;
881 try {
882 make.at(kInfo.clazz);
883 addDeserializationCase(refSym, tree.type, samSym,
884 tree, staticArgs, indyType);
885 } finally {
886 make.at(prevPos);
887 }
888 }
889 }
890
891 Name lambdaName = samSym.name;
892 if (tree.codeReflectionInfo != null) {
893 lambdaName = lambdaName
894 .append(names.fromString("="))
895 .append(tree.codeReflectionInfo.codeModel().name);
896 }
897 Type lambdaMetafactory = tree.codeReflectionInfo != null ?
898 tree.codeReflectionInfo.reflectableLambdaMetafactory() : syms.lambdaMetafactory;
899 return makeIndyCall(tree, lambdaMetafactory, metafactoryName, staticArgs, indyType, indy_args, lambdaName);
900 }
901
902 /**
903 * Generate an indy method call with given name, type and static bootstrap
904 * arguments types
905 */
906 private JCExpression makeIndyCall(DiagnosticPosition pos, Type site, Name bsmName,
907 List<LoadableConstant> staticArgs, MethodType indyType, List<JCExpression> indyArgs,
908 Name methName) {
909 int prevPos = make.pos;
910 try {
911 make.at(pos);
912 List<Type> bsm_staticArgs = List.of(syms.methodHandleLookupType,
913 syms.stringType,
914 syms.methodTypeType).appendList(staticArgs.map(types::constantType));
915
916 MethodSymbol bsm = rs.resolveInternalMethod(pos, attrEnv, site,
917 bsmName, bsm_staticArgs, List.nil());
918
919 DynamicMethodSymbol dynSym =
920 new DynamicMethodSymbol(methName,
921 syms.noSymbol,
922 bsm.asHandle(),
923 indyType,
924 staticArgs.toArray(new LoadableConstant[staticArgs.length()]));
925 JCFieldAccess qualifier = make.Select(make.QualIdent(site.tsym), bsmName);
926 DynamicMethodSymbol existing = kInfo.dynMethSyms.putIfAbsent(
927 dynSym.poolKey(types), dynSym);
928 qualifier.sym = existing != null ? existing : dynSym;
929 qualifier.type = indyType.getReturnType();
930
931 JCMethodInvocation proxyCall = make.Apply(List.nil(), qualifier, indyArgs);
932 proxyCall.type = indyType.getReturnType();
933 return proxyCall;
934 } finally {
935 make.at(prevPos);
936 }
937 }
938
939 List<Symbol> bridges(JCFunctionalExpression tree) {
940 ClassSymbol csym =
941 types.makeFunctionalInterfaceClass(attrEnv, names.empty, tree.target, ABSTRACT | INTERFACE);
942 return types.functionalInterfaceBridges(csym);
943 }
944
945 /** does this functional expression require serialization support? */
946 boolean isSerializable(JCFunctionalExpression tree) {
947 if (forceSerializable) {
948 return true;
949 }
950 return types.asSuper(tree.target, syms.serializableType.tsym) != null;
951 }
952
953 void dumpStats(JCFunctionalExpression tree, boolean needsAltMetafactory, Symbol sym) {
954 if (dumpLambdaToMethodStats) {
955 if (tree instanceof JCLambda lambda) {
956 log.note(tree, diags.noteKey(lambda.wasMethodReference ? "mref.stat.1" : "lambda.stat",
957 needsAltMetafactory, sym));
958 } else if (tree instanceof JCMemberReference) {
959 log.note(tree, Notes.MrefStat(needsAltMetafactory, null));
960 }
961 }
962 }
963
964 /**
965 * This class retains all the useful information about a lambda expression,
966 * and acts as a translation map that is used by the main translation routines
967 * in order to adjust references to captured locals/members, etc.
968 */
969 class LambdaTranslationContext {
970
971 /** the underlying (untranslated) tree */
972 final JCFunctionalExpression tree;
973
974 /** a translation map from source symbols to translated symbols */
975 final Map<VarSymbol, VarSymbol> lambdaProxies = new HashMap<>();
976
977 /** the list of symbols captured by this lambda expression */
978 final List<VarSymbol> capturedVars;
979
980 /** the synthetic symbol for the method hoisting the translated lambda */
981 final MethodSymbol translatedSym;
982
983 /** the list of parameter declarations of the translated lambda method */
984 final List<JCVariableDecl> syntheticParams;
985
986 LambdaTranslationContext(JCLambda tree) {
987 this.tree = tree;
988 // This symbol will be filled-in in complete
989 Symbol owner = tree.owner;
990 if (owner.kind == MTH) {
991 final MethodSymbol originalOwner = (MethodSymbol)owner.clone(owner.owner);
992 this.translatedSym = new MethodSymbol(0, null, null, owner.enclClass()) {
993 @Override
994 public MethodSymbol originalEnclosingMethod() {
995 return originalOwner;
996 }
997 };
998 } else {
999 this.translatedSym = makePrivateSyntheticMethod(0, null, null, owner.enclClass());
1000 }
1001 ListBuffer<JCVariableDecl> params = new ListBuffer<>();
1002 ListBuffer<VarSymbol> parameterSymbols = new ListBuffer<>();
1003 LambdaCaptureScanner captureScanner = new LambdaCaptureScanner(tree);
1004 capturedVars = captureScanner.analyzeCaptures();
1005 for (VarSymbol captured : capturedVars) {
1006 VarSymbol trans = addSymbol(captured, LambdaSymbolKind.CAPTURED_VAR);
1007 params.append(make.VarDef(trans, null));
1008 parameterSymbols.add(trans);
1009 }
1010 for (JCVariableDecl param : tree.params) {
1011 VarSymbol trans = addSymbol(param.sym, LambdaSymbolKind.PARAM);
1012 params.append(make.VarDef(trans, null));
1013 parameterSymbols.add(trans);
1014 }
1015 syntheticParams = params.toList();
1016 completeLambdaMethodSymbol(owner, captureScanner.capturesThis);
1017 translatedSym.params = parameterSymbols.toList();
1018 }
1019
1020 void completeLambdaMethodSymbol(Symbol owner, boolean thisReferenced) {
1021 boolean inInterface = owner.enclClass().isInterface();
1022
1023 // Compute and set the lambda name
1024 Name name = isSerializable(tree)
1025 ? serializedLambdaName(owner)
1026 : lambdaName(owner);
1027
1028 //prepend synthetic args to translated lambda method signature
1029 Type type = types.createMethodTypeWithParameters(
1030 generatedLambdaSig(),
1031 TreeInfo.types(syntheticParams));
1032
1033 // If instance access isn't needed, make it static.
1034 // Interface instance methods must be default methods.
1035 // Lambda methods are private synthetic.
1036 // Inherit ACC_STRICT from the enclosing method, or, for clinit,
1037 // from the class.
1038 long flags = SYNTHETIC | LAMBDA_METHOD |
1039 owner.flags_field & STRICTFP |
1040 owner.owner.flags_field & STRICTFP |
1041 PRIVATE |
1042 (thisReferenced? (inInterface? DEFAULT : 0) : STATIC);
1043
1044 translatedSym.type = type;
1045 translatedSym.name = name;
1046 translatedSym.flags_field = flags;
1047 }
1048
1049 /**
1050 * For a serializable lambda, generate a disambiguating string
1051 * which maximizes stability across deserialization.
1052 *
1053 * @return String to differentiate synthetic lambda method names
1054 */
1055 private String serializedLambdaDisambiguation(Symbol owner) {
1056 StringBuilder buf = new StringBuilder();
1057 // Append the enclosing method signature to differentiate
1058 // overloaded enclosing methods. For lambdas enclosed in
1059 // lambdas, the generated lambda method will not have type yet,
1060 // but the enclosing method's name will have been generated
1061 // with this same method, so it will be unique and never be
1062 // overloaded.
1063 Assert.check(
1064 owner.type != null ||
1065 lambdaContext != null);
1066 if (owner.type != null) {
1067 buf.append(typeSig(owner.type, true));
1068 buf.append(":");
1069 }
1070
1071 // Add target type info
1072 buf.append(types.findDescriptorSymbol(tree.type.tsym).owner.flatName());
1073 buf.append(" ");
1074
1075 // Add variable assigned to
1076 if (pendingVar != null) {
1077 buf.append(pendingVar.flatName());
1078 buf.append("=");
1079 }
1080 //add captured locals info: type, name, order
1081 for (Symbol fv : capturedVars) {
1082 if (fv != owner) {
1083 buf.append(typeSig(fv.type, true));
1084 buf.append(" ");
1085 buf.append(fv.flatName());
1086 buf.append(",");
1087 }
1088 }
1089
1090 return buf.toString();
1091 }
1092
1093 /**
1094 * For a non-serializable lambda, generate a simple method.
1095 *
1096 * @return Name to use for the synthetic lambda method name
1097 */
1098 private Name lambdaName(Symbol owner) {
1099 StringBuilder buf = new StringBuilder();
1100 buf.append(names.lambda);
1101 buf.append(syntheticMethodNameComponent(owner));
1102 buf.append("$");
1103 buf.append(kInfo.syntheticNameIndex(buf, 0));
1104 return names.fromString(buf.toString());
1105 }
1106
1107 /**
1108 * @return Method name in a form that can be folded into a
1109 * component of a synthetic method name
1110 */
1111 String syntheticMethodNameComponent(Symbol owner) {
1112 long ownerFlags = owner.flags();
1113 if ((ownerFlags & BLOCK) != 0) {
1114 return (ownerFlags & STATIC) != 0 ?
1115 "static" : "new";
1116 } else if (owner.isConstructor()) {
1117 return "new";
1118 } else {
1119 return owner.name.toString();
1120 }
1121 }
1122
1123 /**
1124 * For a serializable lambda, generate a method name which maximizes
1125 * name stability across deserialization.
1126 *
1127 * @return Name to use for the synthetic lambda method name
1128 */
1129 private Name serializedLambdaName(Symbol owner) {
1130 StringBuilder buf = new StringBuilder();
1131 buf.append(names.lambda);
1132 // Append the name of the method enclosing the lambda.
1133 buf.append(syntheticMethodNameComponent(owner));
1134 buf.append('$');
1135 // Append a hash of the disambiguating string : enclosing method
1136 // signature, etc.
1137 String disam = serializedLambdaDisambiguation(owner);
1138 buf.append(Integer.toHexString(disam.hashCode()));
1139 buf.append('$');
1140 // The above appended name components may not be unique, append
1141 // a count based on the above name components.
1142 buf.append(kInfo.syntheticNameIndex(buf, 1));
1143 String result = buf.toString();
1144 //System.err.printf("serializedLambdaName: %s -- %s\n", result, disam);
1145 return names.fromString(result);
1146 }
1147
1148 /**
1149 * Translate a symbol of a given kind into something suitable for the
1150 * synthetic lambda body
1151 */
1152 VarSymbol translate(final VarSymbol sym, LambdaSymbolKind skind) {
1153 VarSymbol ret;
1154 boolean propagateAnnos = true;
1155 switch (skind) {
1156 case CAPTURED_VAR:
1157 Name name = (sym.flags() & LOCAL_CAPTURE_FIELD) != 0 ?
1158 sym.baseSymbol().name : sym.name;
1159 ret = new VarSymbol(SYNTHETIC | FINAL | PARAMETER, name, types.erasure(sym.type), translatedSym);
1160 propagateAnnos = false;
1161 break;
1162 case LOCAL_VAR:
1163 ret = new VarSymbol(sym.flags() & FINAL, sym.name, sym.type, translatedSym);
1164 ret.pos = sym.pos;
1165 // If sym.data == ElementKind.EXCEPTION_PARAMETER,
1166 // set ret.data = ElementKind.EXCEPTION_PARAMETER too.
1167 // Because method com.sun.tools.javac.jvm.Code.fillExceptionParameterPositions and
1168 // com.sun.tools.javac.jvm.Code.fillLocalVarPosition would use it.
1169 // See JDK-8257740 for more information.
1170 if (sym.isExceptionParameter()) {
1171 ret.setData(ElementKind.EXCEPTION_PARAMETER);
1172 }
1173 break;
1174 case PARAM:
1175 ret = new VarSymbol((sym.flags() & FINAL) | PARAMETER, sym.name, types.erasure(sym.type), translatedSym);
1176 ret.pos = sym.pos;
1177 break;
1178 default:
1179 Assert.error(skind.name());
1180 throw new AssertionError();
1181 }
1182 if (ret != sym && propagateAnnos) {
1183 ret.setDeclarationAttributes(sym.getRawAttributes());
1184 ret.setTypeAttributes(sym.getRawTypeAttributes());
1185 }
1186 return ret;
1187 }
1188
1189 VarSymbol addLocal(VarSymbol sym) {
1190 return addSymbol(sym, LambdaSymbolKind.LOCAL_VAR);
1191 }
1192
1193 private VarSymbol addSymbol(VarSymbol sym, LambdaSymbolKind skind) {
1194 return lambdaProxies.computeIfAbsent(sym, s -> translate(s, skind));
1195 }
1196
1197 JCTree translate(JCIdent lambdaIdent) {
1198 Symbol tSym = lambdaProxies.get(lambdaIdent.sym);
1199 return tSym != null ?
1200 make.Ident(tSym).setType(lambdaIdent.type) :
1201 null;
1202 }
1203
1204 Type generatedLambdaSig() {
1205 return types.erasure(tree.getDescriptorType(types));
1206 }
1207
1208 /**
1209 * Compute the set of local variables captured by this lambda expression.
1210 * Also determines whether this lambda expression captures the enclosing 'this'.
1211 */
1212 class LambdaCaptureScanner extends CaptureScanner {
1213 boolean capturesThis;
1214 Set<ClassSymbol> seenClasses = new HashSet<>();
1215
1216 LambdaCaptureScanner(JCLambda ownerTree) {
1217 super(ownerTree);
1218 }
1219
1220 @Override
1221 public void visitClassDef(JCClassDecl tree) {
1222 seenClasses.add(tree.sym);
1223 super.visitClassDef(tree);
1224 }
1225
1226 @Override
1227 public void visitIdent(JCIdent tree) {
1228 if (!tree.sym.isStatic() &&
1229 tree.sym.owner.kind == TYP &&
1230 (tree.sym.kind == VAR || tree.sym.kind == MTH) &&
1231 !seenClasses.contains(tree.sym.owner)) {
1232 if ((tree.sym.flags() & LOCAL_CAPTURE_FIELD) != 0) {
1233 // a local, captured by Lower - re-capture!
1234 addFreeVar((VarSymbol) tree.sym);
1235 } else {
1236 // a reference to an enclosing field or method, we need to capture 'this'
1237 capturesThis = true;
1238 }
1239 } else {
1240 // might be a local capture
1241 super.visitIdent(tree);
1242 }
1243 }
1244
1245 @Override
1246 public void visitSelect(JCFieldAccess tree) {
1247 if (tree.sym.kind == VAR &&
1248 (tree.sym.name == names._this ||
1249 tree.sym.name == names._super) &&
1250 !seenClasses.contains(tree.sym.type.tsym)) {
1251 capturesThis = true;
1252 }
1253 super.visitSelect(tree);
1254 }
1255
1256 @Override
1257 public void visitAnnotation(JCAnnotation tree) {
1258 // do nothing (annotation values look like captured instance fields)
1259 }
1260 }
1261
1262 /*
1263 * These keys provide mappings for various translated lambda symbols
1264 * and the prevailing order must be maintained.
1265 */
1266 enum LambdaSymbolKind {
1267 PARAM, // original to translated lambda parameters
1268 LOCAL_VAR, // original to translated lambda locals
1269 CAPTURED_VAR; // variables in enclosing scope to translated synthetic parameters
1270 }
1271 }
1272
1273 /**
1274 * ****************************************************************
1275 * Signature Generation
1276 * ****************************************************************
1277 */
1278
1279 private String typeSig(Type type) {
1280 return typeSig(type, false);
1281 }
1282
1283 private String typeSig(Type type, boolean allowIllegalSignature) {
1284 try {
1285 L2MSignatureGenerator sg = new L2MSignatureGenerator(allowIllegalSignature);
1286 sg.assembleSig(type);
1287 return sg.toString();
1288 } catch (InvalidSignatureException ex) {
1289 Symbol c = attrEnv.enclClass.sym;
1290 log.error(Errors.CannotGenerateClass(c, Fragments.IllegalSignature(c, ex.type())));
1291 return "<ERRONEOUS>";
1292 }
1293 }
1294
1295 private String classSig(Type type) {
1296 try {
1297 L2MSignatureGenerator sg = new L2MSignatureGenerator(false);
1298 sg.assembleClassSig(type);
1299 return sg.toString();
1300 } catch (InvalidSignatureException ex) {
1301 Symbol c = attrEnv.enclClass.sym;
1302 log.error(Errors.CannotGenerateClass(c, Fragments.IllegalSignature(c, ex.type())));
1303 return "<ERRONEOUS>";
1304 }
1305 }
1306
1307 /**
1308 * Signature Generation
1309 */
1310 private class L2MSignatureGenerator extends Types.SignatureGenerator {
1311
1312 /**
1313 * An output buffer for type signatures.
1314 */
1315 StringBuilder sb = new StringBuilder();
1316
1317 /**
1318 * Are signatures incompatible with JVM spec allowed?
1319 * Used by {@link LambdaTranslationContext#serializedLambdaDisambiguation(Symbol)}}.
1320 */
1321 boolean allowIllegalSignatures;
1322
1323 L2MSignatureGenerator(boolean allowIllegalSignatures) {
1324 types.super();
1325 this.allowIllegalSignatures = allowIllegalSignatures;
1326 }
1327
1328 @Override
1329 protected void reportIllegalSignature(Type t) {
1330 if (!allowIllegalSignatures) {
1331 super.reportIllegalSignature(t);
1332 }
1333 }
1334
1335 @Override
1336 protected void append(char ch) {
1337 sb.append(ch);
1338 }
1339
1340 @Override
1341 protected void append(byte[] ba) {
1342 Name name;
1343 try {
1344 name = names.fromUtf(ba);
1345 } catch (InvalidUtfException e) {
1346 throw new AssertionError(e);
1347 }
1348 sb.append(name.toString());
1349 }
1350
1351 @Override
1352 protected void append(Name name) {
1353 sb.append(name.toString());
1354 }
1355
1356 @Override
1357 public String toString() {
1358 return sb.toString();
1359 }
1360 }
1361 }