1 /*
2 * Copyright (c) 1999, 2026, 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.jvm;
27
28 import java.util.HashMap;
29 import java.util.Map;
30 import java.util.Set;
31
32 import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant;
33 import com.sun.tools.javac.tree.TreeInfo.PosKind;
34 import com.sun.tools.javac.util.*;
35 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
36 import com.sun.tools.javac.util.List;
37 import com.sun.tools.javac.code.*;
38 import com.sun.tools.javac.code.Attribute.TypeCompound;
39 import com.sun.tools.javac.code.Symbol.VarSymbol;
40 import com.sun.tools.javac.comp.*;
41 import com.sun.tools.javac.tree.*;
42
43 import com.sun.tools.javac.code.Symbol.*;
44 import com.sun.tools.javac.code.Type.*;
45 import com.sun.tools.javac.jvm.Code.*;
46 import com.sun.tools.javac.jvm.Items.*;
47 import com.sun.tools.javac.resources.CompilerProperties.Errors;
48 import com.sun.tools.javac.tree.JCTree.*;
49
50 import static com.sun.tools.javac.code.Flags.*;
51 import static com.sun.tools.javac.code.Kinds.Kind.*;
52 import static com.sun.tools.javac.code.TypeTag.*;
53 import static com.sun.tools.javac.jvm.ByteCodes.*;
54 import static com.sun.tools.javac.jvm.CRTFlags.*;
55 import static com.sun.tools.javac.main.Option.*;
56 import static com.sun.tools.javac.tree.JCTree.Tag.*;
57
58 /** This pass maps flat Java (i.e. without inner classes) to bytecodes.
59 *
60 * <p><b>This is NOT part of any supported API.
61 * If you write code that depends on this, you do so at your own risk.
62 * This code and its internal interfaces are subject to change or
63 * deletion without notice.</b>
64 */
65 public class Gen extends JCTree.Visitor {
66 protected static final Context.Key<Gen> genKey = new Context.Key<>();
67
68 private final Log log;
69 private final Symtab syms;
70 private final Check chk;
71 private final Resolve rs;
72 private final TreeMaker make;
73 private final Names names;
74 private final Target target;
75 private final String accessDollar;
76 private final Types types;
77 private final Lower lower;
78 private final Annotate annotate;
79 private final StringConcat concat;
80 private final LocalProxyVarsGen localProxyVarsGen;
81
82 /** Format of stackmap tables to be generated. */
83 private final Code.StackMapFormat stackMap;
84
85 /** A type that serves as the expected type for all method expressions.
86 */
87 private final Type methodType;
88
89 public static Gen instance(Context context) {
90 Gen instance = context.get(genKey);
91 if (instance == null)
92 instance = new Gen(context);
93 return instance;
94 }
95
96 /** Constant pool writer, set by genClass.
97 */
98 final PoolWriter poolWriter;
99
100 @SuppressWarnings("this-escape")
101 protected Gen(Context context) {
102 context.put(genKey, this);
103
104 names = Names.instance(context);
105 log = Log.instance(context);
106 syms = Symtab.instance(context);
107 chk = Check.instance(context);
108 rs = Resolve.instance(context);
109 make = TreeMaker.instance(context);
110 target = Target.instance(context);
111 types = Types.instance(context);
112 concat = StringConcat.instance(context);
113 localProxyVarsGen = LocalProxyVarsGen.instance(context);
114
115 methodType = new MethodType(null, null, null, syms.methodClass);
116 accessDollar = "access" + target.syntheticNameChar();
117 lower = Lower.instance(context);
118
119 Options options = Options.instance(context);
120 lineDebugInfo =
121 options.isUnset(G_CUSTOM) ||
122 options.isSet(G_CUSTOM, "lines");
123 varDebugInfo =
124 options.isUnset(G_CUSTOM)
125 ? options.isSet(G)
126 : options.isSet(G_CUSTOM, "vars");
127 genCrt = options.isSet(XJCOV);
128 debugCode = options.isSet("debug.code");
129 disableVirtualizedPrivateInvoke = options.isSet("disableVirtualizedPrivateInvoke");
130 poolWriter = new PoolWriter(types, names);
131
132 // ignore cldc because we cannot have both stackmap formats
133 this.stackMap = StackMapFormat.JSR202;
134 annotate = Annotate.instance(context);
135 qualifiedSymbolCache = new HashMap<>();
136 Preview preview = Preview.instance(context);
137 Source source = Source.instance(context);
138 allowValueClasses = preview.isEnabled() && Source.Feature.VALUE_CLASSES.allowedInSource(source);
139 }
140
141 /** Switches
142 */
143 private final boolean lineDebugInfo;
144 private final boolean varDebugInfo;
145 private final boolean genCrt;
146 private final boolean debugCode;
147 private boolean disableVirtualizedPrivateInvoke;
148 private final boolean allowValueClasses;
149
150 /** Code buffer, set by genMethod.
151 */
152 private Code code;
153
154 /** Items structure, set by genMethod.
155 */
156 private Items items;
157
158 /** Environment for symbol lookup, set by genClass
159 */
160 private Env<AttrContext> attrEnv;
161
162 /** The top level tree.
163 */
164 private JCCompilationUnit toplevel;
165
166 /** The number of code-gen errors in this class.
167 */
168 private int nerrs = 0;
169
170 boolean inCondSwitchExpression;
171 Chain switchExpressionTrueChain;
172 Chain switchExpressionFalseChain;
173 List<LocalItem> stackBeforeSwitchExpression;
174 LocalItem switchResult;
175 PatternMatchingCatchConfiguration patternMatchingCatchConfiguration =
176 new PatternMatchingCatchConfiguration(Set.of(), null, null, null);
177
178 /** Cache the symbol to reflect the qualifying type.
179 * key: corresponding type
180 * value: qualified symbol
181 */
182 Map<Type, Symbol> qualifiedSymbolCache;
183
184 /** Generate code to load an integer constant.
185 * @param n The integer to be loaded.
186 */
187 void loadIntConst(int n) {
188 items.makeImmediateItem(syms.intType, n).load();
189 }
190
191 /** The opcode that loads a zero constant of a given type code.
192 * @param tc The given type code (@see ByteCode).
193 */
194 public static int zero(int tc) {
195 switch(tc) {
196 case INTcode: case BYTEcode: case SHORTcode: case CHARcode:
197 return iconst_0;
198 case LONGcode:
199 return lconst_0;
200 case FLOATcode:
201 return fconst_0;
202 case DOUBLEcode:
203 return dconst_0;
204 default:
205 throw new AssertionError("zero");
206 }
207 }
208
209 /** The opcode that loads a one constant of a given type code.
210 * @param tc The given type code (@see ByteCode).
211 */
212 public static int one(int tc) {
213 return zero(tc) + 1;
214 }
215
216 /** Generate code to load -1 of the given type code (either int or long).
217 * @param tc The given type code (@see ByteCode).
218 */
219 void emitMinusOne(int tc) {
220 if (tc == LONGcode) {
221 items.makeImmediateItem(syms.longType, Long.valueOf(-1)).load();
222 } else {
223 code.emitop0(iconst_m1);
224 }
225 }
226
227 /** Construct a symbol to reflect the qualifying type that should
228 * appear in the byte code as per JLS 13.1.
229 *
230 * For {@literal target >= 1.2}: Clone a method with the qualifier as owner (except
231 * for those cases where we need to work around VM bugs).
232 *
233 * For {@literal target <= 1.1}: If qualified variable or method is defined in a
234 * non-accessible class, clone it with the qualifier class as owner.
235 *
236 * @param sym The accessed symbol
237 * @param site The qualifier's type.
238 */
239 Symbol binaryQualifier(Symbol sym, Type site) {
240
241 if (site.hasTag(ARRAY)) {
242 if (sym == syms.lengthVar ||
243 sym.owner != syms.arrayClass)
244 return sym;
245 // array clone can be qualified by the array type in later targets
246 Symbol qualifier;
247 if ((qualifier = qualifiedSymbolCache.get(site)) == null) {
248 qualifier = new ClassSymbol(Flags.PUBLIC, site.tsym.name, site, syms.noSymbol);
249 qualifiedSymbolCache.put(site, qualifier);
250 }
251 return sym.clone(qualifier);
252 }
253
254 if (sym.owner == site.tsym ||
255 (sym.flags() & (STATIC | SYNTHETIC)) == (STATIC | SYNTHETIC)) {
256 return sym;
257 }
258
259 // leave alone methods inherited from Object
260 // JLS 13.1.
261 if (sym.owner == syms.objectType.tsym)
262 return sym;
263
264 return sym.clone(site.tsym);
265 }
266
267 /** Insert a reference to given type in the constant pool,
268 * checking for an array with too many dimensions;
269 * return the reference's index.
270 * @param type The type for which a reference is inserted.
271 */
272 int makeRef(DiagnosticPosition pos, Type type) {
273 return poolWriter.putClass(checkDimension(pos, type));
274 }
275
276 /** Check if the given type is an array with too many dimensions.
277 */
278 private Type checkDimension(DiagnosticPosition pos, Type t) {
279 checkDimensionInternal(pos, t);
280 return t;
281 }
282
283 private void checkDimensionInternal(DiagnosticPosition pos, Type t) {
284 switch (t.getTag()) {
285 case METHOD:
286 checkDimension(pos, t.getReturnType());
287 for (List<Type> args = t.getParameterTypes(); args.nonEmpty(); args = args.tail)
288 checkDimension(pos, args.head);
289 break;
290 case ARRAY:
291 if (types.dimensions(t) > ClassFile.MAX_DIMENSIONS) {
292 log.error(pos, Errors.LimitDimensions);
293 nerrs++;
294 }
295 break;
296 default:
297 break;
298 }
299 }
300
301 /** Create a temporary variable.
302 * @param type The variable's type.
303 */
304 LocalItem makeTemp(Type type) {
305 VarSymbol v = new VarSymbol(Flags.SYNTHETIC,
306 names.empty,
307 type,
308 env.enclMethod.sym);
309 code.newLocal(v);
310 return items.makeLocalItem(v);
311 }
312
313 /** Generate code to call a non-private method or constructor.
314 * @param pos Position to be used for error reporting.
315 * @param site The type of which the method is a member.
316 * @param name The method's name.
317 * @param argtypes The method's argument types.
318 * @param isStatic A flag that indicates whether we call a
319 * static or instance method.
320 */
321 void callMethod(DiagnosticPosition pos,
322 Type site, Name name, List<Type> argtypes,
323 boolean isStatic) {
324 Symbol msym = rs.
325 resolveInternalMethod(pos, attrEnv, site, name, argtypes, null);
326 if (isStatic) items.makeStaticItem(msym).invoke();
327 else items.makeMemberItem(msym, name == names.init).invoke();
328 }
329
330 /** Is the given method definition an access method
331 * resulting from a qualified super? This is signified by an odd
332 * access code.
333 */
334 private boolean isAccessSuper(JCMethodDecl enclMethod) {
335 return
336 (enclMethod.mods.flags & SYNTHETIC) != 0 &&
337 isOddAccessName(enclMethod.name);
338 }
339
340 /** Does given name start with "access$" and end in an odd digit?
341 */
342 private boolean isOddAccessName(Name name) {
343 final String string = name.toString();
344 return
345 string.startsWith(accessDollar) &&
346 (string.charAt(string.length() - 1) & 1) != 0;
347 }
348
349 /* ************************************************************************
350 * Non-local exits
351 *************************************************************************/
352
353 /** Generate code to invoke the finalizer associated with given
354 * environment.
355 * Any calls to finalizers are appended to the environments `cont' chain.
356 * Mark beginning of gap in catch all range for finalizer.
357 */
358 void genFinalizer(Env<GenContext> env) {
359 if (code.isAlive() && env.info.finalize != null)
360 env.info.finalize.gen();
361 }
362
363 /** Generate code to call all finalizers of structures aborted by
364 * a non-local
365 * exit. Return target environment of the non-local exit.
366 * @param target The tree representing the structure that's aborted
367 * @param env The environment current at the non-local exit.
368 */
369 Env<GenContext> unwind(JCTree target, Env<GenContext> env) {
370 Env<GenContext> env1 = env;
371 while (true) {
372 genFinalizer(env1);
373 if (env1.tree == target) break;
374 env1 = env1.next;
375 }
376 return env1;
377 }
378
379 /** Mark end of gap in catch-all range for finalizer.
380 * @param env the environment which might contain the finalizer
381 * (if it does, env.info.gaps != null).
382 */
383 void endFinalizerGap(Env<GenContext> env) {
384 if (env.info.gaps != null && env.info.gaps.length() % 2 == 1)
385 env.info.gaps.append(code.curCP());
386 }
387
388 /** Mark end of all gaps in catch-all ranges for finalizers of environments
389 * lying between, and including to two environments.
390 * @param from the most deeply nested environment to mark
391 * @param to the least deeply nested environment to mark
392 */
393 void endFinalizerGaps(Env<GenContext> from, Env<GenContext> to) {
394 Env<GenContext> last = null;
395 while (last != to) {
396 endFinalizerGap(from);
397 last = from;
398 from = from.next;
399 }
400 }
401
402 /** Do any of the structures aborted by a non-local exit have
403 * finalizers that require an empty stack?
404 * @param target The tree representing the structure that's aborted
405 * @param env The environment current at the non-local exit.
406 */
407 boolean hasFinally(JCTree target, Env<GenContext> env) {
408 while (env.tree != target) {
409 if (env.tree.hasTag(TRY) && env.info.finalize.hasFinalizer())
410 return true;
411 env = env.next;
412 }
413 return false;
414 }
415
416 /* ************************************************************************
417 * Normalizing class-members.
418 *************************************************************************/
419
420 /** Distribute member initializer code into constructors and {@code <clinit>}
421 * method.
422 * @param classDecl The class declaration to normalize.
423 */
424 List<JCTree> normalizeDefs(JCClassDecl classDecl) {
425 ListBuffer<JCStatement> initCode = new ListBuffer<>();
426 // only used for value classes
427 ListBuffer<JCStatement> initBlocks = new ListBuffer<>();
428 ListBuffer<Attribute.TypeCompound> initTAs = new ListBuffer<>();
429 ListBuffer<JCStatement> clinitCode = new ListBuffer<>();
430 ListBuffer<Attribute.TypeCompound> clinitTAs = new ListBuffer<>();
431 ListBuffer<JCTree> methodDefs = new ListBuffer<>();
432 // Sort definitions into three listbuffers:
433 // - initCode for instance initializers
434 // - clinitCode for class initializers
435 // - methodDefs for method definitions
436 for (List<JCTree> l = classDecl.defs; l.nonEmpty(); l = l.tail) {
437 JCTree def = l.head;
438 switch (def.getTag()) {
439 case BLOCK:
440 JCBlock block = (JCBlock)def;
441 if ((block.flags & STATIC) != 0)
442 clinitCode.append(block);
443 else if ((block.flags & SYNTHETIC) == 0) {
444 if (classDecl.sym.isValueClass()) {
445 initBlocks.append(block);
446 } else {
447 initCode.append(block);
448 }
449 }
450 break;
451 case METHODDEF:
452 methodDefs.append(def);
453 break;
454 case VARDEF:
455 JCVariableDecl vdef = (JCVariableDecl) def;
456 VarSymbol sym = vdef.sym;
457 checkDimension(vdef.pos(), sym.type);
458 if (vdef.init != null) {
459 if ((sym.flags() & STATIC) == 0) {
460 // Always initialize instance variables.
461 JCStatement init = make.at(vdef.pos()).
462 Assignment(sym, vdef.init);
463 initCode.append(init);
464 init.endpos = vdef.endpos;
465 initTAs.addAll(getAndRemoveNonFieldTAs(sym));
466 } else if (sym.getConstValue() == null) {
467 // Initialize class (static) variables only if
468 // they are not compile-time constants.
469 JCStatement init = make.at(vdef.pos).
470 Assignment(sym, vdef.init);
471 clinitCode.append(init);
472 init.endpos = vdef.endpos;
473 clinitTAs.addAll(getAndRemoveNonFieldTAs(sym));
474 } else {
475 checkStringConstant(vdef.init.pos(), sym.getConstValue());
476 /* if the init contains a reference to an external class, add it to the
477 * constant's pool
478 */
479 vdef.init.accept(classReferenceVisitor);
480 }
481 }
482 break;
483 default:
484 Assert.error();
485 }
486 }
487 // Insert any instance initializers into all constructors.
488 List<TypeCompound> initTAlist = List.nil();
489 if (initCode.nonEmpty() || initBlocks.nonEmpty()) {
490 initTAs.addAll(classDecl.sym.getInitTypeAttributes());
491 initTAlist = initTAs.toList();
492 }
493 for (JCTree t : methodDefs) {
494 normalizeMethod((JCMethodDecl)t, initCode.toList(), initBlocks.toList(), initTAlist);
495 }
496 // If there are class initializers, create a <clinit> method
497 // that contains them as its body.
498 if (clinitCode.length() != 0) {
499 MethodSymbol clinit = new MethodSymbol(
500 STATIC | (classDecl.sym.flags() & STRICTFP),
501 names.clinit,
502 new MethodType(
503 List.nil(), syms.voidType,
504 List.nil(), syms.methodClass),
505 classDecl.sym);
506 classDecl.sym.members().enter(clinit);
507 List<JCStatement> clinitStats = clinitCode.toList();
508 JCBlock block = make.at(clinitStats.head.pos()).Block(0, clinitStats);
509 block.bracePos = TreeInfo.endPos(clinitStats.last());
510 methodDefs.append(make.MethodDef(clinit, block));
511
512 if (!clinitTAs.isEmpty())
513 clinit.appendUniqueTypeAttributes(clinitTAs.toList());
514 if (!classDecl.sym.getClassInitTypeAttributes().isEmpty())
515 clinit.appendUniqueTypeAttributes(classDecl.sym.getClassInitTypeAttributes());
516 }
517 // Return all method definitions.
518 return methodDefs.toList();
519 }
520
521 private List<Attribute.TypeCompound> getAndRemoveNonFieldTAs(VarSymbol sym) {
522 List<TypeCompound> tas = sym.getRawTypeAttributes();
523 ListBuffer<Attribute.TypeCompound> fieldTAs = new ListBuffer<>();
524 ListBuffer<Attribute.TypeCompound> nonfieldTAs = new ListBuffer<>();
525 for (TypeCompound ta : tas) {
526 Assert.check(ta.getPosition().type != TargetType.UNKNOWN);
527 if (ta.getPosition().type == TargetType.FIELD) {
528 fieldTAs.add(ta);
529 } else {
530 nonfieldTAs.add(ta);
531 }
532 }
533 sym.setTypeAttributes(fieldTAs.toList());
534 return nonfieldTAs.toList();
535 }
536
537 /** Check a constant value and report if it is a string that is
538 * too large.
539 */
540 private void checkStringConstant(DiagnosticPosition pos, Object constValue) {
541 if (nerrs != 0 || // only complain about a long string once
542 constValue == null ||
543 !(constValue instanceof String str) ||
544 str.length() < PoolWriter.MAX_STRING_LENGTH)
545 return;
546 log.error(pos, Errors.LimitString);
547 nerrs++;
548 }
549
550 /** Insert instance initializer code into constructors prior to the super() call.
551 * @param md The tree potentially representing a
552 * constructor's definition.
553 * @param initCode The list of instance initializer statements.
554 * @param initTAs Type annotations from the initializer expression.
555 */
556 void normalizeMethod(JCMethodDecl md, List<JCStatement> initCode, List<JCStatement> initBlocks, List<TypeCompound> initTAs) {
557 if (TreeInfo.isConstructor(md) && TreeInfo.hasConstructorCall(md, names._super)) {
558 // We are seeing a constructor that has a super() call.
559 // Find the super() invocation and append the given initializer code.
560 if (initCode.nonEmpty() || initBlocks.nonEmpty()) {
561 if (allowValueClasses &&
562 (md.sym.owner.isValueClass() || ((md.sym.owner.flags_field & RECORD) != 0))) {
563 md.body.stats = initCode.appendList(md.body.stats);
564 TreeInfo.mapSuperCalls(md.body, supercall -> make.Block(0, initBlocks.prepend(supercall)));
565 } else {
566 TreeInfo.mapSuperCalls(md.body, supercall -> make.Block(0, initCode.prepend(supercall)));
567 }
568 md.sym.appendUniqueTypeAttributes(initTAs);
569 }
570
571 if (md.body.bracePos == Position.NOPOS)
572 md.body.bracePos = TreeInfo.endPos(md.body.stats.last());
573 }
574 }
575
576 /* ************************************************************************
577 * Traversal methods
578 *************************************************************************/
579
580 /** Visitor argument: The current environment.
581 */
582 Env<GenContext> env;
583
584 /** Visitor argument: The expected type (prototype).
585 */
586 Type pt;
587
588 /** Visitor result: The item representing the computed value.
589 */
590 Item result;
591
592 /** Visitor method: generate code for a definition, catching and reporting
593 * any completion failures.
594 * @param tree The definition to be visited.
595 * @param env The environment current at the definition.
596 */
597 public void genDef(JCTree tree, Env<GenContext> env) {
598 Env<GenContext> prevEnv = this.env;
599 try {
600 this.env = env;
601 tree.accept(this);
602 } catch (CompletionFailure ex) {
603 chk.completionError(tree.pos(), ex);
604 } finally {
605 this.env = prevEnv;
606 }
607 }
608
609 /** Derived visitor method: check whether CharacterRangeTable
610 * should be emitted, if so, put a new entry into CRTable
611 * and call method to generate bytecode.
612 * If not, just call method to generate bytecode.
613 * @see #genStat(JCTree, Env)
614 *
615 * @param tree The tree to be visited.
616 * @param env The environment to use.
617 * @param crtFlags The CharacterRangeTable flags
618 * indicating type of the entry.
619 */
620 public void genStat(JCTree tree, Env<GenContext> env, int crtFlags) {
621 if (!genCrt) {
622 genStat(tree, env);
623 return;
624 }
625 int startpc = code.curCP();
626 genStat(tree, env);
627 if (tree.hasTag(Tag.BLOCK)) crtFlags |= CRT_BLOCK;
628 code.crt.put(tree, crtFlags, startpc, code.curCP());
629 }
630
631 /** Derived visitor method: generate code for a statement.
632 */
633 public void genStat(JCTree tree, Env<GenContext> env) {
634 if (code.isAlive()) {
635 code.statBegin(tree.pos);
636 genDef(tree, env);
637 } else if (env.info.isSwitch && tree.hasTag(VARDEF)) {
638 // variables whose declarations are in a switch
639 // can be used even if the decl is unreachable.
640 code.newLocal(((JCVariableDecl) tree).sym);
641 }
642 }
643
644 /** Derived visitor method: check whether CharacterRangeTable
645 * should be emitted, if so, put a new entry into CRTable
646 * and call method to generate bytecode.
647 * If not, just call method to generate bytecode.
648 * @see #genStats(List, Env)
649 *
650 * @param trees The list of trees to be visited.
651 * @param env The environment to use.
652 * @param crtFlags The CharacterRangeTable flags
653 * indicating type of the entry.
654 */
655 public void genStats(List<JCStatement> trees, Env<GenContext> env, int crtFlags) {
656 if (!genCrt) {
657 genStats(trees, env);
658 return;
659 }
660 if (trees.length() == 1) { // mark one statement with the flags
661 genStat(trees.head, env, crtFlags | CRT_STATEMENT);
662 } else {
663 int startpc = code.curCP();
664 genStats(trees, env);
665 code.crt.put(trees, crtFlags, startpc, code.curCP());
666 }
667 }
668
669 /** Derived visitor method: generate code for a list of statements.
670 */
671 public void genStats(List<? extends JCTree> trees, Env<GenContext> env) {
672 for (List<? extends JCTree> l = trees; l.nonEmpty(); l = l.tail)
673 genStat(l.head, env, CRT_STATEMENT);
674 }
675
676 /** Derived visitor method: check whether CharacterRangeTable
677 * should be emitted, if so, put a new entry into CRTable
678 * and call method to generate bytecode.
679 * If not, just call method to generate bytecode.
680 * @see #genCond(JCTree,boolean)
681 *
682 * @param tree The tree to be visited.
683 * @param crtFlags The CharacterRangeTable flags
684 * indicating type of the entry.
685 */
686 public CondItem genCond(JCTree tree, int crtFlags) {
687 if (!genCrt) return genCond(tree, false);
688 int startpc = code.curCP();
689 CondItem item = genCond(tree, (crtFlags & CRT_FLOW_CONTROLLER) != 0);
690 code.crt.put(tree, crtFlags, startpc, code.curCP());
691 return item;
692 }
693
694 /** Derived visitor method: generate code for a boolean
695 * expression in a control-flow context.
696 * @param _tree The expression to be visited.
697 * @param markBranches The flag to indicate that the condition is
698 * a flow controller so produced conditions
699 * should contain a proper tree to generate
700 * CharacterRangeTable branches for them.
701 */
702 public CondItem genCond(JCTree _tree, boolean markBranches) {
703 JCTree inner_tree = TreeInfo.skipParens(_tree);
704 if (inner_tree.hasTag(CONDEXPR)) {
705 JCConditional tree = (JCConditional)inner_tree;
706 CondItem cond = genCond(tree.cond, CRT_FLOW_CONTROLLER);
707 if (cond.isTrue()) {
708 code.resolve(cond.trueJumps);
709 CondItem result = genCond(tree.truepart, CRT_FLOW_TARGET);
710 if (markBranches) result.tree = tree.truepart;
711 return result;
712 }
713 if (cond.isFalse()) {
714 code.resolve(cond.falseJumps);
715 CondItem result = genCond(tree.falsepart, CRT_FLOW_TARGET);
716 if (markBranches) result.tree = tree.falsepart;
717 return result;
718 }
719 Chain secondJumps = cond.jumpFalse();
720 code.resolve(cond.trueJumps);
721 CondItem first = genCond(tree.truepart, CRT_FLOW_TARGET);
722 if (markBranches) first.tree = tree.truepart;
723 Chain falseJumps = first.jumpFalse();
724 code.resolve(first.trueJumps);
725 Chain trueJumps = code.branch(goto_);
726 code.resolve(secondJumps);
727 CondItem second = genCond(tree.falsepart, CRT_FLOW_TARGET);
728 CondItem result = items.makeCondItem(second.opcode,
729 Code.mergeChains(trueJumps, second.trueJumps),
730 Code.mergeChains(falseJumps, second.falseJumps));
731 if (markBranches) result.tree = tree.falsepart;
732 return result;
733 } else if (inner_tree.hasTag(SWITCH_EXPRESSION)) {
734 code.resolvePending();
735
736 boolean prevInCondSwitchExpression = inCondSwitchExpression;
737 Chain prevSwitchExpressionTrueChain = switchExpressionTrueChain;
738 Chain prevSwitchExpressionFalseChain = switchExpressionFalseChain;
739 try {
740 inCondSwitchExpression = true;
741 switchExpressionTrueChain = null;
742 switchExpressionFalseChain = null;
743 try {
744 doHandleSwitchExpression((JCSwitchExpression) inner_tree);
745 } catch (CompletionFailure ex) {
746 chk.completionError(_tree.pos(), ex);
747 code.state.stacksize = 1;
748 }
749 CondItem result = items.makeCondItem(goto_,
750 switchExpressionTrueChain,
751 switchExpressionFalseChain);
752 if (markBranches) result.tree = _tree;
753 return result;
754 } finally {
755 inCondSwitchExpression = prevInCondSwitchExpression;
756 switchExpressionTrueChain = prevSwitchExpressionTrueChain;
757 switchExpressionFalseChain = prevSwitchExpressionFalseChain;
758 }
759 } else if (inner_tree.hasTag(LETEXPR) && ((LetExpr) inner_tree).needsCond) {
760 code.resolvePending();
761
762 LetExpr tree = (LetExpr) inner_tree;
763
764 if (tree.needsLineNumberTableEntry) {
765 code.statBegin(tree.pos);
766 }
767
768 int limit = code.nextreg;
769 int prevLetExprStart = code.setLetExprStackPos(code.state.stacksize);
770 try {
771 genStats(tree.defs, env);
772 } finally {
773 code.setLetExprStackPos(prevLetExprStart);
774 }
775 CondItem result = genCond(tree.expr, markBranches);
776 Assert.checkNull(code.pendingJumps);
777 code.endScopes(limit);
778 //make sure variables defined in the let expression are not included
779 //in the defined variables for jumps that go outside of this let
780 //expression:
781 code.undefineVariablesInChain(result.falseJumps, limit);
782 code.undefineVariablesInChain(result.trueJumps, limit);
783 return result;
784 } else if (inner_tree instanceof JCTypeCast cast) {
785 //as part of condition, the cast must always be (boolean), assert that holds:
786 Assert.check(cast.type.hasTag(BOOLEAN));
787 CondItem result = genCond(cast.expr, markBranches);
788 setTypeAnnotationPositions(cast.pos);
789 return result;
790 } else if (inner_tree instanceof JCMethodInvocation mi &&
791 mi.boxingKind == JCMethodInvocation.BoxingKind.UNBOX &&
792 ((JCFieldAccess) mi.meth).selected instanceof JCTree unboxedValue &&
793 findDeepestCast(unboxedValue) instanceof JCTypeCast deepestCast &&
794 deepestCast.expr instanceof JCMethodInvocation boxing &&
795 boxing.boxingKind == JCMethodInvocation.BoxingKind.BOX) {
796 //case like:
797 //(Boolean) (b && (result = 1) > 0)
798 //expanded to:
799 //((Boolean)Boolean.valueOf((b && (result = 1) > 0))).booleanValue()
800 //it is impossible to correctly track variable DA across the method calls,
801 //so call after evaluating the actual condition,
802 //keep the true and false branches separate
803 //note that in place of (Boolean), there may be multiple casts,
804 //to different types, including (Boolean) (Object) (String) (Object) (Boolean)
805
806 //generate the actual condition:
807 JCExpression boxedValue = boxing.args.head;
808 CondItem value = genCond(boxedValue, markBranches);
809
810 //now generate the cast cascade, once for true and once for false,
811 //ignoring the resulting value, but preserving the codepath:
812 ClassSymbol jlBoolean = types.boxedClass(syms.booleanType);
813
814 Chain secondJumps = value.jumpFalse();
815 code.resolve(value.trueJumps);
816 make.at(boxing.args.head);
817 VarSymbol _true =
818 rs.resolveInternalField(_tree, attrEnv, jlBoolean.type, names.TRUE);
819 deepestCast.expr = make.QualIdent(_true);
820 genExpr(unboxedValue, unboxedValue.type).drop();
821 Chain trueJumps = code.branch(goto_);
822
823 code.resolve(secondJumps);
824 make.at(boxing.args.head);
825 VarSymbol _false =
826 rs.resolveInternalField(_tree, attrEnv, jlBoolean.type, names.FALSE);
827 deepestCast.expr = make.QualIdent(_false);
828 genExpr(unboxedValue, unboxedValue.type).drop();
829 Chain falseJumps = code.branch(goto_);
830
831 CondItem result = items.makeCondItem(goto_,
832 trueJumps,
833 falseJumps);
834 if (markBranches) result.tree = _tree;
835
836 deepestCast.expr = boxing;
837
838 return result;
839 } else {
840 CondItem result = genExpr(_tree, syms.booleanType).mkCond();
841 if (markBranches) result.tree = _tree;
842 return result;
843 }
844 }
845 //where:
846 JCTree findDeepestCast(JCTree source) {
847 JCTree lastTypeCast = null;
848
849 while (TreeInfo.skipParens(source) instanceof JCTypeCast tc) {
850 lastTypeCast = tc;
851 source = tc.expr;
852 }
853
854 return lastTypeCast;
855 }
856
857 public Code getCode() {
858 return code;
859 }
860
861 public Items getItems() {
862 return items;
863 }
864
865 public Env<AttrContext> getAttrEnv() {
866 return attrEnv;
867 }
868
869 /** Visitor class for expressions which might be constant expressions.
870 * This class is a subset of TreeScanner. Intended to visit trees pruned by
871 * Lower as long as constant expressions looking for references to any
872 * ClassSymbol. Any such reference will be added to the constant pool so
873 * automated tools can detect class dependencies better.
874 */
875 class ClassReferenceVisitor extends JCTree.Visitor {
876
877 @Override
878 public void visitTree(JCTree tree) {}
879
880 @Override
881 public void visitBinary(JCBinary tree) {
882 tree.lhs.accept(this);
883 tree.rhs.accept(this);
884 }
885
886 @Override
887 public void visitSelect(JCFieldAccess tree) {
888 if (tree.selected.type.hasTag(CLASS)) {
889 makeRef(tree.selected.pos(), tree.selected.type);
890 }
891 }
892
893 @Override
894 public void visitIdent(JCIdent tree) {
895 if (tree.sym.owner instanceof ClassSymbol classSymbol) {
896 poolWriter.putClass(classSymbol);
897 }
898 }
899
900 @Override
901 public void visitConditional(JCConditional tree) {
902 tree.cond.accept(this);
903 tree.truepart.accept(this);
904 tree.falsepart.accept(this);
905 }
906
907 @Override
908 public void visitUnary(JCUnary tree) {
909 tree.arg.accept(this);
910 }
911
912 @Override
913 public void visitParens(JCParens tree) {
914 tree.expr.accept(this);
915 }
916
917 @Override
918 public void visitTypeCast(JCTypeCast tree) {
919 tree.expr.accept(this);
920 }
921 }
922
923 private ClassReferenceVisitor classReferenceVisitor = new ClassReferenceVisitor();
924
925 /** Visitor method: generate code for an expression, catching and reporting
926 * any completion failures.
927 * @param tree The expression to be visited.
928 * @param pt The expression's expected type (proto-type).
929 */
930 public Item genExpr(JCTree tree, Type pt) {
931 if (!code.isAlive()) {
932 return items.makeStackItem(pt);
933 }
934
935 Type prevPt = this.pt;
936 try {
937 if (tree.type.constValue() != null) {
938 // Short circuit any expressions which are constants
939 tree.accept(classReferenceVisitor);
940 checkStringConstant(tree.pos(), tree.type.constValue());
941 Symbol sym = TreeInfo.symbol(tree);
942 if (sym != null && isConstantDynamic(sym)) {
943 result = items.makeDynamicItem(sym);
944 } else {
945 result = items.makeImmediateItem(tree.type, tree.type.constValue());
946 }
947 } else {
948 this.pt = pt;
949 tree.accept(this);
950 }
951 return result.coerce(pt);
952 } catch (CompletionFailure ex) {
953 chk.completionError(tree.pos(), ex);
954 code.state.stacksize = 1;
955 return items.makeStackItem(pt);
956 } finally {
957 this.pt = prevPt;
958 }
959 }
960
961 public boolean isConstantDynamic(Symbol sym) {
962 return sym.kind == VAR &&
963 sym instanceof DynamicVarSymbol dynamicVarSymbol &&
964 dynamicVarSymbol.isDynamic();
965 }
966
967 /** Derived visitor method: generate code for a list of method arguments.
968 * @param trees The argument expressions to be visited.
969 * @param pts The expression's expected types (i.e. the formal parameter
970 * types of the invoked method).
971 */
972 public void genArgs(List<JCExpression> trees, List<Type> pts) {
973 for (List<JCExpression> l = trees; l.nonEmpty(); l = l.tail) {
974 genExpr(l.head, pts.head).load();
975 pts = pts.tail;
976 }
977 // require lists be of same length
978 Assert.check(pts.isEmpty());
979 }
980
981 /* ************************************************************************
982 * Visitor methods for statements and definitions
983 *************************************************************************/
984
985 public void visitMethodDef(JCMethodDecl tree) {
986 // Create a new local environment that points pack at method
987 // definition.
988 Env<GenContext> localEnv = env.dup(tree);
989 localEnv.enclMethod = tree;
990 // The expected type of every return statement in this method
991 // is the method's return type.
992 this.pt = tree.sym.erasure(types).getReturnType();
993
994 checkDimension(tree.pos(), tree.sym.erasure(types));
995 genMethod(tree, localEnv, false);
996 }
997 //where
998 /** Generate code for a method.
999 * @param tree The tree representing the method definition.
1000 * @param env The environment current for the method body.
1001 * @param fatcode A flag that indicates whether all jumps are
1002 * within 32K. We first invoke this method under
1003 * the assumption that fatcode == false, i.e. all
1004 * jumps are within 32K. If this fails, fatcode
1005 * is set to true and we try again.
1006 */
1007 void genMethod(JCMethodDecl tree, Env<GenContext> env, boolean fatcode) {
1008 MethodSymbol meth = tree.sym;
1009 int extras = 0;
1010 // Count up extra parameters
1011 if (meth.isConstructor()) {
1012 localProxyVarsGen.patchConstructor(tree, make);
1013 extras++;
1014 if (meth.enclClass().isInner() &&
1015 !meth.enclClass().isStatic()) {
1016 extras++;
1017 }
1018 } else if ((tree.mods.flags & STATIC) == 0) {
1019 extras++;
1020 }
1021 // System.err.println("Generating " + meth + " in " + meth.owner); //DEBUG
1022 if (Code.width(types.erasure(env.enclMethod.sym.type).getParameterTypes()) + extras >
1023 ClassFile.MAX_PARAMETERS) {
1024 log.error(tree.pos(), Errors.LimitParameters);
1025 nerrs++;
1026 }
1027
1028 else if (tree.body != null) {
1029 // Create a new code structure and initialize it.
1030 int startpcCrt = initCode(tree, env, fatcode);
1031
1032 genStat(tree.body, env);
1033
1034 if (code.state.stacksize != 0) {
1035 log.error(tree.body.pos(), Errors.StackSimError(tree.sym));
1036 throw new AssertionError();
1037 }
1038
1039 // If last statement could complete normally, insert a
1040 // return at the end.
1041 if (code.isAlive()) {
1042 code.statBegin(TreeInfo.endPos(tree.body));
1043 if (env.enclMethod == null ||
1044 env.enclMethod.sym.type.getReturnType().hasTag(VOID)) {
1045 code.emitop0(return_);
1046 } else {
1047 // sometime dead code seems alive (4415991);
1048 // generate a small loop instead
1049 int startpc = code.entryPoint();
1050 CondItem c = items.makeCondItem(goto_);
1051 code.resolve(c.jumpTrue(), startpc);
1052 }
1053 }
1054 if (genCrt)
1055 code.crt.put(tree.body,
1056 CRT_BLOCK,
1057 startpcCrt,
1058 code.curCP());
1059
1060 code.endScopes(0);
1061
1062 // If we exceeded limits, panic
1063 if (code.checkLimits(tree.pos(), log)) {
1064 nerrs++;
1065 return;
1066 }
1067
1068 // If we generated short code but got a long jump, do it again
1069 // with fatCode = true.
1070 if (!fatcode && code.fatcode) genMethod(tree, env, true);
1071
1072 // Clean up
1073 if(stackMap == StackMapFormat.JSR202) {
1074 code.lastFrame = null;
1075 code.frameBeforeLast = null;
1076 }
1077
1078 // Compress exception table
1079 code.compressCatchTable();
1080
1081 // Fill in type annotation positions for exception parameters
1082 code.fillExceptionParameterPositions();
1083 }
1084 if (meth.isConstructor()) {
1085 localProxyVarsGen.unpatchConstructor(tree, make);
1086 }
1087 }
1088
1089 private int initCode(JCMethodDecl tree, Env<GenContext> env, boolean fatcode) {
1090 MethodSymbol meth = tree.sym;
1091
1092 // Create a new code structure.
1093 meth.code = code = new Code(meth,
1094 fatcode,
1095 lineDebugInfo ? toplevel.lineMap : null,
1096 varDebugInfo,
1097 stackMap,
1098 debugCode,
1099 genCrt ? new CRTable(tree) : null,
1100 syms,
1101 types,
1102 poolWriter,
1103 allowValueClasses);
1104 items = new Items(poolWriter, code, syms, types);
1105 if (code.debugCode) {
1106 System.err.println(meth + " for body " + tree);
1107 }
1108
1109 // If method is not static, create a new local variable address
1110 // for `this'.
1111 if ((tree.mods.flags & STATIC) == 0) {
1112 Type selfType = meth.owner.type;
1113 if (meth.isConstructor() && selfType != syms.objectType)
1114 selfType = UninitializedType.uninitializedThis(selfType);
1115 code.setDefined(
1116 code.newLocal(
1117 new VarSymbol(FINAL, names._this, selfType, meth.owner)));
1118 }
1119
1120 // Mark all parameters as defined from the beginning of
1121 // the method.
1122 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
1123 checkDimension(l.head.pos(), l.head.sym.type);
1124 code.setDefined(code.newLocal(l.head.sym));
1125 }
1126
1127 if (allowValueClasses && meth.isConstructor()) {
1128 code.initUnsetStrictFields(env.enclClass.sym);
1129 }
1130
1131 // Get ready to generate code for method body.
1132 int startpcCrt = genCrt ? code.curCP() : 0;
1133 code.entryPoint();
1134
1135 // Suppress initial stackmap
1136 code.pendingStackMap = false;
1137
1138 return startpcCrt;
1139 }
1140
1141 public void visitVarDef(JCVariableDecl tree) {
1142 VarSymbol v = tree.sym;
1143 if (tree.init != null) {
1144 checkStringConstant(tree.init.pos(), v.getConstValue());
1145 if (v.getConstValue() == null || varDebugInfo) {
1146 Assert.check(code.isStatementStart());
1147 code.newLocal(v);
1148 genExpr(tree.init, v.erasure(types)).load();
1149 items.makeLocalItem(v).store();
1150 Assert.check(code.isStatementStart());
1151 }
1152 } else {
1153 code.newLocal(v);
1154 }
1155 checkDimension(tree.pos(), v.type);
1156 }
1157
1158 public void visitSkip(JCSkip tree) {
1159 }
1160
1161 public void visitBlock(JCBlock tree) {
1162 /* this method is heavily invoked, as expected, for deeply nested blocks, if blocks doesn't happen to have
1163 * patterns there will be an unnecessary tax on memory consumption every time this method is executed, for this
1164 * reason we have created helper methods and here at a higher level we just discriminate depending on the
1165 * presence, or not, of patterns in a given block
1166 */
1167 if (tree.patternMatchingCatch != null) {
1168 visitBlockWithPatterns(tree);
1169 } else {
1170 internalVisitBlock(tree);
1171 }
1172 }
1173
1174 private void visitBlockWithPatterns(JCBlock tree) {
1175 PatternMatchingCatchConfiguration prevConfiguration = patternMatchingCatchConfiguration;
1176 try {
1177 patternMatchingCatchConfiguration =
1178 new PatternMatchingCatchConfiguration(tree.patternMatchingCatch.calls2Handle(),
1179 new ListBuffer<int[]>(),
1180 tree.patternMatchingCatch.handler(),
1181 code.state.dup());
1182 internalVisitBlock(tree);
1183 } finally {
1184 generatePatternMatchingCatch(env);
1185 patternMatchingCatchConfiguration = prevConfiguration;
1186 }
1187 }
1188
1189 private void generatePatternMatchingCatch(Env<GenContext> env) {
1190 if (patternMatchingCatchConfiguration.handler != null &&
1191 !patternMatchingCatchConfiguration.ranges.isEmpty()) {
1192 Chain skipCatch = code.branch(goto_);
1193 JCCatch handler = patternMatchingCatchConfiguration.handler();
1194 code.entryPoint(patternMatchingCatchConfiguration.startState(),
1195 handler.param.sym.type);
1196 genPatternMatchingCatch(handler,
1197 env,
1198 patternMatchingCatchConfiguration.ranges.toList());
1199 code.resolve(skipCatch);
1200 }
1201 }
1202
1203 private void internalVisitBlock(JCBlock tree) {
1204 int limit = code.nextreg;
1205 Env<GenContext> localEnv = env.dup(tree, new GenContext());
1206 genStats(tree.stats, localEnv);
1207 // End the scope of all block-local variables in variable info.
1208 if (!env.tree.hasTag(METHODDEF)) {
1209 code.statBegin(tree.bracePos);
1210 code.endScopes(limit);
1211 code.pendingStatPos = Position.NOPOS;
1212 }
1213 }
1214
1215 public void visitDoLoop(JCDoWhileLoop tree) {
1216 genLoop(tree, tree.body, tree.cond, List.nil(), false);
1217 }
1218
1219 public void visitWhileLoop(JCWhileLoop tree) {
1220 genLoop(tree, tree.body, tree.cond, List.nil(), true);
1221 }
1222
1223 public void visitForLoop(JCForLoop tree) {
1224 int limit = code.nextreg;
1225 genStats(tree.init, env);
1226 genLoop(tree, tree.body, tree.cond, tree.step, true);
1227 code.endScopes(limit);
1228 }
1229 //where
1230 /** Generate code for a loop.
1231 * @param loop The tree representing the loop.
1232 * @param body The loop's body.
1233 * @param cond The loop's controlling condition.
1234 * @param step "Step" statements to be inserted at end of
1235 * each iteration.
1236 * @param testFirst True if the loop test belongs before the body.
1237 */
1238 private void genLoop(JCStatement loop,
1239 JCStatement body,
1240 JCExpression cond,
1241 List<JCExpressionStatement> step,
1242 boolean testFirst) {
1243 genLoopHelper(loop, body, cond, step, testFirst);
1244 }
1245
1246 private void genLoopHelper(JCStatement loop,
1247 JCStatement body,
1248 JCExpression cond,
1249 List<JCExpressionStatement> step,
1250 boolean testFirst) {
1251 Env<GenContext> loopEnv = env.dup(loop, new GenContext());
1252 int startpc = code.entryPoint();
1253 if (testFirst) { //while or for loop
1254 CondItem c;
1255 if (cond != null) {
1256 code.statBegin(cond.pos);
1257 Assert.check(code.isStatementStart());
1258 c = genCond(TreeInfo.skipParens(cond), CRT_FLOW_CONTROLLER);
1259 } else {
1260 c = items.makeCondItem(goto_);
1261 }
1262 Chain loopDone = c.jumpFalse();
1263 code.resolve(c.trueJumps);
1264 Assert.check(code.isStatementStart());
1265 genStat(body, loopEnv, CRT_STATEMENT | CRT_FLOW_TARGET);
1266 code.resolve(loopEnv.info.cont);
1267 genStats(step, loopEnv);
1268 code.resolve(code.branch(goto_), startpc);
1269 code.resolve(loopDone);
1270 } else {
1271 genStat(body, loopEnv, CRT_STATEMENT | CRT_FLOW_TARGET);
1272 code.resolve(loopEnv.info.cont);
1273 genStats(step, loopEnv);
1274 if (code.isAlive()) {
1275 CondItem c;
1276 if (cond != null) {
1277 code.statBegin(cond.pos);
1278 Assert.check(code.isStatementStart());
1279 c = genCond(TreeInfo.skipParens(cond), CRT_FLOW_CONTROLLER);
1280 } else {
1281 c = items.makeCondItem(goto_);
1282 }
1283 code.resolve(c.jumpTrue(), startpc);
1284 Assert.check(code.isStatementStart());
1285 code.resolve(c.falseJumps);
1286 }
1287 }
1288 code.resolve(loopEnv.info.exit);
1289 }
1290
1291 public void visitForeachLoop(JCEnhancedForLoop tree) {
1292 throw new AssertionError(); // should have been removed by Lower.
1293 }
1294
1295 public void visitLabelled(JCLabeledStatement tree) {
1296 Env<GenContext> localEnv = env.dup(tree, new GenContext());
1297 genStat(tree.body, localEnv, CRT_STATEMENT);
1298 code.resolve(localEnv.info.exit);
1299 }
1300
1301 public void visitSwitch(JCSwitch tree) {
1302 handleSwitch(tree, tree.selector, tree.cases, tree.patternSwitch);
1303 }
1304
1305 @Override
1306 public void visitSwitchExpression(JCSwitchExpression tree) {
1307 code.resolvePending();
1308 boolean prevInCondSwitchExpression = inCondSwitchExpression;
1309 try {
1310 inCondSwitchExpression = false;
1311 doHandleSwitchExpression(tree);
1312 } finally {
1313 inCondSwitchExpression = prevInCondSwitchExpression;
1314 }
1315 result = items.makeStackItem(pt);
1316 }
1317
1318 private void doHandleSwitchExpression(JCSwitchExpression tree) {
1319 List<LocalItem> prevStackBeforeSwitchExpression = stackBeforeSwitchExpression;
1320 LocalItem prevSwitchResult = switchResult;
1321 int limit = code.nextreg;
1322 try {
1323 stackBeforeSwitchExpression = List.nil();
1324 switchResult = null;
1325 if (hasTry(tree)) {
1326 //if the switch expression contains try-catch, the catch handlers need to have
1327 //an empty stack. So stash whole stack to local variables, and restore it before
1328 //breaks:
1329 while (code.state.stacksize > 0) {
1330 Type type = code.state.peek();
1331 Name varName = names.fromString(target.syntheticNameChar() +
1332 "stack" +
1333 target.syntheticNameChar() +
1334 tree.pos +
1335 target.syntheticNameChar() +
1336 code.state.stacksize);
1337 VarSymbol var = new VarSymbol(Flags.SYNTHETIC, varName, type,
1338 this.env.enclMethod.sym);
1339 LocalItem item = items.new LocalItem(type, code.newLocal(var));
1340 stackBeforeSwitchExpression = stackBeforeSwitchExpression.prepend(item);
1341 item.store();
1342 }
1343 switchResult = makeTemp(tree.type);
1344 }
1345 int prevLetExprStart = code.setLetExprStackPos(code.state.stacksize);
1346 try {
1347 handleSwitch(tree, tree.selector, tree.cases, tree.patternSwitch);
1348 } finally {
1349 code.setLetExprStackPos(prevLetExprStart);
1350 }
1351 } finally {
1352 stackBeforeSwitchExpression = prevStackBeforeSwitchExpression;
1353 switchResult = prevSwitchResult;
1354 code.endScopes(limit);
1355 }
1356 }
1357 //where:
1358 private boolean hasTry(JCSwitchExpression tree) {
1359 class HasTryScanner extends TreeScanner {
1360 private boolean hasTry;
1361
1362 @Override
1363 public void visitTry(JCTry tree) {
1364 hasTry = true;
1365 }
1366
1367 @Override
1368 public void visitSynchronized(JCSynchronized tree) {
1369 hasTry = true;
1370 }
1371
1372 @Override
1373 public void visitClassDef(JCClassDecl tree) {
1374 }
1375
1376 @Override
1377 public void visitLambda(JCLambda tree) {
1378 }
1379 };
1380
1381 HasTryScanner hasTryScanner = new HasTryScanner();
1382
1383 hasTryScanner.scan(tree);
1384 return hasTryScanner.hasTry;
1385 }
1386
1387 private void handleSwitch(JCTree swtch, JCExpression selector, List<JCCase> cases,
1388 boolean patternSwitch) {
1389 handleSwitchHelper(swtch, selector, cases, patternSwitch);
1390 }
1391
1392 void handleSwitchHelper(JCTree swtch, JCExpression selector, List<JCCase> cases,
1393 boolean patternSwitch) {
1394 int limit = code.nextreg;
1395 Assert.check(!selector.type.hasTag(CLASS));
1396 int switchStart = patternSwitch ? code.entryPoint() : -1;
1397 int startpcCrt = genCrt ? code.curCP() : 0;
1398 Assert.check(code.isStatementStart());
1399 Item sel = genExpr(selector, syms.intType);
1400 if (cases.isEmpty()) {
1401 // We are seeing: switch <sel> {}
1402 sel.load().drop();
1403 if (genCrt)
1404 code.crt.put(TreeInfo.skipParens(selector),
1405 CRT_FLOW_CONTROLLER, startpcCrt, code.curCP());
1406 } else {
1407 // We are seeing a nonempty switch.
1408 sel.load();
1409 if (genCrt)
1410 code.crt.put(TreeInfo.skipParens(selector),
1411 CRT_FLOW_CONTROLLER, startpcCrt, code.curCP());
1412 Env<GenContext> switchEnv = env.dup(swtch, new GenContext());
1413 switchEnv.info.isSwitch = true;
1414
1415 // Compute number of labels and minimum and maximum label values.
1416 // For each case, store its label in an array.
1417 int lo = Integer.MAX_VALUE; // minimum label.
1418 int hi = Integer.MIN_VALUE; // maximum label.
1419 int nlabels = 0; // number of labels.
1420
1421 int[] labels = new int[cases.length()]; // the label array.
1422 int defaultIndex = -1; // the index of the default clause.
1423
1424 List<JCCase> l = cases;
1425 for (int i = 0; i < labels.length; i++) {
1426 if (l.head.labels.head instanceof JCConstantCaseLabel constLabel) {
1427 Assert.check(l.head.labels.size() == 1);
1428 int val = ((Number) constLabel.expr.type.constValue()).intValue();
1429 labels[i] = val;
1430 if (val < lo) lo = val;
1431 if (hi < val) hi = val;
1432 nlabels++;
1433 } else {
1434 Assert.check(defaultIndex == -1);
1435 defaultIndex = i;
1436 }
1437 l = l.tail;
1438 }
1439
1440 // Determine whether to issue a tableswitch or a lookupswitch
1441 // instruction.
1442 long table_space_cost = 4 + ((long) hi - lo + 1); // words
1443 long table_time_cost = 3; // comparisons
1444 long lookup_space_cost = 3 + 2 * (long) nlabels;
1445 long lookup_time_cost = nlabels;
1446 int opcode =
1447 nlabels > 0 &&
1448 table_space_cost + 3 * table_time_cost <=
1449 lookup_space_cost + 3 * lookup_time_cost
1450 ?
1451 tableswitch : lookupswitch;
1452
1453 int startpc = code.curCP(); // the position of the selector operation
1454 code.emitop0(opcode);
1455 code.align(4);
1456 int tableBase = code.curCP(); // the start of the jump table
1457 int[] offsets = null; // a table of offsets for a lookupswitch
1458 code.emit4(-1); // leave space for default offset
1459 if (opcode == tableswitch) {
1460 code.emit4(lo); // minimum label
1461 code.emit4(hi); // maximum label
1462 for (long i = lo; i <= hi; i++) { // leave space for jump table
1463 code.emit4(-1);
1464 }
1465 } else {
1466 code.emit4(nlabels); // number of labels
1467 for (int i = 0; i < nlabels; i++) {
1468 code.emit4(-1); code.emit4(-1); // leave space for lookup table
1469 }
1470 offsets = new int[labels.length];
1471 }
1472 Code.State stateSwitch = code.state.dup();
1473 code.markDead();
1474
1475 // For each case do:
1476 l = cases;
1477 for (int i = 0; i < labels.length; i++) {
1478 JCCase c = l.head;
1479 l = l.tail;
1480
1481 int pc = code.entryPoint(stateSwitch);
1482 // Insert offset directly into code or else into the
1483 // offsets table.
1484 if (i != defaultIndex) {
1485 if (opcode == tableswitch) {
1486 code.put4(
1487 tableBase + 4 * (labels[i] - lo + 3),
1488 pc - startpc);
1489 } else {
1490 offsets[i] = pc - startpc;
1491 }
1492 } else {
1493 code.put4(tableBase, pc - startpc);
1494 }
1495
1496 // Generate code for the statements in this case.
1497 genStats(c.stats, switchEnv, CRT_FLOW_TARGET);
1498 }
1499
1500 if (switchEnv.info.cont != null) {
1501 Assert.check(patternSwitch);
1502 code.resolve(switchEnv.info.cont, switchStart);
1503 }
1504
1505 // Resolve all breaks.
1506 code.resolve(switchEnv.info.exit);
1507
1508 // If we have not set the default offset, we do so now.
1509 if (code.get4(tableBase) == -1) {
1510 code.put4(tableBase, code.entryPoint(stateSwitch) - startpc);
1511 }
1512
1513 if (opcode == tableswitch) {
1514 // Let any unfilled slots point to the default case.
1515 int defaultOffset = code.get4(tableBase);
1516 for (long i = lo; i <= hi; i++) {
1517 int t = (int)(tableBase + 4 * (i - lo + 3));
1518 if (code.get4(t) == -1)
1519 code.put4(t, defaultOffset);
1520 }
1521 } else {
1522 // Sort non-default offsets and copy into lookup table.
1523 if (defaultIndex >= 0)
1524 for (int i = defaultIndex; i < labels.length - 1; i++) {
1525 labels[i] = labels[i+1];
1526 offsets[i] = offsets[i+1];
1527 }
1528 if (nlabels > 0)
1529 qsort2(labels, offsets, 0, nlabels - 1);
1530 for (int i = 0; i < nlabels; i++) {
1531 int caseidx = tableBase + 8 * (i + 1);
1532 code.put4(caseidx, labels[i]);
1533 code.put4(caseidx + 4, offsets[i]);
1534 }
1535 }
1536
1537 if (swtch instanceof JCSwitchExpression) {
1538 // Emit line position for the end of a switch expression
1539 code.statBegin(TreeInfo.endPos(swtch));
1540 }
1541 }
1542 code.endScopes(limit);
1543 }
1544 //where
1545 /** Sort (int) arrays of keys and values
1546 */
1547 static void qsort2(int[] keys, int[] values, int lo, int hi) {
1548 int i = lo;
1549 int j = hi;
1550 int pivot = keys[(i+j)/2];
1551 do {
1552 while (keys[i] < pivot) i++;
1553 while (pivot < keys[j]) j--;
1554 if (i <= j) {
1555 int temp1 = keys[i];
1556 keys[i] = keys[j];
1557 keys[j] = temp1;
1558 int temp2 = values[i];
1559 values[i] = values[j];
1560 values[j] = temp2;
1561 i++;
1562 j--;
1563 }
1564 } while (i <= j);
1565 if (lo < j) qsort2(keys, values, lo, j);
1566 if (i < hi) qsort2(keys, values, i, hi);
1567 }
1568
1569 public void visitSynchronized(JCSynchronized tree) {
1570 int limit = code.nextreg;
1571 // Generate code to evaluate lock and save in temporary variable.
1572 final LocalItem lockVar = makeTemp(syms.objectType);
1573 Assert.check(code.isStatementStart());
1574 genExpr(tree.lock, tree.lock.type).load().duplicate();
1575 lockVar.store();
1576
1577 // Generate code to enter monitor.
1578 code.emitop0(monitorenter);
1579 code.state.lock(lockVar.reg);
1580
1581 // Generate code for a try statement with given body, no catch clauses
1582 // in a new environment with the "exit-monitor" operation as finalizer.
1583 final Env<GenContext> syncEnv = env.dup(tree, new GenContext());
1584 syncEnv.info.finalize = new GenFinalizer() {
1585 void gen() {
1586 genLast();
1587 Assert.check(syncEnv.info.gaps.length() % 2 == 0);
1588 syncEnv.info.gaps.append(code.curCP());
1589 }
1590 void genLast() {
1591 if (code.isAlive()) {
1592 lockVar.load();
1593 code.emitop0(monitorexit);
1594 code.state.unlock(lockVar.reg);
1595 }
1596 }
1597 };
1598 syncEnv.info.gaps = new ListBuffer<>();
1599 genTry(tree.body, List.nil(), syncEnv);
1600 code.endScopes(limit);
1601 }
1602
1603 public void visitTry(final JCTry tree) {
1604 // Generate code for a try statement with given body and catch clauses,
1605 // in a new environment which calls the finally block if there is one.
1606 final Env<GenContext> tryEnv = env.dup(tree, new GenContext());
1607 final Env<GenContext> oldEnv = env;
1608 tryEnv.info.finalize = new GenFinalizer() {
1609 void gen() {
1610 Assert.check(tryEnv.info.gaps.length() % 2 == 0);
1611 tryEnv.info.gaps.append(code.curCP());
1612 genLast();
1613 }
1614 void genLast() {
1615 if (tree.finalizer != null)
1616 genStat(tree.finalizer, oldEnv, CRT_BLOCK);
1617 }
1618 boolean hasFinalizer() {
1619 return tree.finalizer != null;
1620 }
1621
1622 @Override
1623 void afterBody() {
1624 if (tree.finalizer != null && (tree.finalizer.flags & BODY_ONLY_FINALIZE) != 0) {
1625 //for body-only finally, remove the GenFinalizer after try body
1626 //so that the finally is not generated to catch bodies:
1627 tryEnv.info.finalize = null;
1628 }
1629 }
1630
1631 };
1632 tryEnv.info.gaps = new ListBuffer<>();
1633 genTry(tree.body, tree.catchers, tryEnv);
1634 }
1635 //where
1636 /** Generate code for a try or synchronized statement
1637 * @param body The body of the try or synchronized statement.
1638 * @param catchers The list of catch clauses.
1639 * @param env The current environment of the body.
1640 */
1641 void genTry(JCTree body, List<JCCatch> catchers, Env<GenContext> env) {
1642 genTryHelper(body, catchers, env);
1643 }
1644
1645 void genTryHelper(JCTree body, List<JCCatch> catchers, Env<GenContext> env) {
1646 int limit = code.nextreg;
1647 int startpc = code.curCP();
1648 Code.State stateTry = code.state.dup();
1649 genStat(body, env, CRT_BLOCK);
1650 int endpc = code.curCP();
1651 List<Integer> gaps = env.info.gaps.toList();
1652 code.statBegin(TreeInfo.endPos(body));
1653 genFinalizer(env);
1654 code.statBegin(TreeInfo.endPos(env.tree));
1655 Chain exitChain;
1656 boolean actualTry = env.tree.hasTag(TRY);
1657 if (startpc == endpc && actualTry) {
1658 exitChain = code.branch(dontgoto);
1659 } else {
1660 exitChain = code.branch(goto_);
1661 }
1662 endFinalizerGap(env);
1663 env.info.finalize.afterBody();
1664 boolean hasFinalizer =
1665 env.info.finalize != null &&
1666 env.info.finalize.hasFinalizer();
1667 if (startpc != endpc) for (List<JCCatch> l = catchers; l.nonEmpty(); l = l.tail) {
1668 // start off with exception on stack
1669 code.entryPoint(stateTry, l.head.param.sym.type);
1670 genCatch(l.head, env, startpc, endpc, gaps);
1671 genFinalizer(env);
1672 if (hasFinalizer || l.tail.nonEmpty()) {
1673 code.statBegin(TreeInfo.endPos(env.tree));
1674 exitChain = Code.mergeChains(exitChain,
1675 code.branch(goto_));
1676 }
1677 endFinalizerGap(env);
1678 }
1679 if (hasFinalizer && (startpc != endpc || !actualTry)) {
1680 // Create a new register segment to avoid allocating
1681 // the same variables in finalizers and other statements.
1682 code.newRegSegment();
1683
1684 // Add a catch-all clause.
1685
1686 // start off with exception on stack
1687 int catchallpc = code.entryPoint(stateTry, syms.throwableType);
1688
1689 // Register all exception ranges for catch all clause.
1690 // The range of the catch all clause is from the beginning
1691 // of the try or synchronized block until the present
1692 // code pointer excluding all gaps in the current
1693 // environment's GenContext.
1694 int startseg = startpc;
1695 while (env.info.gaps.nonEmpty()) {
1696 int endseg = env.info.gaps.next().intValue();
1697 registerCatch(body.pos(), startseg, endseg,
1698 catchallpc, 0);
1699 startseg = env.info.gaps.next().intValue();
1700 }
1701 code.statBegin(TreeInfo.finalizerPos(env.tree, PosKind.FIRST_STAT_POS));
1702 code.markStatBegin();
1703
1704 Item excVar = makeTemp(syms.throwableType);
1705 excVar.store();
1706 genFinalizer(env);
1707 code.resolvePending();
1708 code.statBegin(TreeInfo.finalizerPos(env.tree, PosKind.END_POS));
1709 code.markStatBegin();
1710
1711 excVar.load();
1712 registerCatch(body.pos(), startseg,
1713 env.info.gaps.next().intValue(),
1714 catchallpc, 0);
1715 code.emitop0(athrow);
1716 code.markDead();
1717
1718 // If there are jsr's to this finalizer, ...
1719 if (env.info.cont != null) {
1720 // Resolve all jsr's.
1721 code.resolve(env.info.cont);
1722
1723 // Mark statement line number
1724 code.statBegin(TreeInfo.finalizerPos(env.tree, PosKind.FIRST_STAT_POS));
1725 code.markStatBegin();
1726
1727 // Save return address.
1728 LocalItem retVar = makeTemp(syms.throwableType);
1729 retVar.store();
1730
1731 // Generate finalizer code.
1732 env.info.finalize.genLast();
1733
1734 // Return.
1735 code.emitop1w(ret, retVar.reg);
1736 code.markDead();
1737 }
1738 }
1739 // Resolve all breaks.
1740 code.resolve(exitChain);
1741
1742 code.endScopes(limit);
1743 }
1744
1745 /** Generate code for a catch clause.
1746 * @param tree The catch clause.
1747 * @param env The environment current in the enclosing try.
1748 * @param startpc Start pc of try-block.
1749 * @param endpc End pc of try-block.
1750 */
1751 void genCatch(JCCatch tree,
1752 Env<GenContext> env,
1753 int startpc, int endpc,
1754 List<Integer> gaps) {
1755 if (startpc != endpc) {
1756 List<Pair<List<Attribute.TypeCompound>, JCExpression>> catchTypeExprs
1757 = catchTypesWithAnnotations(tree);
1758 while (gaps.nonEmpty()) {
1759 for (Pair<List<Attribute.TypeCompound>, JCExpression> subCatch1 : catchTypeExprs) {
1760 JCExpression subCatch = subCatch1.snd;
1761 int catchType = makeRef(tree.pos(), subCatch.type);
1762 int end = gaps.head.intValue();
1763 registerCatch(tree.pos(),
1764 startpc, end, code.curCP(),
1765 catchType);
1766 for (Attribute.TypeCompound tc : subCatch1.fst) {
1767 tc.position.setCatchInfo(catchType, startpc);
1768 }
1769 }
1770 gaps = gaps.tail;
1771 startpc = gaps.head.intValue();
1772 gaps = gaps.tail;
1773 }
1774 if (startpc < endpc) {
1775 for (Pair<List<Attribute.TypeCompound>, JCExpression> subCatch1 : catchTypeExprs) {
1776 JCExpression subCatch = subCatch1.snd;
1777 int catchType = makeRef(tree.pos(), subCatch.type);
1778 registerCatch(tree.pos(),
1779 startpc, endpc, code.curCP(),
1780 catchType);
1781 for (Attribute.TypeCompound tc : subCatch1.fst) {
1782 tc.position.setCatchInfo(catchType, startpc);
1783 }
1784 }
1785 }
1786 genCatchBlock(tree, env);
1787 }
1788 }
1789 void genPatternMatchingCatch(JCCatch tree,
1790 Env<GenContext> env,
1791 List<int[]> ranges) {
1792 for (int[] range : ranges) {
1793 JCExpression subCatch = tree.param.vartype;
1794 int catchType = makeRef(tree.pos(), subCatch.type);
1795 registerCatch(tree.pos(),
1796 range[0], range[1], code.curCP(),
1797 catchType);
1798 }
1799 genCatchBlock(tree, env);
1800 }
1801 void genCatchBlock(JCCatch tree, Env<GenContext> env) {
1802 VarSymbol exparam = tree.param.sym;
1803 code.statBegin(tree.pos);
1804 code.markStatBegin();
1805 int limit = code.nextreg;
1806 code.newLocal(exparam);
1807 items.makeLocalItem(exparam).store();
1808 code.statBegin(TreeInfo.firstStatPos(tree.body));
1809 genStat(tree.body, env, CRT_BLOCK);
1810 code.endScopes(limit);
1811 code.statBegin(TreeInfo.endPos(tree.body));
1812 }
1813 // where
1814 List<Pair<List<Attribute.TypeCompound>, JCExpression>> catchTypesWithAnnotations(JCCatch tree) {
1815 return TreeInfo.isMultiCatch(tree) ?
1816 catchTypesWithAnnotationsFromMulticatch((JCTypeUnion)tree.param.vartype, tree.param.sym.getRawTypeAttributes()) :
1817 List.of(new Pair<>(tree.param.sym.getRawTypeAttributes(), tree.param.vartype));
1818 }
1819 // where
1820 List<Pair<List<Attribute.TypeCompound>, JCExpression>> catchTypesWithAnnotationsFromMulticatch(JCTypeUnion tree, List<TypeCompound> first) {
1821 List<JCExpression> alts = tree.alternatives;
1822 List<Pair<List<TypeCompound>, JCExpression>> res = List.of(new Pair<>(first, alts.head));
1823 alts = alts.tail;
1824
1825 while(alts != null && alts.head != null) {
1826 JCExpression alt = alts.head;
1827 if (alt instanceof JCAnnotatedType annotatedType) {
1828 res = res.prepend(new Pair<>(annotate.fromAnnotations(annotatedType.annotations), alt));
1829 } else {
1830 res = res.prepend(new Pair<>(List.nil(), alt));
1831 }
1832 alts = alts.tail;
1833 }
1834 return res.reverse();
1835 }
1836
1837 /** Register a catch clause in the "Exceptions" code-attribute.
1838 */
1839 void registerCatch(DiagnosticPosition pos,
1840 int startpc, int endpc,
1841 int handler_pc, int catch_type) {
1842 char startpc1 = (char)startpc;
1843 char endpc1 = (char)endpc;
1844 char handler_pc1 = (char)handler_pc;
1845 if (startpc1 == startpc &&
1846 endpc1 == endpc &&
1847 handler_pc1 == handler_pc) {
1848 code.addCatch(startpc1, endpc1, handler_pc1,
1849 (char)catch_type);
1850 } else {
1851 log.error(pos, Errors.LimitCodeTooLargeForTryStmt);
1852 nerrs++;
1853 }
1854 }
1855
1856 public void visitIf(JCIf tree) {
1857 visitIfHelper(tree);
1858 }
1859
1860 public void visitIfHelper(JCIf tree) {
1861 int limit = code.nextreg;
1862 Chain thenExit = null;
1863 Assert.check(code.isStatementStart());
1864 CondItem c = genCond(TreeInfo.skipParens(tree.cond),
1865 CRT_FLOW_CONTROLLER);
1866 Chain elseChain = c.jumpFalse();
1867 Assert.check(code.isStatementStart());
1868 if (!c.isFalse()) {
1869 code.resolve(c.trueJumps);
1870 genStat(tree.thenpart, env, CRT_STATEMENT | CRT_FLOW_TARGET);
1871 thenExit = code.branch(goto_);
1872 }
1873 if (elseChain != null) {
1874 code.resolve(elseChain);
1875 if (tree.elsepart != null) {
1876 genStat(tree.elsepart, env,CRT_STATEMENT | CRT_FLOW_TARGET);
1877 }
1878 }
1879 code.resolve(thenExit);
1880 code.endScopes(limit);
1881 Assert.check(code.isStatementStart());
1882 }
1883
1884 public void visitExec(JCExpressionStatement tree) {
1885 // Optimize x++ to ++x and x-- to --x.
1886 JCExpression e = tree.expr;
1887 switch (e.getTag()) {
1888 case POSTINC:
1889 ((JCUnary) e).setTag(PREINC);
1890 break;
1891 case POSTDEC:
1892 ((JCUnary) e).setTag(PREDEC);
1893 break;
1894 }
1895 Assert.check(code.isStatementStart());
1896 genExpr(tree.expr, tree.expr.type).drop();
1897 Assert.check(code.isStatementStart());
1898 }
1899
1900 public void visitBreak(JCBreak tree) {
1901 Assert.check(code.isStatementStart());
1902 final Env<GenContext> targetEnv = unwindBreak(tree.target);
1903 targetEnv.info.addExit(code.branch(goto_));
1904 endFinalizerGaps(env, targetEnv);
1905 }
1906
1907 public void visitYield(JCYield tree) {
1908 Assert.check(code.isStatementStart());
1909 final Env<GenContext> targetEnv;
1910 if (inCondSwitchExpression) {
1911 CondItem value = genCond(tree.value, CRT_FLOW_TARGET);
1912 Chain falseJumps = value.jumpFalse();
1913
1914 code.resolve(value.trueJumps);
1915 Env<GenContext> localEnv = unwindBreak(tree.target);
1916 reloadStackBeforeSwitchExpr();
1917 Chain trueJumps = code.branch(goto_);
1918
1919 endFinalizerGaps(env, localEnv);
1920
1921 code.resolve(falseJumps);
1922 targetEnv = unwindBreak(tree.target);
1923 reloadStackBeforeSwitchExpr();
1924 falseJumps = code.branch(goto_);
1925
1926 if (switchExpressionTrueChain == null) {
1927 switchExpressionTrueChain = trueJumps;
1928 } else {
1929 switchExpressionTrueChain =
1930 Code.mergeChains(switchExpressionTrueChain, trueJumps);
1931 }
1932 if (switchExpressionFalseChain == null) {
1933 switchExpressionFalseChain = falseJumps;
1934 } else {
1935 switchExpressionFalseChain =
1936 Code.mergeChains(switchExpressionFalseChain, falseJumps);
1937 }
1938 } else {
1939 genExpr(tree.value, pt).load();
1940 if (switchResult != null)
1941 switchResult.store();
1942
1943 targetEnv = unwindBreak(tree.target);
1944
1945 if (code.isAlive()) {
1946 reloadStackBeforeSwitchExpr();
1947 if (switchResult != null)
1948 switchResult.load();
1949
1950 targetEnv.info.addExit(code.branch(goto_));
1951 code.markDead();
1952 }
1953 }
1954 endFinalizerGaps(env, targetEnv);
1955 }
1956 //where:
1957 /** As side-effect, might mark code as dead disabling any further emission.
1958 */
1959 private Env<GenContext> unwindBreak(JCTree target) {
1960 int tmpPos = code.pendingStatPos;
1961 Env<GenContext> targetEnv = unwind(target, env);
1962 code.pendingStatPos = tmpPos;
1963 return targetEnv;
1964 }
1965
1966 private void reloadStackBeforeSwitchExpr() {
1967 for (LocalItem li : stackBeforeSwitchExpression)
1968 li.load();
1969 }
1970
1971 public void visitContinue(JCContinue tree) {
1972 int tmpPos = code.pendingStatPos;
1973 Env<GenContext> targetEnv = unwind(tree.target, env);
1974 code.pendingStatPos = tmpPos;
1975 Assert.check(code.isStatementStart());
1976 targetEnv.info.addCont(code.branch(goto_));
1977 endFinalizerGaps(env, targetEnv);
1978 }
1979
1980 public void visitReturn(JCReturn tree) {
1981 int limit = code.nextreg;
1982 final Env<GenContext> targetEnv;
1983
1984 /* Save and then restore the location of the return in case a finally
1985 * is expanded (with unwind()) in the middle of our bytecodes.
1986 */
1987 int tmpPos = code.pendingStatPos;
1988 if (tree.expr != null) {
1989 Assert.check(code.isStatementStart());
1990 Item r = genExpr(tree.expr, pt).load();
1991 if (hasFinally(env.enclMethod, env)) {
1992 r = makeTemp(pt);
1993 r.store();
1994 }
1995 targetEnv = unwind(env.enclMethod, env);
1996 code.pendingStatPos = tmpPos;
1997 r.load();
1998 code.emitop0(ireturn + Code.truncate(Code.typecode(pt)));
1999 } else {
2000 targetEnv = unwind(env.enclMethod, env);
2001 code.pendingStatPos = tmpPos;
2002 code.emitop0(return_);
2003 }
2004 endFinalizerGaps(env, targetEnv);
2005 code.endScopes(limit);
2006 }
2007
2008 public void visitThrow(JCThrow tree) {
2009 Assert.check(code.isStatementStart());
2010 genExpr(tree.expr, tree.expr.type).load();
2011 code.emitop0(athrow);
2012 Assert.check(code.isStatementStart());
2013 }
2014
2015 /* ************************************************************************
2016 * Visitor methods for expressions
2017 *************************************************************************/
2018
2019 public void visitApply(JCMethodInvocation tree) {
2020 setTypeAnnotationPositions(tree.pos);
2021 // Generate code for method.
2022 Item m = genExpr(tree.meth, methodType);
2023 // Generate code for all arguments, where the expected types are
2024 // the parameters of the method's external type (that is, any implicit
2025 // outer instance of a super(...) call appears as first parameter).
2026 MethodSymbol msym = (MethodSymbol)TreeInfo.symbol(tree.meth);
2027 genArgs(tree.args,
2028 msym.externalType(types).getParameterTypes());
2029 if (!msym.isDynamic()) {
2030 code.statBegin(tree.pos);
2031 }
2032 if (patternMatchingCatchConfiguration.invocations().contains(tree)) {
2033 int start = code.curCP();
2034 result = m.invoke();
2035 patternMatchingCatchConfiguration.ranges().add(new int[] {start, code.curCP()});
2036 } else {
2037 if (msym.isConstructor() && TreeInfo.isConstructorCall(tree)) {
2038 //if this is a this(...) or super(...) call, there is a pending
2039 //"uninitialized this" before this call. One catch handler cannot
2040 //handle exceptions that may come from places with "uninitialized this"
2041 //and (initialized) this, hence generate one set of handlers here
2042 //for the "uninitialized this" case, and another set of handlers
2043 //will be generated at the end of the method for the initialized this,
2044 //if needed:
2045 generatePatternMatchingCatch(env);
2046 result = m.invoke();
2047 patternMatchingCatchConfiguration =
2048 patternMatchingCatchConfiguration.restart(code.state.dup());
2049 } else {
2050 result = m.invoke();
2051 }
2052 }
2053 }
2054
2055 public void visitConditional(JCConditional tree) {
2056 Chain thenExit = null;
2057 code.statBegin(tree.cond.pos);
2058 CondItem c = genCond(tree.cond, CRT_FLOW_CONTROLLER);
2059 Chain elseChain = c.jumpFalse();
2060 if (!c.isFalse()) {
2061 code.resolve(c.trueJumps);
2062 int startpc = genCrt ? code.curCP() : 0;
2063 code.statBegin(tree.truepart.pos);
2064 genExpr(tree.truepart, pt).load();
2065 if (genCrt) code.crt.put(tree.truepart, CRT_FLOW_TARGET,
2066 startpc, code.curCP());
2067 thenExit = code.branch(goto_);
2068 }
2069 if (elseChain != null) {
2070 code.resolve(elseChain);
2071 int startpc = genCrt ? code.curCP() : 0;
2072 code.statBegin(tree.falsepart.pos);
2073 genExpr(tree.falsepart, pt).load();
2074 if (genCrt) code.crt.put(tree.falsepart, CRT_FLOW_TARGET,
2075 startpc, code.curCP());
2076 }
2077 code.resolve(thenExit);
2078 result = items.makeStackItem(pt);
2079 }
2080
2081 private void setTypeAnnotationPositions(int treePos) {
2082 MethodSymbol meth = code.meth;
2083 boolean initOrClinit = code.meth.getKind() == javax.lang.model.element.ElementKind.CONSTRUCTOR
2084 || code.meth.getKind() == javax.lang.model.element.ElementKind.STATIC_INIT;
2085
2086 for (Attribute.TypeCompound ta : meth.getRawTypeAttributes()) {
2087 if (ta.hasUnknownPosition())
2088 ta.tryFixPosition();
2089
2090 if (ta.position.matchesPos(treePos))
2091 ta.position.updatePosOffset(code.cp);
2092 }
2093
2094 if (!initOrClinit)
2095 return;
2096
2097 for (Attribute.TypeCompound ta : meth.owner.getRawTypeAttributes()) {
2098 if (ta.hasUnknownPosition())
2099 ta.tryFixPosition();
2100
2101 if (ta.position.matchesPos(treePos))
2102 ta.position.updatePosOffset(code.cp);
2103 }
2104
2105 ClassSymbol clazz = meth.enclClass();
2106 for (Symbol s : new com.sun.tools.javac.model.FilteredMemberList(clazz.members())) {
2107 if (!s.getKind().isField())
2108 continue;
2109
2110 for (Attribute.TypeCompound ta : s.getRawTypeAttributes()) {
2111 if (ta.hasUnknownPosition())
2112 ta.tryFixPosition();
2113
2114 if (ta.position.matchesPos(treePos))
2115 ta.position.updatePosOffset(code.cp);
2116 }
2117 }
2118 }
2119
2120 public void visitNewClass(JCNewClass tree) {
2121 // Enclosing instances or anonymous classes should have been eliminated
2122 // by now.
2123 Assert.check(tree.encl == null && tree.def == null);
2124 setTypeAnnotationPositions(tree.pos);
2125
2126 code.emitop2(new_, checkDimension(tree.pos(), tree.type), PoolWriter::putClass);
2127 code.emitop0(dup);
2128
2129 // Generate code for all arguments, where the expected types are
2130 // the parameters of the constructor's external type (that is,
2131 // any implicit outer instance appears as first parameter).
2132 genArgs(tree.args, tree.constructor.externalType(types).getParameterTypes());
2133
2134 items.makeMemberItem(tree.constructor, true).invoke();
2135 result = items.makeStackItem(tree.type);
2136 }
2137
2138 public void visitNewArray(JCNewArray tree) {
2139 setTypeAnnotationPositions(tree.pos);
2140
2141 if (tree.elems != null) {
2142 Type elemtype = types.elemtype(tree.type);
2143 loadIntConst(tree.elems.length());
2144 Item arr = makeNewArray(tree.pos(), tree.type, 1);
2145 int i = 0;
2146 for (List<JCExpression> l = tree.elems; l.nonEmpty(); l = l.tail) {
2147 arr.duplicate();
2148 loadIntConst(i);
2149 i++;
2150 genExpr(l.head, elemtype).load();
2151 items.makeIndexedItem(elemtype).store();
2152 }
2153 result = arr;
2154 } else {
2155 for (List<JCExpression> l = tree.dims; l.nonEmpty(); l = l.tail) {
2156 genExpr(l.head, syms.intType).load();
2157 }
2158 result = makeNewArray(tree.pos(), tree.type, tree.dims.length());
2159 }
2160 }
2161 //where
2162 /** Generate code to create an array with given element type and number
2163 * of dimensions.
2164 */
2165 Item makeNewArray(DiagnosticPosition pos, Type type, int ndims) {
2166 Type elemtype = types.elemtype(type);
2167 if (types.dimensions(type) > ClassFile.MAX_DIMENSIONS) {
2168 log.error(pos, Errors.LimitDimensions);
2169 nerrs++;
2170 }
2171 int elemcode = Code.arraycode(elemtype);
2172 if (elemcode == 0 || (elemcode == 1 && ndims == 1)) {
2173 code.emitAnewarray(makeRef(pos, elemtype), type);
2174 } else if (elemcode == 1) {
2175 code.emitMultianewarray(ndims, makeRef(pos, type), type);
2176 } else {
2177 code.emitNewarray(elemcode, type);
2178 }
2179 return items.makeStackItem(type);
2180 }
2181
2182 public void visitParens(JCParens tree) {
2183 result = genExpr(tree.expr, tree.expr.type);
2184 }
2185
2186 public void visitAssign(JCAssign tree) {
2187 Item l = genExpr(tree.lhs, tree.lhs.type);
2188 genExpr(tree.rhs, tree.lhs.type).load();
2189 if (tree.rhs.type.hasTag(BOT)) {
2190 /* This is just a case of widening reference conversion that per 5.1.5 simply calls
2191 for "regarding a reference as having some other type in a manner that can be proved
2192 correct at compile time."
2193 */
2194 code.state.forceStackTop(tree.lhs.type);
2195 }
2196 result = items.makeAssignItem(l);
2197 }
2198
2199 public void visitAssignop(JCAssignOp tree) {
2200 OperatorSymbol operator = tree.operator;
2201 Item l;
2202 if (operator.opcode == string_add) {
2203 l = concat.makeConcat(tree);
2204 } else {
2205 // Generate code for first expression
2206 l = genExpr(tree.lhs, tree.lhs.type);
2207
2208 // If we have an increment of -32768 to +32767 of a local
2209 // int variable we can use an incr instruction instead of
2210 // proceeding further.
2211 if ((tree.hasTag(PLUS_ASG) || tree.hasTag(MINUS_ASG)) &&
2212 l instanceof LocalItem localItem &&
2213 tree.lhs.type.getTag().isSubRangeOf(INT) &&
2214 tree.rhs.type.getTag().isSubRangeOf(INT) &&
2215 tree.rhs.type.constValue() != null) {
2216 int ival = ((Number) tree.rhs.type.constValue()).intValue();
2217 if (tree.hasTag(MINUS_ASG)) ival = -ival;
2218 localItem.incr(ival);
2219 result = l;
2220 return;
2221 }
2222 // Otherwise, duplicate expression, load one copy
2223 // and complete binary operation.
2224 l.duplicate();
2225 l.coerce(operator.type.getParameterTypes().head).load();
2226 completeBinop(tree.lhs, tree.rhs, operator).coerce(tree.lhs.type);
2227 }
2228 result = items.makeAssignItem(l);
2229 }
2230
2231 public void visitUnary(JCUnary tree) {
2232 OperatorSymbol operator = tree.operator;
2233 if (tree.hasTag(NOT)) {
2234 CondItem od = genCond(tree.arg, false);
2235 result = od.negate();
2236 } else {
2237 Item od = genExpr(tree.arg, operator.type.getParameterTypes().head);
2238 switch (tree.getTag()) {
2239 case POS:
2240 result = od.load();
2241 break;
2242 case NEG:
2243 result = od.load();
2244 code.emitop0(operator.opcode);
2245 break;
2246 case COMPL:
2247 result = od.load();
2248 emitMinusOne(od.typecode);
2249 code.emitop0(operator.opcode);
2250 break;
2251 case PREINC: case PREDEC:
2252 od.duplicate();
2253 if (od instanceof LocalItem localItem &&
2254 (operator.opcode == iadd || operator.opcode == isub)) {
2255 localItem.incr(tree.hasTag(PREINC) ? 1 : -1);
2256 result = od;
2257 } else {
2258 od.load();
2259 code.emitop0(one(od.typecode));
2260 code.emitop0(operator.opcode);
2261 // Perform narrowing primitive conversion if byte,
2262 // char, or short. Fix for 4304655.
2263 if (od.typecode != INTcode &&
2264 Code.truncate(od.typecode) == INTcode)
2265 code.emitop0(int2byte + od.typecode - BYTEcode);
2266 result = items.makeAssignItem(od);
2267 }
2268 break;
2269 case POSTINC: case POSTDEC:
2270 od.duplicate();
2271 if (od instanceof LocalItem localItem &&
2272 (operator.opcode == iadd || operator.opcode == isub)) {
2273 Item res = od.load();
2274 localItem.incr(tree.hasTag(POSTINC) ? 1 : -1);
2275 result = res;
2276 } else {
2277 Item res = od.load();
2278 od.stash(od.typecode);
2279 code.emitop0(one(od.typecode));
2280 code.emitop0(operator.opcode);
2281 // Perform narrowing primitive conversion if byte,
2282 // char, or short. Fix for 4304655.
2283 if (od.typecode != INTcode &&
2284 Code.truncate(od.typecode) == INTcode)
2285 code.emitop0(int2byte + od.typecode - BYTEcode);
2286 od.store();
2287 result = res;
2288 }
2289 break;
2290 case NULLCHK:
2291 result = od.load();
2292 code.emitop0(dup);
2293 genNullCheck(tree);
2294 break;
2295 default:
2296 Assert.error();
2297 }
2298 }
2299 }
2300
2301 /** Generate a null check from the object value at stack top. */
2302 private void genNullCheck(JCTree tree) {
2303 code.statBegin(tree.pos);
2304 callMethod(tree.pos(), syms.objectsType, names.requireNonNull,
2305 List.of(syms.objectType), true);
2306 code.emitop0(pop);
2307 }
2308
2309 public void visitBinary(JCBinary tree) {
2310 OperatorSymbol operator = tree.operator;
2311 if (operator.opcode == string_add) {
2312 result = concat.makeConcat(tree);
2313 } else if (tree.hasTag(AND)) {
2314 CondItem lcond = genCond(tree.lhs, CRT_FLOW_CONTROLLER);
2315 if (!lcond.isFalse()) {
2316 Chain falseJumps = lcond.jumpFalse();
2317 code.resolve(lcond.trueJumps);
2318 CondItem rcond = genCond(tree.rhs, CRT_FLOW_TARGET);
2319 result = items.
2320 makeCondItem(rcond.opcode,
2321 rcond.trueJumps,
2322 Code.mergeChains(falseJumps,
2323 rcond.falseJumps));
2324 } else {
2325 result = lcond;
2326 }
2327 } else if (tree.hasTag(OR)) {
2328 CondItem lcond = genCond(tree.lhs, CRT_FLOW_CONTROLLER);
2329 if (!lcond.isTrue()) {
2330 Chain trueJumps = lcond.jumpTrue();
2331 code.resolve(lcond.falseJumps);
2332 CondItem rcond = genCond(tree.rhs, CRT_FLOW_TARGET);
2333 result = items.
2334 makeCondItem(rcond.opcode,
2335 Code.mergeChains(trueJumps, rcond.trueJumps),
2336 rcond.falseJumps);
2337 } else {
2338 result = lcond;
2339 }
2340 } else {
2341 Item od = genExpr(tree.lhs, operator.type.getParameterTypes().head);
2342 od.load();
2343 result = completeBinop(tree.lhs, tree.rhs, operator);
2344 }
2345 }
2346
2347
2348 /** Complete generating code for operation, with left operand
2349 * already on stack.
2350 * @param lhs The tree representing the left operand.
2351 * @param rhs The tree representing the right operand.
2352 * @param operator The operator symbol.
2353 */
2354 Item completeBinop(JCTree lhs, JCTree rhs, OperatorSymbol operator) {
2355 MethodType optype = (MethodType)operator.type;
2356 int opcode = operator.opcode;
2357 if (opcode >= if_icmpeq && opcode <= if_icmple &&
2358 rhs.type.constValue() instanceof Number number &&
2359 number.intValue() == 0) {
2360 opcode = opcode + (ifeq - if_icmpeq);
2361 } else if (opcode >= if_acmpeq && opcode <= if_acmpne &&
2362 TreeInfo.isNull(rhs)) {
2363 opcode = opcode + (if_acmp_null - if_acmpeq);
2364 } else {
2365 // The expected type of the right operand is
2366 // the second parameter type of the operator, except for
2367 // shifts with long shiftcount, where we convert the opcode
2368 // to a short shift and the expected type to int.
2369 Type rtype = operator.erasure(types).getParameterTypes().tail.head;
2370 if (opcode >= ishll && opcode <= lushrl) {
2371 opcode = opcode + (ishl - ishll);
2372 rtype = syms.intType;
2373 }
2374 // Generate code for right operand and load.
2375 genExpr(rhs, rtype).load();
2376 // If there are two consecutive opcode instructions,
2377 // emit the first now.
2378 if (opcode >= (1 << preShift)) {
2379 code.emitop0(opcode >> preShift);
2380 opcode = opcode & 0xFF;
2381 }
2382 }
2383 if (opcode >= ifeq && opcode <= if_acmpne ||
2384 opcode == if_acmp_null || opcode == if_acmp_nonnull) {
2385 return items.makeCondItem(opcode);
2386 } else {
2387 code.emitop0(opcode);
2388 return items.makeStackItem(optype.restype);
2389 }
2390 }
2391
2392 public void visitTypeCast(JCTypeCast tree) {
2393 result = genExpr(tree.expr, tree.clazz.type).load();
2394 setTypeAnnotationPositions(tree.pos);
2395 // Additional code is only needed if we cast to a reference type
2396 // which is not statically a supertype of the expression's type.
2397 // For basic types, the coerce(...) in genExpr(...) will do
2398 // the conversion.
2399 if (!tree.clazz.type.isPrimitive() &&
2400 !types.isSameType(tree.expr.type, tree.clazz.type) &&
2401 types.asSuper(tree.expr.type, tree.clazz.type.tsym) == null) {
2402 code.emitop2(checkcast, checkDimension(tree.pos(), tree.clazz.type), PoolWriter::putClass);
2403 }
2404 }
2405
2406 public void visitWildcard(JCWildcard tree) {
2407 throw new AssertionError(this.getClass().getName());
2408 }
2409
2410 public void visitTypeTest(JCInstanceOf tree) {
2411 genExpr(tree.expr, tree.expr.type).load();
2412 setTypeAnnotationPositions(tree.pos);
2413 code.emitop2(instanceof_, makeRef(tree.pos(), tree.pattern.type));
2414 result = items.makeStackItem(syms.booleanType);
2415 }
2416
2417 public void visitIndexed(JCArrayAccess tree) {
2418 genExpr(tree.indexed, tree.indexed.type).load();
2419 genExpr(tree.index, syms.intType).load();
2420 result = items.makeIndexedItem(tree.type);
2421 }
2422
2423 public void visitIdent(JCIdent tree) {
2424 Symbol sym = tree.sym;
2425 if (tree.name == names._this || tree.name == names._super) {
2426 Item res = tree.name == names._this
2427 ? items.makeThisItem()
2428 : items.makeSuperItem();
2429 if (sym.kind == MTH) {
2430 // Generate code to address the constructor.
2431 res.load();
2432 res = items.makeMemberItem(sym, true);
2433 }
2434 result = res;
2435 } else if (isInvokeDynamic(sym) || isConstantDynamic(sym)) {
2436 if (isConstantDynamic(sym)) {
2437 setTypeAnnotationPositions(tree.pos);
2438 }
2439 result = items.makeDynamicItem(sym);
2440 } else if (sym.kind == VAR && (sym.owner.kind == MTH || sym.owner.kind == VAR)) {
2441 result = items.makeLocalItem((VarSymbol)sym);
2442 } else if ((sym.flags() & STATIC) != 0) {
2443 if (!isAccessSuper(env.enclMethod))
2444 sym = binaryQualifier(sym, env.enclClass.type);
2445 result = items.makeStaticItem(sym);
2446 } else {
2447 items.makeThisItem().load();
2448 sym = binaryQualifier(sym, env.enclClass.type);
2449 result = items.makeMemberItem(sym, nonVirtualForPrivateAccess(sym));
2450 }
2451 }
2452
2453 //where
2454 private boolean nonVirtualForPrivateAccess(Symbol sym) {
2455 boolean useVirtual = target.hasVirtualPrivateInvoke() &&
2456 !disableVirtualizedPrivateInvoke;
2457 return !useVirtual && ((sym.flags() & PRIVATE) != 0);
2458 }
2459
2460 public void visitSelect(JCFieldAccess tree) {
2461 Symbol sym = tree.sym;
2462
2463 if (tree.name == names._class) {
2464 code.emitLdc((LoadableConstant)checkDimension(tree.pos(), tree.selected.type));
2465 result = items.makeStackItem(pt);
2466 return;
2467 }
2468
2469 Symbol ssym = TreeInfo.symbol(tree.selected);
2470
2471 // Are we selecting via super?
2472 boolean selectSuper =
2473 ssym != null && (ssym.kind == TYP || ssym.name == names._super);
2474
2475 // Are we accessing a member of the superclass in an access method
2476 // resulting from a qualified super?
2477 boolean accessSuper = isAccessSuper(env.enclMethod);
2478
2479 Item base = (selectSuper)
2480 ? items.makeSuperItem()
2481 : genExpr(tree.selected, tree.selected.type);
2482
2483 if (sym.kind == VAR && ((VarSymbol) sym).getConstValue() != null) {
2484 // We are seeing a variable that is constant but its selecting
2485 // expression is not.
2486 if ((sym.flags() & STATIC) != 0) {
2487 if (!selectSuper && (ssym == null || ssym.kind != TYP))
2488 base = base.load();
2489 base.drop();
2490 } else {
2491 base.load();
2492 genNullCheck(tree.selected);
2493 }
2494 result = items.
2495 makeImmediateItem(sym.type, ((VarSymbol) sym).getConstValue());
2496 } else {
2497 if (isInvokeDynamic(sym)) {
2498 result = items.makeDynamicItem(sym);
2499 return;
2500 } else {
2501 sym = binaryQualifier(sym, tree.selected.type);
2502 }
2503 if ((sym.flags() & STATIC) != 0) {
2504 if (!selectSuper && (ssym == null || ssym.kind != TYP))
2505 base = base.load();
2506 base.drop();
2507 result = items.makeStaticItem(sym);
2508 } else {
2509 base.load();
2510 if (sym == syms.lengthVar) {
2511 code.emitop0(arraylength);
2512 result = items.makeStackItem(syms.intType);
2513 } else {
2514 result = items.
2515 makeMemberItem(sym,
2516 nonVirtualForPrivateAccess(sym) ||
2517 selectSuper || accessSuper);
2518 }
2519 }
2520 }
2521 }
2522
2523 public boolean isInvokeDynamic(Symbol sym) {
2524 return sym.kind == MTH && ((MethodSymbol)sym).isDynamic();
2525 }
2526
2527 public void visitLiteral(JCLiteral tree) {
2528 if (tree.type.hasTag(BOT)) {
2529 code.emitop0(aconst_null);
2530 result = items.makeStackItem(tree.type);
2531 }
2532 else
2533 result = items.makeImmediateItem(tree.type, tree.value);
2534 }
2535
2536 public void visitLetExpr(LetExpr tree) {
2537 code.resolvePending();
2538
2539 if (tree.needsLineNumberTableEntry) {
2540 code.statBegin(tree.pos);
2541 }
2542
2543 int limit = code.nextreg;
2544 int prevLetExprStart = code.setLetExprStackPos(code.state.stacksize);
2545 try {
2546 genStats(tree.defs, env);
2547 } finally {
2548 code.setLetExprStackPos(prevLetExprStart);
2549 }
2550 result = genExpr(tree.expr, tree.expr.type).load();
2551 code.endScopes(limit);
2552 }
2553
2554 private void generateReferencesToPrunedTree(ClassSymbol classSymbol) {
2555 List<JCTree> prunedInfo = lower.prunedTree.get(classSymbol);
2556 if (prunedInfo != null) {
2557 for (JCTree prunedTree: prunedInfo) {
2558 prunedTree.accept(classReferenceVisitor);
2559 }
2560 }
2561 }
2562
2563 /* ************************************************************************
2564 * main method
2565 *************************************************************************/
2566
2567 /** Generate code for a class definition.
2568 * @param env The attribution environment that belongs to the
2569 * outermost class containing this class definition.
2570 * We need this for resolving some additional symbols.
2571 * @param cdef The tree representing the class definition.
2572 * @return True if code is generated with no errors.
2573 */
2574 public boolean genClass(Env<AttrContext> env, JCClassDecl cdef) {
2575 try {
2576 attrEnv = env;
2577 ClassSymbol c = cdef.sym;
2578 this.toplevel = env.toplevel;
2579 /* method normalizeDefs() can add references to external classes into the constant pool
2580 */
2581 cdef.defs = normalizeDefs(cdef);
2582 generateReferencesToPrunedTree(c);
2583 Env<GenContext> localEnv = new Env<>(cdef, new GenContext());
2584 localEnv.toplevel = env.toplevel;
2585 localEnv.enclClass = cdef;
2586
2587 for (List<JCTree> l = cdef.defs; l.nonEmpty(); l = l.tail) {
2588 genDef(l.head, localEnv);
2589 }
2590 if (poolWriter.size() > PoolWriter.MAX_ENTRIES) {
2591 log.error(cdef.pos(), Errors.LimitPool);
2592 nerrs++;
2593 }
2594 if (nerrs != 0) {
2595 // if errors, discard code
2596 for (List<JCTree> l = cdef.defs; l.nonEmpty(); l = l.tail) {
2597 if (l.head.hasTag(METHODDEF))
2598 ((JCMethodDecl) l.head).sym.code = null;
2599 }
2600 }
2601 cdef.defs = List.nil(); // discard trees
2602 localProxyVarsGen.classGenerated(c);
2603 return nerrs == 0;
2604 } finally {
2605 // note: this method does NOT support recursion.
2606 attrEnv = null;
2607 this.env = null;
2608 toplevel = null;
2609 nerrs = 0;
2610 qualifiedSymbolCache.clear();
2611 }
2612 }
2613
2614 /* ************************************************************************
2615 * Auxiliary classes
2616 *************************************************************************/
2617
2618 /** An abstract class for finalizer generation.
2619 */
2620 abstract class GenFinalizer {
2621 /** Generate code to clean up when unwinding. */
2622 abstract void gen();
2623
2624 /** Generate code to clean up at last. */
2625 abstract void genLast();
2626
2627 /** Does this finalizer have some nontrivial cleanup to perform? */
2628 boolean hasFinalizer() { return true; }
2629
2630 /** Should be invoked after the try's body has been visited. */
2631 void afterBody() {}
2632 }
2633
2634 /** code generation contexts,
2635 * to be used as type parameter for environments.
2636 */
2637 final class GenContext {
2638
2639 /**
2640 * The top defined local variables for exit or continue branches to merge into.
2641 * It may contain uninitialized variables to be initialized by branched code,
2642 * so we cannot use Code.State.defined bits.
2643 */
2644 final int limit;
2645
2646 /** A chain for all unresolved jumps that exit the current environment.
2647 */
2648 Chain exit = null;
2649
2650 /** A chain for all unresolved jumps that continue in the
2651 * current environment.
2652 */
2653 Chain cont = null;
2654
2655 /** A closure that generates the finalizer of the current environment.
2656 * Only set for Synchronized and Try contexts.
2657 */
2658 GenFinalizer finalize = null;
2659
2660 /** Is this a switch statement? If so, allocate registers
2661 * even when the variable declaration is unreachable.
2662 */
2663 boolean isSwitch = false;
2664
2665 /** A list buffer containing all gaps in the finalizer range,
2666 * where a catch all exception should not apply.
2667 */
2668 ListBuffer<Integer> gaps = null;
2669
2670 GenContext() {
2671 var code = Gen.this.code;
2672 this.limit = code == null ? 0 : code.nextreg;
2673 }
2674
2675 /** Add given chain to exit chain.
2676 */
2677 void addExit(Chain c) {
2678 if (c != null) {
2679 c.state.defined.excludeFrom(limit);
2680 }
2681 exit = Code.mergeChains(c, exit);
2682 }
2683
2684 /** Add given chain to cont chain.
2685 */
2686 void addCont(Chain c) {
2687 if (c != null) {
2688 c.state.defined.excludeFrom(limit);
2689 }
2690 cont = Code.mergeChains(c, cont);
2691 }
2692 }
2693
2694 record PatternMatchingCatchConfiguration(Set<JCMethodInvocation> invocations,
2695 ListBuffer<int[]> ranges,
2696 JCCatch handler,
2697 State startState) {
2698 public PatternMatchingCatchConfiguration restart(State newState) {
2699 return new PatternMatchingCatchConfiguration(invocations(),
2700 new ListBuffer<int[]>(),
2701 handler(),
2702 newState);
2703 }
2704 }
2705 }