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