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 generateAssertUnsetFieldsFrame = options.isSet("generateAssertUnsetFieldsFrame"); 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 boolean generateAssertUnsetFieldsFrame; 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 /** An object containing mappings of syntax trees to their 171 * ending source positions. 172 */ 173 EndPosTable endPosTable; 174 175 boolean inCondSwitchExpression; 176 Chain switchExpressionTrueChain; 177 Chain switchExpressionFalseChain; 178 List<LocalItem> stackBeforeSwitchExpression; 179 LocalItem switchResult; 180 PatternMatchingCatchConfiguration patternMatchingCatchConfiguration = 181 new PatternMatchingCatchConfiguration(Set.of(), null, null, null); 182 183 /** Cache the symbol to reflect the qualifying type. 184 * key: corresponding type 185 * value: qualified symbol 186 */ 187 Map<Type, Symbol> qualifiedSymbolCache; 188 189 /** Generate code to load an integer constant. 190 * @param n The integer to be loaded. 191 */ 192 void loadIntConst(int n) { 193 items.makeImmediateItem(syms.intType, n).load(); 194 } 195 196 /** The opcode that loads a zero constant of a given type code. 197 * @param tc The given type code (@see ByteCode). 198 */ 199 public static int zero(int tc) { 200 switch(tc) { 201 case INTcode: case BYTEcode: case SHORTcode: case CHARcode: 202 return iconst_0; 203 case LONGcode: 204 return lconst_0; 205 case FLOATcode: 206 return fconst_0; 207 case DOUBLEcode: 208 return dconst_0; 209 default: 210 throw new AssertionError("zero"); 211 } 212 } 213 214 /** The opcode that loads a one constant of a given type code. 215 * @param tc The given type code (@see ByteCode). 216 */ 217 public static int one(int tc) { 218 return zero(tc) + 1; 219 } 220 221 /** Generate code to load -1 of the given type code (either int or long). 222 * @param tc The given type code (@see ByteCode). 223 */ 224 void emitMinusOne(int tc) { 225 if (tc == LONGcode) { 226 items.makeImmediateItem(syms.longType, Long.valueOf(-1)).load(); 227 } else { 228 code.emitop0(iconst_m1); 229 } 230 } 231 232 /** Construct a symbol to reflect the qualifying type that should 233 * appear in the byte code as per JLS 13.1. 234 * 235 * For {@literal target >= 1.2}: Clone a method with the qualifier as owner (except 236 * for those cases where we need to work around VM bugs). 237 * 238 * For {@literal target <= 1.1}: If qualified variable or method is defined in a 239 * non-accessible class, clone it with the qualifier class as owner. 240 * 241 * @param sym The accessed symbol 242 * @param site The qualifier's type. 243 */ 244 Symbol binaryQualifier(Symbol sym, Type site) { 245 246 if (site.hasTag(ARRAY)) { 247 if (sym == syms.lengthVar || 248 sym.owner != syms.arrayClass) 249 return sym; 250 // array clone can be qualified by the array type in later targets 251 Symbol qualifier; 252 if ((qualifier = qualifiedSymbolCache.get(site)) == null) { 253 qualifier = new ClassSymbol(Flags.PUBLIC, site.tsym.name, site, syms.noSymbol); 254 qualifiedSymbolCache.put(site, qualifier); 255 } 256 return sym.clone(qualifier); 257 } 258 259 if (sym.owner == site.tsym || 260 (sym.flags() & (STATIC | SYNTHETIC)) == (STATIC | SYNTHETIC)) { 261 return sym; 262 } 263 264 // leave alone methods inherited from Object 265 // JLS 13.1. 266 if (sym.owner == syms.objectType.tsym) 267 return sym; 268 269 return sym.clone(site.tsym); 270 } 271 272 /** Insert a reference to given type in the constant pool, 273 * checking for an array with too many dimensions; 274 * return the reference's index. 275 * @param type The type for which a reference is inserted. 276 */ 277 int makeRef(DiagnosticPosition pos, Type type) { 278 return poolWriter.putClass(checkDimension(pos, type)); 279 } 280 281 /** Check if the given type is an array with too many dimensions. 282 */ 283 private Type checkDimension(DiagnosticPosition pos, Type t) { 284 checkDimensionInternal(pos, t); 285 return t; 286 } 287 288 private void checkDimensionInternal(DiagnosticPosition pos, Type t) { 289 switch (t.getTag()) { 290 case METHOD: 291 checkDimension(pos, t.getReturnType()); 292 for (List<Type> args = t.getParameterTypes(); args.nonEmpty(); args = args.tail) 293 checkDimension(pos, args.head); 294 break; 295 case ARRAY: 296 if (types.dimensions(t) > ClassFile.MAX_DIMENSIONS) { 297 log.error(pos, Errors.LimitDimensions); 298 nerrs++; 299 } 300 break; 301 default: 302 break; 303 } 304 } 305 306 /** Create a temporary variable. 307 * @param type The variable's type. 308 */ 309 LocalItem makeTemp(Type type) { 310 VarSymbol v = new VarSymbol(Flags.SYNTHETIC, 311 names.empty, 312 type, 313 env.enclMethod.sym); 314 code.newLocal(v); 315 return items.makeLocalItem(v); 316 } 317 318 /** Generate code to call a non-private method or constructor. 319 * @param pos Position to be used for error reporting. 320 * @param site The type of which the method is a member. 321 * @param name The method's name. 322 * @param argtypes The method's argument types. 323 * @param isStatic A flag that indicates whether we call a 324 * static or instance method. 325 */ 326 void callMethod(DiagnosticPosition pos, 327 Type site, Name name, List<Type> argtypes, 328 boolean isStatic) { 329 Symbol msym = rs. 330 resolveInternalMethod(pos, attrEnv, site, name, argtypes, null); 331 if (isStatic) items.makeStaticItem(msym).invoke(); 332 else items.makeMemberItem(msym, name == names.init).invoke(); 333 } 334 335 /** Is the given method definition an access method 336 * resulting from a qualified super? This is signified by an odd 337 * access code. 338 */ 339 private boolean isAccessSuper(JCMethodDecl enclMethod) { 340 return 341 (enclMethod.mods.flags & SYNTHETIC) != 0 && 342 isOddAccessName(enclMethod.name); 343 } 344 345 /** Does given name start with "access$" and end in an odd digit? 346 */ 347 private boolean isOddAccessName(Name name) { 348 final String string = name.toString(); 349 return 350 string.startsWith(accessDollar) && 351 (string.charAt(string.length() - 1) & 1) != 0; 352 } 353 354 /* ************************************************************************ 355 * Non-local exits 356 *************************************************************************/ 357 358 /** Generate code to invoke the finalizer associated with given 359 * environment. 360 * Any calls to finalizers are appended to the environments `cont' chain. 361 * Mark beginning of gap in catch all range for finalizer. 362 */ 363 void genFinalizer(Env<GenContext> env) { 364 if (code.isAlive() && env.info.finalize != null) 365 env.info.finalize.gen(); 366 } 367 368 /** Generate code to call all finalizers of structures aborted by 369 * a non-local 370 * exit. Return target environment of the non-local exit. 371 * @param target The tree representing the structure that's aborted 372 * @param env The environment current at the non-local exit. 373 */ 374 Env<GenContext> unwind(JCTree target, Env<GenContext> env) { 375 Env<GenContext> env1 = env; 376 while (true) { 377 genFinalizer(env1); 378 if (env1.tree == target) break; 379 env1 = env1.next; 380 } 381 return env1; 382 } 383 384 /** Mark end of gap in catch-all range for finalizer. 385 * @param env the environment which might contain the finalizer 386 * (if it does, env.info.gaps != null). 387 */ 388 void endFinalizerGap(Env<GenContext> env) { 389 if (env.info.gaps != null && env.info.gaps.length() % 2 == 1) 390 env.info.gaps.append(code.curCP()); 391 } 392 393 /** Mark end of all gaps in catch-all ranges for finalizers of environments 394 * lying between, and including to two environments. 395 * @param from the most deeply nested environment to mark 396 * @param to the least deeply nested environment to mark 397 */ 398 void endFinalizerGaps(Env<GenContext> from, Env<GenContext> to) { 399 Env<GenContext> last = null; 400 while (last != to) { 401 endFinalizerGap(from); 402 last = from; 403 from = from.next; 404 } 405 } 406 407 /** Do any of the structures aborted by a non-local exit have 408 * finalizers that require an empty stack? 409 * @param target The tree representing the structure that's aborted 410 * @param env The environment current at the non-local exit. 411 */ 412 boolean hasFinally(JCTree target, Env<GenContext> env) { 413 while (env.tree != target) { 414 if (env.tree.hasTag(TRY) && env.info.finalize.hasFinalizer()) 415 return true; 416 env = env.next; 417 } 418 return false; 419 } 420 421 /* ************************************************************************ 422 * Normalizing class-members. 423 *************************************************************************/ 424 425 /** Distribute member initializer code into constructors and {@code <clinit>} 426 * method. 427 * @param defs The list of class member declarations. 428 * @param c The enclosing class. 429 */ 430 List<JCTree> normalizeDefs(List<JCTree> defs, ClassSymbol c) { 431 ListBuffer<JCStatement> initCode = new ListBuffer<>(); 432 // only used for value classes 433 ListBuffer<JCStatement> initBlocks = new ListBuffer<>(); 434 ListBuffer<Attribute.TypeCompound> initTAs = new ListBuffer<>(); 435 ListBuffer<JCStatement> clinitCode = new ListBuffer<>(); 436 ListBuffer<Attribute.TypeCompound> clinitTAs = new ListBuffer<>(); 437 ListBuffer<JCTree> methodDefs = new ListBuffer<>(); 438 // Sort definitions into three listbuffers: 439 // - initCode for instance initializers 440 // - clinitCode for class initializers 441 // - methodDefs for method definitions 442 for (List<JCTree> l = defs; l.nonEmpty(); l = l.tail) { 443 JCTree def = l.head; 444 switch (def.getTag()) { 445 case BLOCK: 446 JCBlock block = (JCBlock)def; 447 if ((block.flags & STATIC) != 0) 448 clinitCode.append(block); 449 else if ((block.flags & SYNTHETIC) == 0) { 450 if (c.isValueClass() || c.hasStrict()) { 451 initBlocks.append(block); 452 } else { 453 initCode.append(block); 454 } 455 } 456 break; 457 case METHODDEF: 458 methodDefs.append(def); 459 break; 460 case VARDEF: 461 JCVariableDecl vdef = (JCVariableDecl) def; 462 VarSymbol sym = vdef.sym; 463 checkDimension(vdef.pos(), sym.type); 464 if (vdef.init != null) { 465 if ((sym.flags() & STATIC) == 0) { 466 // Always initialize instance variables. 467 JCStatement init = make.at(vdef.pos()). 468 Assignment(sym, vdef.init); 469 initCode.append(init); 470 endPosTable.replaceTree(vdef, init); 471 initTAs.addAll(getAndRemoveNonFieldTAs(sym)); 472 } else if (sym.getConstValue() == null) { 473 // Initialize class (static) variables only if 474 // they are not compile-time constants. 475 JCStatement init = make.at(vdef.pos). 476 Assignment(sym, vdef.init); 477 clinitCode.append(init); 478 endPosTable.replaceTree(vdef, init); 479 clinitTAs.addAll(getAndRemoveNonFieldTAs(sym)); 480 } else { 481 checkStringConstant(vdef.init.pos(), sym.getConstValue()); 482 /* if the init contains a reference to an external class, add it to the 483 * constant's pool 484 */ 485 vdef.init.accept(classReferenceVisitor); 486 } 487 } 488 break; 489 default: 490 Assert.error(); 491 } 492 } 493 // Insert any instance initializers into all constructors. 494 if (initCode.length() != 0 || initBlocks.length() != 0) { 495 initTAs.addAll(c.getInitTypeAttributes()); 496 List<Attribute.TypeCompound> initTAlist = initTAs.toList(); 497 for (JCTree t : methodDefs) { 498 normalizeMethod((JCMethodDecl)t, initCode.toList(), initBlocks.toList(), initTAlist); 499 } 500 } 501 // If there are class initializers, create a <clinit> method 502 // that contains them as its body. 503 if (clinitCode.length() != 0) { 504 MethodSymbol clinit = new MethodSymbol( 505 STATIC | (c.flags() & STRICTFP), 506 names.clinit, 507 new MethodType( 508 List.nil(), syms.voidType, 509 List.nil(), syms.methodClass), 510 c); 511 c.members().enter(clinit); 512 List<JCStatement> clinitStats = clinitCode.toList(); 513 JCBlock block = make.at(clinitStats.head.pos()).Block(0, clinitStats); 514 block.endpos = TreeInfo.endPos(clinitStats.last()); 515 methodDefs.append(make.MethodDef(clinit, block)); 516 517 if (!clinitTAs.isEmpty()) 518 clinit.appendUniqueTypeAttributes(clinitTAs.toList()); 519 if (!c.getClassInitTypeAttributes().isEmpty()) 520 clinit.appendUniqueTypeAttributes(c.getClassInitTypeAttributes()); 521 } 522 // Return all method definitions. 523 return methodDefs.toList(); 524 } 525 526 private List<Attribute.TypeCompound> getAndRemoveNonFieldTAs(VarSymbol sym) { 527 List<TypeCompound> tas = sym.getRawTypeAttributes(); 528 ListBuffer<Attribute.TypeCompound> fieldTAs = new ListBuffer<>(); 529 ListBuffer<Attribute.TypeCompound> nonfieldTAs = new ListBuffer<>(); 530 for (TypeCompound ta : tas) { 531 Assert.check(ta.getPosition().type != TargetType.UNKNOWN); 532 if (ta.getPosition().type == TargetType.FIELD) { 533 fieldTAs.add(ta); 534 } else { 535 nonfieldTAs.add(ta); 536 } 537 } 538 sym.setTypeAttributes(fieldTAs.toList()); 539 return nonfieldTAs.toList(); 540 } 541 542 /** Check a constant value and report if it is a string that is 543 * too large. 544 */ 545 private void checkStringConstant(DiagnosticPosition pos, Object constValue) { 546 if (nerrs != 0 || // only complain about a long string once 547 constValue == null || 548 !(constValue instanceof String str) || 549 str.length() < PoolWriter.MAX_STRING_LENGTH) 550 return; 551 log.error(pos, Errors.LimitString); 552 nerrs++; 553 } 554 555 /** Insert instance initializer code into constructors prior to the super() call. 556 * @param md The tree potentially representing a 557 * constructor's definition. 558 * @param initCode The list of instance initializer statements. 559 * @param initTAs Type annotations from the initializer expression. 560 */ 561 void normalizeMethod(JCMethodDecl md, List<JCStatement> initCode, List<JCStatement> initBlocks, List<TypeCompound> initTAs) { 562 if (TreeInfo.isConstructor(md) && TreeInfo.hasConstructorCall(md, names._super)) { 563 // We are seeing a constructor that has a super() call. 564 // Find the super() invocation and append the given initializer code. 565 if (md.sym.owner.isValueClass() || md.sym.owner.hasStrict()) { 566 rewriteInitializersIfNeeded(md, initCode); 567 md.body.stats = initCode.appendList(md.body.stats); 568 TreeInfo.mapSuperCalls(md.body, supercall -> make.Block(0, initBlocks.prepend(supercall))); 569 } else { 570 TreeInfo.mapSuperCalls(md.body, supercall -> make.Block(0, initCode.prepend(supercall))); 571 } 572 573 if (md.body.endpos == Position.NOPOS) 574 md.body.endpos = TreeInfo.endPos(md.body.stats.last()); 575 576 md.sym.appendUniqueTypeAttributes(initTAs); 577 } 578 } 579 580 void rewriteInitializersIfNeeded(JCMethodDecl md, List<JCStatement> initCode) { 581 if (lower.initializerOuterThis.containsKey(md.sym.owner)) { 582 InitializerVisitor initializerVisitor = new InitializerVisitor(md, lower.initializerOuterThis.get(md.sym.owner)); 583 for (JCStatement init : initCode) { 584 initializerVisitor.scan(init); 585 } 586 } 587 } 588 589 public static class InitializerVisitor extends TreeScanner { 590 JCMethodDecl md; 591 Set<JCExpression> exprSet; 592 593 public InitializerVisitor(JCMethodDecl md, Set<JCExpression> exprSet) { 594 this.md = md; 595 this.exprSet = exprSet; 596 } 597 598 @Override 599 public void visitTree(JCTree tree) {} 600 601 @Override 602 public void visitIdent(JCIdent tree) { 603 if (exprSet.contains(tree)) { 604 for (JCVariableDecl param: md.params) { 605 if (param.name == tree.name && 606 ((param.sym.flags_field & (MANDATED | NOOUTERTHIS)) == (MANDATED | NOOUTERTHIS))) { 607 tree.sym = param.sym; 608 } 609 } 610 } 611 } 612 } 613 614 /* ************************************************************************ 615 * Traversal methods 616 *************************************************************************/ 617 618 /** Visitor argument: The current environment. 619 */ 620 Env<GenContext> env; 621 622 /** Visitor argument: The expected type (prototype). 623 */ 624 Type pt; 625 626 /** Visitor result: The item representing the computed value. 627 */ 628 Item result; 629 630 /** Visitor method: generate code for a definition, catching and reporting 631 * any completion failures. 632 * @param tree The definition to be visited. 633 * @param env The environment current at the definition. 634 */ 635 public void genDef(JCTree tree, Env<GenContext> env) { 636 Env<GenContext> prevEnv = this.env; 637 try { 638 this.env = env; 639 tree.accept(this); 640 } catch (CompletionFailure ex) { 641 chk.completionError(tree.pos(), ex); 642 } finally { 643 this.env = prevEnv; 644 } 645 } 646 647 /** Derived visitor method: check whether CharacterRangeTable 648 * should be emitted, if so, put a new entry into CRTable 649 * and call method to generate bytecode. 650 * If not, just call method to generate bytecode. 651 * @see #genStat(JCTree, Env) 652 * 653 * @param tree The tree to be visited. 654 * @param env The environment to use. 655 * @param crtFlags The CharacterRangeTable flags 656 * indicating type of the entry. 657 */ 658 public void genStat(JCTree tree, Env<GenContext> env, int crtFlags) { 659 if (!genCrt) { 660 genStat(tree, env); 661 return; 662 } 663 int startpc = code.curCP(); 664 genStat(tree, env); 665 if (tree.hasTag(Tag.BLOCK)) crtFlags |= CRT_BLOCK; 666 code.crt.put(tree, crtFlags, startpc, code.curCP()); 667 } 668 669 /** Derived visitor method: generate code for a statement. 670 */ 671 public void genStat(JCTree tree, Env<GenContext> env) { 672 if (code.isAlive()) { 673 code.statBegin(tree.pos); 674 genDef(tree, env); 675 } else if (env.info.isSwitch && tree.hasTag(VARDEF)) { 676 // variables whose declarations are in a switch 677 // can be used even if the decl is unreachable. 678 code.newLocal(((JCVariableDecl) tree).sym); 679 } 680 } 681 682 /** Derived visitor method: check whether CharacterRangeTable 683 * should be emitted, if so, put a new entry into CRTable 684 * and call method to generate bytecode. 685 * If not, just call method to generate bytecode. 686 * @see #genStats(List, Env) 687 * 688 * @param trees The list of trees to be visited. 689 * @param env The environment to use. 690 * @param crtFlags The CharacterRangeTable flags 691 * indicating type of the entry. 692 */ 693 public void genStats(List<JCStatement> trees, Env<GenContext> env, int crtFlags) { 694 if (!genCrt) { 695 genStats(trees, env); 696 return; 697 } 698 if (trees.length() == 1) { // mark one statement with the flags 699 genStat(trees.head, env, crtFlags | CRT_STATEMENT); 700 } else { 701 int startpc = code.curCP(); 702 genStats(trees, env); 703 code.crt.put(trees, crtFlags, startpc, code.curCP()); 704 } 705 } 706 707 /** Derived visitor method: generate code for a list of statements. 708 */ 709 public void genStats(List<? extends JCTree> trees, Env<GenContext> env) { 710 for (List<? extends JCTree> l = trees; l.nonEmpty(); l = l.tail) 711 genStat(l.head, env, CRT_STATEMENT); 712 } 713 714 /** Derived visitor method: check whether CharacterRangeTable 715 * should be emitted, if so, put a new entry into CRTable 716 * and call method to generate bytecode. 717 * If not, just call method to generate bytecode. 718 * @see #genCond(JCTree,boolean) 719 * 720 * @param tree The tree to be visited. 721 * @param crtFlags The CharacterRangeTable flags 722 * indicating type of the entry. 723 */ 724 public CondItem genCond(JCTree tree, int crtFlags) { 725 if (!genCrt) return genCond(tree, false); 726 int startpc = code.curCP(); 727 CondItem item = genCond(tree, (crtFlags & CRT_FLOW_CONTROLLER) != 0); 728 code.crt.put(tree, crtFlags, startpc, code.curCP()); 729 return item; 730 } 731 732 /** Derived visitor method: generate code for a boolean 733 * expression in a control-flow context. 734 * @param _tree The expression to be visited. 735 * @param markBranches The flag to indicate that the condition is 736 * a flow controller so produced conditions 737 * should contain a proper tree to generate 738 * CharacterRangeTable branches for them. 739 */ 740 public CondItem genCond(JCTree _tree, boolean markBranches) { 741 JCTree inner_tree = TreeInfo.skipParens(_tree); 742 if (inner_tree.hasTag(CONDEXPR)) { 743 JCConditional tree = (JCConditional)inner_tree; 744 CondItem cond = genCond(tree.cond, CRT_FLOW_CONTROLLER); 745 if (cond.isTrue()) { 746 code.resolve(cond.trueJumps); 747 CondItem result = genCond(tree.truepart, CRT_FLOW_TARGET); 748 if (markBranches) result.tree = tree.truepart; 749 return result; 750 } 751 if (cond.isFalse()) { 752 code.resolve(cond.falseJumps); 753 CondItem result = genCond(tree.falsepart, CRT_FLOW_TARGET); 754 if (markBranches) result.tree = tree.falsepart; 755 return result; 756 } 757 Chain secondJumps = cond.jumpFalse(); 758 code.resolve(cond.trueJumps); 759 CondItem first = genCond(tree.truepart, CRT_FLOW_TARGET); 760 if (markBranches) first.tree = tree.truepart; 761 Chain falseJumps = first.jumpFalse(); 762 code.resolve(first.trueJumps); 763 Chain trueJumps = code.branch(goto_); 764 code.resolve(secondJumps); 765 CondItem second = genCond(tree.falsepart, CRT_FLOW_TARGET); 766 CondItem result = items.makeCondItem(second.opcode, 767 Code.mergeChains(trueJumps, second.trueJumps), 768 Code.mergeChains(falseJumps, second.falseJumps)); 769 if (markBranches) result.tree = tree.falsepart; 770 return result; 771 } else if (inner_tree.hasTag(SWITCH_EXPRESSION)) { 772 code.resolvePending(); 773 774 boolean prevInCondSwitchExpression = inCondSwitchExpression; 775 Chain prevSwitchExpressionTrueChain = switchExpressionTrueChain; 776 Chain prevSwitchExpressionFalseChain = switchExpressionFalseChain; 777 try { 778 inCondSwitchExpression = true; 779 switchExpressionTrueChain = null; 780 switchExpressionFalseChain = null; 781 try { 782 doHandleSwitchExpression((JCSwitchExpression) inner_tree); 783 } catch (CompletionFailure ex) { 784 chk.completionError(_tree.pos(), ex); 785 code.state.stacksize = 1; 786 } 787 CondItem result = items.makeCondItem(goto_, 788 switchExpressionTrueChain, 789 switchExpressionFalseChain); 790 if (markBranches) result.tree = _tree; 791 return result; 792 } finally { 793 inCondSwitchExpression = prevInCondSwitchExpression; 794 switchExpressionTrueChain = prevSwitchExpressionTrueChain; 795 switchExpressionFalseChain = prevSwitchExpressionFalseChain; 796 } 797 } else if (inner_tree.hasTag(LETEXPR) && ((LetExpr) inner_tree).needsCond) { 798 code.resolvePending(); 799 800 LetExpr tree = (LetExpr) inner_tree; 801 int limit = code.nextreg; 802 int prevLetExprStart = code.setLetExprStackPos(code.state.stacksize); 803 try { 804 genStats(tree.defs, env); 805 } finally { 806 code.setLetExprStackPos(prevLetExprStart); 807 } 808 CondItem result = genCond(tree.expr, markBranches); 809 code.endScopes(limit); 810 return result; 811 } else { 812 CondItem result = genExpr(_tree, syms.booleanType).mkCond(); 813 if (markBranches) result.tree = _tree; 814 return result; 815 } 816 } 817 818 public Code getCode() { 819 return code; 820 } 821 822 public Items getItems() { 823 return items; 824 } 825 826 public Env<AttrContext> getAttrEnv() { 827 return attrEnv; 828 } 829 830 /** Visitor class for expressions which might be constant expressions. 831 * This class is a subset of TreeScanner. Intended to visit trees pruned by 832 * Lower as long as constant expressions looking for references to any 833 * ClassSymbol. Any such reference will be added to the constant pool so 834 * automated tools can detect class dependencies better. 835 */ 836 class ClassReferenceVisitor extends JCTree.Visitor { 837 838 @Override 839 public void visitTree(JCTree tree) {} 840 841 @Override 842 public void visitBinary(JCBinary tree) { 843 tree.lhs.accept(this); 844 tree.rhs.accept(this); 845 } 846 847 @Override 848 public void visitSelect(JCFieldAccess tree) { 849 if (tree.selected.type.hasTag(CLASS)) { 850 makeRef(tree.selected.pos(), tree.selected.type); 851 } 852 } 853 854 @Override 855 public void visitIdent(JCIdent tree) { 856 if (tree.sym.owner instanceof ClassSymbol classSymbol) { 857 poolWriter.putClass(classSymbol); 858 } 859 } 860 861 @Override 862 public void visitConditional(JCConditional tree) { 863 tree.cond.accept(this); 864 tree.truepart.accept(this); 865 tree.falsepart.accept(this); 866 } 867 868 @Override 869 public void visitUnary(JCUnary tree) { 870 tree.arg.accept(this); 871 } 872 873 @Override 874 public void visitParens(JCParens tree) { 875 tree.expr.accept(this); 876 } 877 878 @Override 879 public void visitTypeCast(JCTypeCast tree) { 880 tree.expr.accept(this); 881 } 882 } 883 884 private ClassReferenceVisitor classReferenceVisitor = new ClassReferenceVisitor(); 885 886 /** Visitor method: generate code for an expression, catching and reporting 887 * any completion failures. 888 * @param tree The expression to be visited. 889 * @param pt The expression's expected type (proto-type). 890 */ 891 public Item genExpr(JCTree tree, Type pt) { 892 if (!code.isAlive()) { 893 return items.makeStackItem(pt); 894 } 895 896 Type prevPt = this.pt; 897 try { 898 if (tree.type.constValue() != null) { 899 // Short circuit any expressions which are constants 900 tree.accept(classReferenceVisitor); 901 checkStringConstant(tree.pos(), tree.type.constValue()); 902 Symbol sym = TreeInfo.symbol(tree); 903 if (sym != null && isConstantDynamic(sym)) { 904 result = items.makeDynamicItem(sym); 905 } else { 906 result = items.makeImmediateItem(tree.type, tree.type.constValue()); 907 } 908 } else { 909 this.pt = pt; 910 tree.accept(this); 911 } 912 return result.coerce(pt); 913 } catch (CompletionFailure ex) { 914 chk.completionError(tree.pos(), ex); 915 code.state.stacksize = 1; 916 return items.makeStackItem(pt); 917 } finally { 918 this.pt = prevPt; 919 } 920 } 921 922 public boolean isConstantDynamic(Symbol sym) { 923 return sym.kind == VAR && 924 sym instanceof DynamicVarSymbol dynamicVarSymbol && 925 dynamicVarSymbol.isDynamic(); 926 } 927 928 /** Derived visitor method: generate code for a list of method arguments. 929 * @param trees The argument expressions to be visited. 930 * @param pts The expression's expected types (i.e. the formal parameter 931 * types of the invoked method). 932 */ 933 public void genArgs(List<JCExpression> trees, List<Type> pts) { 934 for (List<JCExpression> l = trees; l.nonEmpty(); l = l.tail) { 935 genExpr(l.head, pts.head).load(); 936 pts = pts.tail; 937 } 938 // require lists be of same length 939 Assert.check(pts.isEmpty()); 940 } 941 942 /* ************************************************************************ 943 * Visitor methods for statements and definitions 944 *************************************************************************/ 945 946 /** Thrown when the byte code size exceeds limit. 947 */ 948 public static class CodeSizeOverflow extends RuntimeException { 949 private static final long serialVersionUID = 0; 950 public CodeSizeOverflow() {} 951 } 952 953 public void visitMethodDef(JCMethodDecl tree) { 954 // Create a new local environment that points pack at method 955 // definition. 956 Env<GenContext> localEnv = env.dup(tree); 957 localEnv.enclMethod = tree; 958 // The expected type of every return statement in this method 959 // is the method's return type. 960 this.pt = tree.sym.erasure(types).getReturnType(); 961 962 checkDimension(tree.pos(), tree.sym.erasure(types)); 963 genMethod(tree, localEnv, false); 964 } 965 //where 966 /** Generate code for a method. 967 * @param tree The tree representing the method definition. 968 * @param env The environment current for the method body. 969 * @param fatcode A flag that indicates whether all jumps are 970 * within 32K. We first invoke this method under 971 * the assumption that fatcode == false, i.e. all 972 * jumps are within 32K. If this fails, fatcode 973 * is set to true and we try again. 974 */ 975 void genMethod(JCMethodDecl tree, Env<GenContext> env, boolean fatcode) { 976 MethodSymbol meth = tree.sym; 977 int extras = 0; 978 // Count up extra parameters 979 if (meth.isConstructor()) { 980 extras++; 981 if (meth.enclClass().isInner() && 982 !meth.enclClass().isStatic()) { 983 extras++; 984 } 985 } else if ((tree.mods.flags & STATIC) == 0) { 986 extras++; 987 } 988 // System.err.println("Generating " + meth + " in " + meth.owner); //DEBUG 989 if (Code.width(types.erasure(env.enclMethod.sym.type).getParameterTypes()) + extras > 990 ClassFile.MAX_PARAMETERS) { 991 log.error(tree.pos(), Errors.LimitParameters); 992 nerrs++; 993 } 994 995 else if (tree.body != null) { 996 // Create a new code structure and initialize it. 997 int startpcCrt = initCode(tree, env, fatcode); 998 Set<VarSymbol> prevUnsetFields = code.currentUnsetFields; 999 if (meth.isConstructor()) { 1000 code.currentUnsetFields = unsetFieldsInfo.getUnsetFields(env.enclClass.sym, tree.body); 1001 code.initialUnsetFields = unsetFieldsInfo.getUnsetFields(env.enclClass.sym, tree.body); 1002 } 1003 1004 try { 1005 genStat(tree.body, env); 1006 } catch (CodeSizeOverflow e) { 1007 // Failed due to code limit, try again with jsr/ret 1008 startpcCrt = initCode(tree, env, fatcode); 1009 genStat(tree.body, env); 1010 } finally { 1011 code.currentUnsetFields = prevUnsetFields; 1012 } 1013 1014 if (code.state.stacksize != 0) { 1015 log.error(tree.body.pos(), Errors.StackSimError(tree.sym)); 1016 throw new AssertionError(); 1017 } 1018 1019 // If last statement could complete normally, insert a 1020 // return at the end. 1021 if (code.isAlive()) { 1022 code.statBegin(TreeInfo.endPos(tree.body)); 1023 if (env.enclMethod == null || 1024 env.enclMethod.sym.type.getReturnType().hasTag(VOID)) { 1025 code.emitop0(return_); 1026 } else { 1027 // sometime dead code seems alive (4415991); 1028 // generate a small loop instead 1029 int startpc = code.entryPoint(); 1030 CondItem c = items.makeCondItem(goto_); 1031 code.resolve(c.jumpTrue(), startpc); 1032 } 1033 } 1034 if (genCrt) 1035 code.crt.put(tree.body, 1036 CRT_BLOCK, 1037 startpcCrt, 1038 code.curCP()); 1039 1040 code.endScopes(0); 1041 1042 // If we exceeded limits, panic 1043 if (code.checkLimits(tree.pos(), log)) { 1044 nerrs++; 1045 return; 1046 } 1047 1048 // If we generated short code but got a long jump, do it again 1049 // with fatCode = true. 1050 if (!fatcode && code.fatcode) genMethod(tree, env, true); 1051 1052 // Clean up 1053 if(stackMap == StackMapFormat.JSR202) { 1054 code.lastFrame = null; 1055 code.frameBeforeLast = null; 1056 } 1057 1058 // Compress exception table 1059 code.compressCatchTable(); 1060 1061 // Fill in type annotation positions for exception parameters 1062 code.fillExceptionParameterPositions(); 1063 } 1064 } 1065 1066 private int initCode(JCMethodDecl tree, Env<GenContext> env, boolean fatcode) { 1067 MethodSymbol meth = tree.sym; 1068 1069 // Create a new code structure. 1070 meth.code = code = new Code(meth, 1071 fatcode, 1072 lineDebugInfo ? toplevel.lineMap : null, 1073 varDebugInfo, 1074 stackMap, 1075 debugCode, 1076 genCrt ? new CRTable(tree, env.toplevel.endPositions) 1077 : null, 1078 syms, 1079 types, 1080 poolWriter, 1081 generateAssertUnsetFieldsFrame); 1082 items = new Items(poolWriter, code, syms, types); 1083 if (code.debugCode) { 1084 System.err.println(meth + " for body " + tree); 1085 } 1086 1087 // If method is not static, create a new local variable address 1088 // for `this'. 1089 if ((tree.mods.flags & STATIC) == 0) { 1090 Type selfType = meth.owner.type; 1091 if (meth.isConstructor() && selfType != syms.objectType) 1092 selfType = UninitializedType.uninitializedThis(selfType); 1093 code.setDefined( 1094 code.newLocal( 1095 new VarSymbol(FINAL, names._this, selfType, meth.owner))); 1096 } 1097 1098 // Mark all parameters as defined from the beginning of 1099 // the method. 1100 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) { 1101 checkDimension(l.head.pos(), l.head.sym.type); 1102 code.setDefined(code.newLocal(l.head.sym)); 1103 } 1104 1105 // Get ready to generate code for method body. 1106 int startpcCrt = genCrt ? code.curCP() : 0; 1107 code.entryPoint(); 1108 1109 // Suppress initial stackmap 1110 code.pendingStackMap = false; 1111 1112 return startpcCrt; 1113 } 1114 1115 public void visitVarDef(JCVariableDecl tree) { 1116 VarSymbol v = tree.sym; 1117 if (tree.init != null) { 1118 checkStringConstant(tree.init.pos(), v.getConstValue()); 1119 if (v.getConstValue() == null || varDebugInfo) { 1120 Assert.check(code.isStatementStart()); 1121 code.newLocal(v); 1122 genExpr(tree.init, v.erasure(types)).load(); 1123 items.makeLocalItem(v).store(); 1124 Assert.check(code.isStatementStart()); 1125 } 1126 } else { 1127 code.newLocal(v); 1128 } 1129 checkDimension(tree.pos(), v.type); 1130 } 1131 1132 public void visitSkip(JCSkip tree) { 1133 } 1134 1135 public void visitBlock(JCBlock tree) { 1136 /* this method is heavily invoked, as expected, for deeply nested blocks, if blocks doesn't happen to have 1137 * patterns there will be an unnecessary tax on memory consumption every time this method is executed, for this 1138 * reason we have created helper methods and here at a higher level we just discriminate depending on the 1139 * presence, or not, of patterns in a given block 1140 */ 1141 if (tree.patternMatchingCatch != null) { 1142 visitBlockWithPatterns(tree); 1143 } else { 1144 internalVisitBlock(tree); 1145 } 1146 } 1147 1148 private void visitBlockWithPatterns(JCBlock tree) { 1149 PatternMatchingCatchConfiguration prevConfiguration = patternMatchingCatchConfiguration; 1150 try { 1151 patternMatchingCatchConfiguration = 1152 new PatternMatchingCatchConfiguration(tree.patternMatchingCatch.calls2Handle(), 1153 new ListBuffer<int[]>(), 1154 tree.patternMatchingCatch.handler(), 1155 code.state.dup()); 1156 internalVisitBlock(tree); 1157 } finally { 1158 generatePatternMatchingCatch(env); 1159 patternMatchingCatchConfiguration = prevConfiguration; 1160 } 1161 } 1162 1163 private void generatePatternMatchingCatch(Env<GenContext> env) { 1164 if (patternMatchingCatchConfiguration.handler != null && 1165 !patternMatchingCatchConfiguration.ranges.isEmpty()) { 1166 Chain skipCatch = code.branch(goto_); 1167 JCCatch handler = patternMatchingCatchConfiguration.handler(); 1168 code.entryPoint(patternMatchingCatchConfiguration.startState(), 1169 handler.param.sym.type); 1170 genPatternMatchingCatch(handler, 1171 env, 1172 patternMatchingCatchConfiguration.ranges.toList()); 1173 code.resolve(skipCatch); 1174 } 1175 } 1176 1177 private void internalVisitBlock(JCBlock tree) { 1178 int limit = code.nextreg; 1179 Env<GenContext> localEnv = env.dup(tree, new GenContext()); 1180 genStats(tree.stats, localEnv); 1181 // End the scope of all block-local variables in variable info. 1182 if (!env.tree.hasTag(METHODDEF)) { 1183 code.statBegin(tree.endpos); 1184 code.endScopes(limit); 1185 code.pendingStatPos = Position.NOPOS; 1186 } 1187 } 1188 1189 public void visitDoLoop(JCDoWhileLoop tree) { 1190 genLoop(tree, tree.body, tree.cond, List.nil(), false); 1191 } 1192 1193 public void visitWhileLoop(JCWhileLoop tree) { 1194 genLoop(tree, tree.body, tree.cond, List.nil(), true); 1195 } 1196 1197 public void visitForLoop(JCForLoop tree) { 1198 int limit = code.nextreg; 1199 genStats(tree.init, env); 1200 genLoop(tree, tree.body, tree.cond, tree.step, true); 1201 code.endScopes(limit); 1202 } 1203 //where 1204 /** Generate code for a loop. 1205 * @param loop The tree representing the loop. 1206 * @param body The loop's body. 1207 * @param cond The loop's controlling condition. 1208 * @param step "Step" statements to be inserted at end of 1209 * each iteration. 1210 * @param testFirst True if the loop test belongs before the body. 1211 */ 1212 private void genLoop(JCStatement loop, 1213 JCStatement body, 1214 JCExpression cond, 1215 List<JCExpressionStatement> step, 1216 boolean testFirst) { 1217 Set<VarSymbol> prevCodeUnsetFields = code.currentUnsetFields; 1218 try { 1219 genLoopHelper(loop, body, cond, step, testFirst); 1220 } finally { 1221 code.currentUnsetFields = prevCodeUnsetFields; 1222 } 1223 } 1224 1225 private void genLoopHelper(JCStatement loop, 1226 JCStatement body, 1227 JCExpression cond, 1228 List<JCExpressionStatement> step, 1229 boolean testFirst) { 1230 Env<GenContext> loopEnv = env.dup(loop, new GenContext()); 1231 int startpc = code.entryPoint(); 1232 if (testFirst) { //while or for loop 1233 CondItem c; 1234 if (cond != null) { 1235 code.statBegin(cond.pos); 1236 Assert.check(code.isStatementStart()); 1237 c = genCond(TreeInfo.skipParens(cond), CRT_FLOW_CONTROLLER); 1238 } else { 1239 c = items.makeCondItem(goto_); 1240 } 1241 Chain loopDone = c.jumpFalse(); 1242 code.resolve(c.trueJumps); 1243 Assert.check(code.isStatementStart()); 1244 genStat(body, loopEnv, CRT_STATEMENT | CRT_FLOW_TARGET); 1245 code.resolve(loopEnv.info.cont); 1246 genStats(step, loopEnv); 1247 code.resolve(code.branch(goto_), startpc); 1248 code.resolve(loopDone); 1249 } else { 1250 genStat(body, loopEnv, CRT_STATEMENT | CRT_FLOW_TARGET); 1251 code.resolve(loopEnv.info.cont); 1252 genStats(step, loopEnv); 1253 if (code.isAlive()) { 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 code.resolve(c.jumpTrue(), startpc); 1263 Assert.check(code.isStatementStart()); 1264 code.resolve(c.falseJumps); 1265 } 1266 } 1267 Chain exit = loopEnv.info.exit; 1268 if (exit != null) { 1269 code.resolve(exit); 1270 exit.state.defined.excludeFrom(code.nextreg); 1271 } 1272 } 1273 1274 public void visitForeachLoop(JCEnhancedForLoop tree) { 1275 throw new AssertionError(); // should have been removed by Lower. 1276 } 1277 1278 public void visitLabelled(JCLabeledStatement tree) { 1279 Env<GenContext> localEnv = env.dup(tree, new GenContext()); 1280 genStat(tree.body, localEnv, CRT_STATEMENT); 1281 Chain exit = localEnv.info.exit; 1282 if (exit != null) { 1283 code.resolve(exit); 1284 exit.state.defined.excludeFrom(code.nextreg); 1285 } 1286 } 1287 1288 public void visitSwitch(JCSwitch tree) { 1289 handleSwitch(tree, tree.selector, tree.cases, tree.patternSwitch); 1290 } 1291 1292 @Override 1293 public void visitSwitchExpression(JCSwitchExpression tree) { 1294 code.resolvePending(); 1295 boolean prevInCondSwitchExpression = inCondSwitchExpression; 1296 Set<VarSymbol> prevCodeUnsetFields = code.currentUnsetFields; 1297 try { 1298 inCondSwitchExpression = false; 1299 doHandleSwitchExpression(tree); 1300 } finally { 1301 inCondSwitchExpression = prevInCondSwitchExpression; 1302 code.currentUnsetFields = prevCodeUnsetFields; 1303 } 1304 result = items.makeStackItem(pt); 1305 } 1306 1307 private void doHandleSwitchExpression(JCSwitchExpression tree) { 1308 List<LocalItem> prevStackBeforeSwitchExpression = stackBeforeSwitchExpression; 1309 LocalItem prevSwitchResult = switchResult; 1310 int limit = code.nextreg; 1311 try { 1312 stackBeforeSwitchExpression = List.nil(); 1313 switchResult = null; 1314 if (hasTry(tree)) { 1315 //if the switch expression contains try-catch, the catch handlers need to have 1316 //an empty stack. So stash whole stack to local variables, and restore it before 1317 //breaks: 1318 while (code.state.stacksize > 0) { 1319 Type type = code.state.peek(); 1320 Name varName = names.fromString(target.syntheticNameChar() + 1321 "stack" + 1322 target.syntheticNameChar() + 1323 tree.pos + 1324 target.syntheticNameChar() + 1325 code.state.stacksize); 1326 VarSymbol var = new VarSymbol(Flags.SYNTHETIC, varName, type, 1327 this.env.enclMethod.sym); 1328 LocalItem item = items.new LocalItem(type, code.newLocal(var)); 1329 stackBeforeSwitchExpression = stackBeforeSwitchExpression.prepend(item); 1330 item.store(); 1331 } 1332 switchResult = makeTemp(tree.type); 1333 } 1334 int prevLetExprStart = code.setLetExprStackPos(code.state.stacksize); 1335 try { 1336 handleSwitch(tree, tree.selector, tree.cases, tree.patternSwitch); 1337 } finally { 1338 code.setLetExprStackPos(prevLetExprStart); 1339 } 1340 } finally { 1341 stackBeforeSwitchExpression = prevStackBeforeSwitchExpression; 1342 switchResult = prevSwitchResult; 1343 code.endScopes(limit); 1344 } 1345 } 1346 //where: 1347 private boolean hasTry(JCSwitchExpression tree) { 1348 class HasTryScanner extends TreeScanner { 1349 private boolean hasTry; 1350 1351 @Override 1352 public void visitTry(JCTry tree) { 1353 hasTry = true; 1354 } 1355 1356 @Override 1357 public void visitSynchronized(JCSynchronized tree) { 1358 hasTry = true; 1359 } 1360 1361 @Override 1362 public void visitClassDef(JCClassDecl tree) { 1363 } 1364 1365 @Override 1366 public void visitLambda(JCLambda tree) { 1367 } 1368 }; 1369 1370 HasTryScanner hasTryScanner = new HasTryScanner(); 1371 1372 hasTryScanner.scan(tree); 1373 return hasTryScanner.hasTry; 1374 } 1375 1376 private void handleSwitch(JCTree swtch, JCExpression selector, List<JCCase> cases, 1377 boolean patternSwitch) { 1378 Set<VarSymbol> prevCodeUnsetFields = code.currentUnsetFields; 1379 try { 1380 handleSwitchHelper(swtch, selector, cases, patternSwitch); 1381 } finally { 1382 code.currentUnsetFields = prevCodeUnsetFields; 1383 } 1384 } 1385 1386 void handleSwitchHelper(JCTree swtch, JCExpression selector, List<JCCase> cases, 1387 boolean patternSwitch) { 1388 int limit = code.nextreg; 1389 Assert.check(!selector.type.hasTag(CLASS)); 1390 int switchStart = patternSwitch ? code.entryPoint() : -1; 1391 int startpcCrt = genCrt ? code.curCP() : 0; 1392 Assert.check(code.isStatementStart()); 1393 Item sel = genExpr(selector, syms.intType); 1394 if (cases.isEmpty()) { 1395 // We are seeing: switch <sel> {} 1396 sel.load().drop(); 1397 if (genCrt) 1398 code.crt.put(TreeInfo.skipParens(selector), 1399 CRT_FLOW_CONTROLLER, startpcCrt, code.curCP()); 1400 } else { 1401 // We are seeing a nonempty switch. 1402 sel.load(); 1403 if (genCrt) 1404 code.crt.put(TreeInfo.skipParens(selector), 1405 CRT_FLOW_CONTROLLER, startpcCrt, code.curCP()); 1406 Env<GenContext> switchEnv = env.dup(swtch, new GenContext()); 1407 switchEnv.info.isSwitch = true; 1408 1409 // Compute number of labels and minimum and maximum label values. 1410 // For each case, store its label in an array. 1411 int lo = Integer.MAX_VALUE; // minimum label. 1412 int hi = Integer.MIN_VALUE; // maximum label. 1413 int nlabels = 0; // number of labels. 1414 1415 int[] labels = new int[cases.length()]; // the label array. 1416 int defaultIndex = -1; // the index of the default clause. 1417 1418 List<JCCase> l = cases; 1419 for (int i = 0; i < labels.length; i++) { 1420 if (l.head.labels.head instanceof JCConstantCaseLabel constLabel) { 1421 Assert.check(l.head.labels.size() == 1); 1422 int val = ((Number) constLabel.expr.type.constValue()).intValue(); 1423 labels[i] = val; 1424 if (val < lo) lo = val; 1425 if (hi < val) hi = val; 1426 nlabels++; 1427 } else { 1428 Assert.check(defaultIndex == -1); 1429 defaultIndex = i; 1430 } 1431 l = l.tail; 1432 } 1433 1434 // Determine whether to issue a tableswitch or a lookupswitch 1435 // instruction. 1436 long table_space_cost = 4 + ((long) hi - lo + 1); // words 1437 long table_time_cost = 3; // comparisons 1438 long lookup_space_cost = 3 + 2 * (long) nlabels; 1439 long lookup_time_cost = nlabels; 1440 int opcode = 1441 nlabels > 0 && 1442 table_space_cost + 3 * table_time_cost <= 1443 lookup_space_cost + 3 * lookup_time_cost 1444 ? 1445 tableswitch : lookupswitch; 1446 1447 int startpc = code.curCP(); // the position of the selector operation 1448 code.emitop0(opcode); 1449 code.align(4); 1450 int tableBase = code.curCP(); // the start of the jump table 1451 int[] offsets = null; // a table of offsets for a lookupswitch 1452 code.emit4(-1); // leave space for default offset 1453 if (opcode == tableswitch) { 1454 code.emit4(lo); // minimum label 1455 code.emit4(hi); // maximum label 1456 for (long i = lo; i <= hi; i++) { // leave space for jump table 1457 code.emit4(-1); 1458 } 1459 } else { 1460 code.emit4(nlabels); // number of labels 1461 for (int i = 0; i < nlabels; i++) { 1462 code.emit4(-1); code.emit4(-1); // leave space for lookup table 1463 } 1464 offsets = new int[labels.length]; 1465 } 1466 Code.State stateSwitch = code.state.dup(); 1467 code.markDead(); 1468 1469 // For each case do: 1470 l = cases; 1471 for (int i = 0; i < labels.length; i++) { 1472 JCCase c = l.head; 1473 l = l.tail; 1474 1475 int pc = code.entryPoint(stateSwitch); 1476 // Insert offset directly into code or else into the 1477 // offsets table. 1478 if (i != defaultIndex) { 1479 if (opcode == tableswitch) { 1480 code.put4( 1481 tableBase + 4 * (labels[i] - lo + 3), 1482 pc - startpc); 1483 } else { 1484 offsets[i] = pc - startpc; 1485 } 1486 } else { 1487 code.put4(tableBase, pc - startpc); 1488 } 1489 1490 // Generate code for the statements in this case. 1491 genStats(c.stats, switchEnv, CRT_FLOW_TARGET); 1492 } 1493 1494 if (switchEnv.info.cont != null) { 1495 Assert.check(patternSwitch); 1496 code.resolve(switchEnv.info.cont, switchStart); 1497 } 1498 1499 // Resolve all breaks. 1500 Chain exit = switchEnv.info.exit; 1501 if (exit != null) { 1502 code.resolve(exit); 1503 exit.state.defined.excludeFrom(limit); 1504 } 1505 1506 // If we have not set the default offset, we do so now. 1507 if (code.get4(tableBase) == -1) { 1508 code.put4(tableBase, code.entryPoint(stateSwitch) - startpc); 1509 } 1510 1511 if (opcode == tableswitch) { 1512 // Let any unfilled slots point to the default case. 1513 int defaultOffset = code.get4(tableBase); 1514 for (long i = lo; i <= hi; i++) { 1515 int t = (int)(tableBase + 4 * (i - lo + 3)); 1516 if (code.get4(t) == -1) 1517 code.put4(t, defaultOffset); 1518 } 1519 } else { 1520 // Sort non-default offsets and copy into lookup table. 1521 if (defaultIndex >= 0) 1522 for (int i = defaultIndex; i < labels.length - 1; i++) { 1523 labels[i] = labels[i+1]; 1524 offsets[i] = offsets[i+1]; 1525 } 1526 if (nlabels > 0) 1527 qsort2(labels, offsets, 0, nlabels - 1); 1528 for (int i = 0; i < nlabels; i++) { 1529 int caseidx = tableBase + 8 * (i + 1); 1530 code.put4(caseidx, labels[i]); 1531 code.put4(caseidx + 4, offsets[i]); 1532 } 1533 } 1534 1535 if (swtch instanceof JCSwitchExpression) { 1536 // Emit line position for the end of a switch expression 1537 code.statBegin(TreeInfo.endPos(swtch)); 1538 } 1539 } 1540 code.endScopes(limit); 1541 } 1542 //where 1543 /** Sort (int) arrays of keys and values 1544 */ 1545 static void qsort2(int[] keys, int[] values, int lo, int hi) { 1546 int i = lo; 1547 int j = hi; 1548 int pivot = keys[(i+j)/2]; 1549 do { 1550 while (keys[i] < pivot) i++; 1551 while (pivot < keys[j]) j--; 1552 if (i <= j) { 1553 int temp1 = keys[i]; 1554 keys[i] = keys[j]; 1555 keys[j] = temp1; 1556 int temp2 = values[i]; 1557 values[i] = values[j]; 1558 values[j] = temp2; 1559 i++; 1560 j--; 1561 } 1562 } while (i <= j); 1563 if (lo < j) qsort2(keys, values, lo, j); 1564 if (i < hi) qsort2(keys, values, i, hi); 1565 } 1566 1567 public void visitSynchronized(JCSynchronized tree) { 1568 int limit = code.nextreg; 1569 // Generate code to evaluate lock and save in temporary variable. 1570 final LocalItem lockVar = makeTemp(syms.objectType); 1571 Assert.check(code.isStatementStart()); 1572 genExpr(tree.lock, tree.lock.type).load().duplicate(); 1573 lockVar.store(); 1574 1575 // Generate code to enter monitor. 1576 code.emitop0(monitorenter); 1577 code.state.lock(lockVar.reg); 1578 1579 // Generate code for a try statement with given body, no catch clauses 1580 // in a new environment with the "exit-monitor" operation as finalizer. 1581 final Env<GenContext> syncEnv = env.dup(tree, new GenContext()); 1582 syncEnv.info.finalize = new GenFinalizer() { 1583 void gen() { 1584 genLast(); 1585 Assert.check(syncEnv.info.gaps.length() % 2 == 0); 1586 syncEnv.info.gaps.append(code.curCP()); 1587 } 1588 void genLast() { 1589 if (code.isAlive()) { 1590 lockVar.load(); 1591 code.emitop0(monitorexit); 1592 code.state.unlock(lockVar.reg); 1593 } 1594 } 1595 }; 1596 syncEnv.info.gaps = new ListBuffer<>(); 1597 genTry(tree.body, List.nil(), syncEnv); 1598 code.endScopes(limit); 1599 } 1600 1601 public void visitTry(final JCTry tree) { 1602 // Generate code for a try statement with given body and catch clauses, 1603 // in a new environment which calls the finally block if there is one. 1604 final Env<GenContext> tryEnv = env.dup(tree, new GenContext()); 1605 final Env<GenContext> oldEnv = env; 1606 tryEnv.info.finalize = new GenFinalizer() { 1607 void gen() { 1608 Assert.check(tryEnv.info.gaps.length() % 2 == 0); 1609 tryEnv.info.gaps.append(code.curCP()); 1610 genLast(); 1611 } 1612 void genLast() { 1613 if (tree.finalizer != null) 1614 genStat(tree.finalizer, oldEnv, CRT_BLOCK); 1615 } 1616 boolean hasFinalizer() { 1617 return tree.finalizer != null; 1618 } 1619 1620 @Override 1621 void afterBody() { 1622 if (tree.finalizer != null && (tree.finalizer.flags & BODY_ONLY_FINALIZE) != 0) { 1623 //for body-only finally, remove the GenFinalizer after try body 1624 //so that the finally is not generated to catch bodies: 1625 tryEnv.info.finalize = null; 1626 } 1627 } 1628 1629 }; 1630 tryEnv.info.gaps = new ListBuffer<>(); 1631 genTry(tree.body, tree.catchers, tryEnv); 1632 } 1633 //where 1634 /** Generate code for a try or synchronized statement 1635 * @param body The body of the try or synchronized statement. 1636 * @param catchers The list of catch clauses. 1637 * @param env The current environment of the body. 1638 */ 1639 void genTry(JCTree body, List<JCCatch> catchers, Env<GenContext> env) { 1640 Set<VarSymbol> prevCodeUnsetFields = code.currentUnsetFields; 1641 try { 1642 genTryHelper(body, catchers, env); 1643 } finally { 1644 code.currentUnsetFields = prevCodeUnsetFields; 1645 } 1646 } 1647 1648 void genTryHelper(JCTree body, List<JCCatch> catchers, Env<GenContext> env) { 1649 int limit = code.nextreg; 1650 int startpc = code.curCP(); 1651 Code.State stateTry = code.state.dup(); 1652 genStat(body, env, CRT_BLOCK); 1653 int endpc = code.curCP(); 1654 List<Integer> gaps = env.info.gaps.toList(); 1655 code.statBegin(TreeInfo.endPos(body)); 1656 genFinalizer(env); 1657 code.statBegin(TreeInfo.endPos(env.tree)); 1658 Chain exitChain; 1659 boolean actualTry = env.tree.hasTag(TRY); 1660 if (startpc == endpc && actualTry) { 1661 exitChain = code.branch(dontgoto); 1662 } else { 1663 exitChain = code.branch(goto_); 1664 } 1665 endFinalizerGap(env); 1666 env.info.finalize.afterBody(); 1667 boolean hasFinalizer = 1668 env.info.finalize != null && 1669 env.info.finalize.hasFinalizer(); 1670 if (startpc != endpc) for (List<JCCatch> l = catchers; l.nonEmpty(); l = l.tail) { 1671 // start off with exception on stack 1672 code.entryPoint(stateTry, l.head.param.sym.type); 1673 genCatch(l.head, env, startpc, endpc, gaps); 1674 genFinalizer(env); 1675 if (hasFinalizer || l.tail.nonEmpty()) { 1676 code.statBegin(TreeInfo.endPos(env.tree)); 1677 exitChain = Code.mergeChains(exitChain, 1678 code.branch(goto_)); 1679 } 1680 endFinalizerGap(env); 1681 } 1682 if (hasFinalizer && (startpc != endpc || !actualTry)) { 1683 // Create a new register segment to avoid allocating 1684 // the same variables in finalizers and other statements. 1685 code.newRegSegment(); 1686 1687 // Add a catch-all clause. 1688 1689 // start off with exception on stack 1690 int catchallpc = code.entryPoint(stateTry, syms.throwableType); 1691 1692 // Register all exception ranges for catch all clause. 1693 // The range of the catch all clause is from the beginning 1694 // of the try or synchronized block until the present 1695 // code pointer excluding all gaps in the current 1696 // environment's GenContext. 1697 int startseg = startpc; 1698 while (env.info.gaps.nonEmpty()) { 1699 int endseg = env.info.gaps.next().intValue(); 1700 registerCatch(body.pos(), startseg, endseg, 1701 catchallpc, 0); 1702 startseg = env.info.gaps.next().intValue(); 1703 } 1704 code.statBegin(TreeInfo.finalizerPos(env.tree, PosKind.FIRST_STAT_POS)); 1705 code.markStatBegin(); 1706 1707 Item excVar = makeTemp(syms.throwableType); 1708 excVar.store(); 1709 genFinalizer(env); 1710 code.resolvePending(); 1711 code.statBegin(TreeInfo.finalizerPos(env.tree, PosKind.END_POS)); 1712 code.markStatBegin(); 1713 1714 excVar.load(); 1715 registerCatch(body.pos(), startseg, 1716 env.info.gaps.next().intValue(), 1717 catchallpc, 0); 1718 code.emitop0(athrow); 1719 code.markDead(); 1720 1721 // If there are jsr's to this finalizer, ... 1722 if (env.info.cont != null) { 1723 // Resolve all jsr's. 1724 code.resolve(env.info.cont); 1725 1726 // Mark statement line number 1727 code.statBegin(TreeInfo.finalizerPos(env.tree, PosKind.FIRST_STAT_POS)); 1728 code.markStatBegin(); 1729 1730 // Save return address. 1731 LocalItem retVar = makeTemp(syms.throwableType); 1732 retVar.store(); 1733 1734 // Generate finalizer code. 1735 env.info.finalize.genLast(); 1736 1737 // Return. 1738 code.emitop1w(ret, retVar.reg); 1739 code.markDead(); 1740 } 1741 } 1742 // Resolve all breaks. 1743 code.resolve(exitChain); 1744 1745 code.endScopes(limit); 1746 } 1747 1748 /** Generate code for a catch clause. 1749 * @param tree The catch clause. 1750 * @param env The environment current in the enclosing try. 1751 * @param startpc Start pc of try-block. 1752 * @param endpc End pc of try-block. 1753 */ 1754 void genCatch(JCCatch tree, 1755 Env<GenContext> env, 1756 int startpc, int endpc, 1757 List<Integer> gaps) { 1758 if (startpc != endpc) { 1759 List<Pair<List<Attribute.TypeCompound>, JCExpression>> catchTypeExprs 1760 = catchTypesWithAnnotations(tree); 1761 while (gaps.nonEmpty()) { 1762 for (Pair<List<Attribute.TypeCompound>, JCExpression> subCatch1 : catchTypeExprs) { 1763 JCExpression subCatch = subCatch1.snd; 1764 int catchType = makeRef(tree.pos(), subCatch.type); 1765 int end = gaps.head.intValue(); 1766 registerCatch(tree.pos(), 1767 startpc, end, code.curCP(), 1768 catchType); 1769 for (Attribute.TypeCompound tc : subCatch1.fst) { 1770 tc.position.setCatchInfo(catchType, startpc); 1771 } 1772 } 1773 gaps = gaps.tail; 1774 startpc = gaps.head.intValue(); 1775 gaps = gaps.tail; 1776 } 1777 if (startpc < endpc) { 1778 for (Pair<List<Attribute.TypeCompound>, JCExpression> subCatch1 : catchTypeExprs) { 1779 JCExpression subCatch = subCatch1.snd; 1780 int catchType = makeRef(tree.pos(), subCatch.type); 1781 registerCatch(tree.pos(), 1782 startpc, endpc, code.curCP(), 1783 catchType); 1784 for (Attribute.TypeCompound tc : subCatch1.fst) { 1785 tc.position.setCatchInfo(catchType, startpc); 1786 } 1787 } 1788 } 1789 genCatchBlock(tree, env); 1790 } 1791 } 1792 void genPatternMatchingCatch(JCCatch tree, 1793 Env<GenContext> env, 1794 List<int[]> ranges) { 1795 for (int[] range : ranges) { 1796 JCExpression subCatch = tree.param.vartype; 1797 int catchType = makeRef(tree.pos(), subCatch.type); 1798 registerCatch(tree.pos(), 1799 range[0], range[1], code.curCP(), 1800 catchType); 1801 } 1802 genCatchBlock(tree, env); 1803 } 1804 void genCatchBlock(JCCatch tree, Env<GenContext> env) { 1805 VarSymbol exparam = tree.param.sym; 1806 code.statBegin(tree.pos); 1807 code.markStatBegin(); 1808 int limit = code.nextreg; 1809 code.newLocal(exparam); 1810 items.makeLocalItem(exparam).store(); 1811 code.statBegin(TreeInfo.firstStatPos(tree.body)); 1812 genStat(tree.body, env, CRT_BLOCK); 1813 code.endScopes(limit); 1814 code.statBegin(TreeInfo.endPos(tree.body)); 1815 } 1816 // where 1817 List<Pair<List<Attribute.TypeCompound>, JCExpression>> catchTypesWithAnnotations(JCCatch tree) { 1818 return TreeInfo.isMultiCatch(tree) ? 1819 catchTypesWithAnnotationsFromMulticatch((JCTypeUnion)tree.param.vartype, tree.param.sym.getRawTypeAttributes()) : 1820 List.of(new Pair<>(tree.param.sym.getRawTypeAttributes(), tree.param.vartype)); 1821 } 1822 // where 1823 List<Pair<List<Attribute.TypeCompound>, JCExpression>> catchTypesWithAnnotationsFromMulticatch(JCTypeUnion tree, List<TypeCompound> first) { 1824 List<JCExpression> alts = tree.alternatives; 1825 List<Pair<List<TypeCompound>, JCExpression>> res = List.of(new Pair<>(first, alts.head)); 1826 alts = alts.tail; 1827 1828 while(alts != null && alts.head != null) { 1829 JCExpression alt = alts.head; 1830 if (alt instanceof JCAnnotatedType annotatedType) { 1831 res = res.prepend(new Pair<>(annotate.fromAnnotations(annotatedType.annotations), alt)); 1832 } else { 1833 res = res.prepend(new Pair<>(List.nil(), alt)); 1834 } 1835 alts = alts.tail; 1836 } 1837 return res.reverse(); 1838 } 1839 1840 /** Register a catch clause in the "Exceptions" code-attribute. 1841 */ 1842 void registerCatch(DiagnosticPosition pos, 1843 int startpc, int endpc, 1844 int handler_pc, int catch_type) { 1845 char startpc1 = (char)startpc; 1846 char endpc1 = (char)endpc; 1847 char handler_pc1 = (char)handler_pc; 1848 if (startpc1 == startpc && 1849 endpc1 == endpc && 1850 handler_pc1 == handler_pc) { 1851 code.addCatch(startpc1, endpc1, handler_pc1, 1852 (char)catch_type); 1853 } else { 1854 log.error(pos, Errors.LimitCodeTooLargeForTryStmt); 1855 nerrs++; 1856 } 1857 } 1858 1859 public void visitIf(JCIf tree) { 1860 Set<VarSymbol> prevCodeUnsetFields = code.currentUnsetFields; 1861 try { 1862 visitIfHelper(tree); 1863 } finally { 1864 code.currentUnsetFields = prevCodeUnsetFields; 1865 } 1866 } 1867 1868 public void visitIfHelper(JCIf tree) { 1869 int limit = code.nextreg; 1870 Chain thenExit = null; 1871 Assert.check(code.isStatementStart()); 1872 CondItem c = genCond(TreeInfo.skipParens(tree.cond), 1873 CRT_FLOW_CONTROLLER); 1874 Chain elseChain = c.jumpFalse(); 1875 Assert.check(code.isStatementStart()); 1876 if (!c.isFalse()) { 1877 code.resolve(c.trueJumps); 1878 genStat(tree.thenpart, env, CRT_STATEMENT | CRT_FLOW_TARGET); 1879 thenExit = code.branch(goto_); 1880 } 1881 if (elseChain != null) { 1882 code.resolve(elseChain); 1883 if (tree.elsepart != null) { 1884 genStat(tree.elsepart, env,CRT_STATEMENT | CRT_FLOW_TARGET); 1885 } 1886 } 1887 code.resolve(thenExit); 1888 code.endScopes(limit); 1889 Assert.check(code.isStatementStart()); 1890 } 1891 1892 public void visitExec(JCExpressionStatement tree) { 1893 // Optimize x++ to ++x and x-- to --x. 1894 JCExpression e = tree.expr; 1895 switch (e.getTag()) { 1896 case POSTINC: 1897 ((JCUnary) e).setTag(PREINC); 1898 break; 1899 case POSTDEC: 1900 ((JCUnary) e).setTag(PREDEC); 1901 break; 1902 } 1903 Assert.check(code.isStatementStart()); 1904 genExpr(tree.expr, tree.expr.type).drop(); 1905 Assert.check(code.isStatementStart()); 1906 } 1907 1908 public void visitBreak(JCBreak tree) { 1909 Assert.check(code.isStatementStart()); 1910 final Env<GenContext> targetEnv = unwindBreak(tree.target); 1911 targetEnv.info.addExit(code.branch(goto_)); 1912 endFinalizerGaps(env, targetEnv); 1913 } 1914 1915 public void visitYield(JCYield tree) { 1916 Assert.check(code.isStatementStart()); 1917 final Env<GenContext> targetEnv; 1918 if (inCondSwitchExpression) { 1919 CondItem value = genCond(tree.value, CRT_FLOW_TARGET); 1920 Chain falseJumps = value.jumpFalse(); 1921 1922 code.resolve(value.trueJumps); 1923 Env<GenContext> localEnv = unwindBreak(tree.target); 1924 reloadStackBeforeSwitchExpr(); 1925 Chain trueJumps = code.branch(goto_); 1926 1927 endFinalizerGaps(env, localEnv); 1928 1929 code.resolve(falseJumps); 1930 targetEnv = unwindBreak(tree.target); 1931 reloadStackBeforeSwitchExpr(); 1932 falseJumps = code.branch(goto_); 1933 1934 if (switchExpressionTrueChain == null) { 1935 switchExpressionTrueChain = trueJumps; 1936 } else { 1937 switchExpressionTrueChain = 1938 Code.mergeChains(switchExpressionTrueChain, trueJumps); 1939 } 1940 if (switchExpressionFalseChain == null) { 1941 switchExpressionFalseChain = falseJumps; 1942 } else { 1943 switchExpressionFalseChain = 1944 Code.mergeChains(switchExpressionFalseChain, falseJumps); 1945 } 1946 } else { 1947 genExpr(tree.value, pt).load(); 1948 if (switchResult != null) 1949 switchResult.store(); 1950 1951 targetEnv = unwindBreak(tree.target); 1952 1953 if (code.isAlive()) { 1954 reloadStackBeforeSwitchExpr(); 1955 if (switchResult != null) 1956 switchResult.load(); 1957 1958 code.state.forceStackTop(tree.target.type); 1959 targetEnv.info.addExit(code.branch(goto_)); 1960 code.markDead(); 1961 } 1962 } 1963 endFinalizerGaps(env, targetEnv); 1964 } 1965 //where: 1966 /** As side-effect, might mark code as dead disabling any further emission. 1967 */ 1968 private Env<GenContext> unwindBreak(JCTree target) { 1969 int tmpPos = code.pendingStatPos; 1970 Env<GenContext> targetEnv = unwind(target, env); 1971 code.pendingStatPos = tmpPos; 1972 return targetEnv; 1973 } 1974 1975 private void reloadStackBeforeSwitchExpr() { 1976 for (LocalItem li : stackBeforeSwitchExpression) 1977 li.load(); 1978 } 1979 1980 public void visitContinue(JCContinue tree) { 1981 int tmpPos = code.pendingStatPos; 1982 Env<GenContext> targetEnv = unwind(tree.target, env); 1983 code.pendingStatPos = tmpPos; 1984 Assert.check(code.isStatementStart()); 1985 targetEnv.info.addCont(code.branch(goto_)); 1986 endFinalizerGaps(env, targetEnv); 1987 } 1988 1989 public void visitReturn(JCReturn tree) { 1990 int limit = code.nextreg; 1991 final Env<GenContext> targetEnv; 1992 1993 /* Save and then restore the location of the return in case a finally 1994 * is expanded (with unwind()) in the middle of our bytecodes. 1995 */ 1996 int tmpPos = code.pendingStatPos; 1997 if (tree.expr != null) { 1998 Assert.check(code.isStatementStart()); 1999 Item r = genExpr(tree.expr, pt).load(); 2000 if (hasFinally(env.enclMethod, env)) { 2001 r = makeTemp(pt); 2002 r.store(); 2003 } 2004 targetEnv = unwind(env.enclMethod, env); 2005 code.pendingStatPos = tmpPos; 2006 r.load(); 2007 code.emitop0(ireturn + Code.truncate(Code.typecode(pt))); 2008 } else { 2009 targetEnv = unwind(env.enclMethod, env); 2010 code.pendingStatPos = tmpPos; 2011 code.emitop0(return_); 2012 } 2013 endFinalizerGaps(env, targetEnv); 2014 code.endScopes(limit); 2015 } 2016 2017 public void visitThrow(JCThrow tree) { 2018 Assert.check(code.isStatementStart()); 2019 genExpr(tree.expr, tree.expr.type).load(); 2020 code.emitop0(athrow); 2021 Assert.check(code.isStatementStart()); 2022 } 2023 2024 /* ************************************************************************ 2025 * Visitor methods for expressions 2026 *************************************************************************/ 2027 2028 public void visitApply(JCMethodInvocation tree) { 2029 setTypeAnnotationPositions(tree.pos); 2030 // Generate code for method. 2031 Item m = genExpr(tree.meth, methodType); 2032 // Generate code for all arguments, where the expected types are 2033 // the parameters of the method's external type (that is, any implicit 2034 // outer instance of a super(...) call appears as first parameter). 2035 MethodSymbol msym = (MethodSymbol)TreeInfo.symbol(tree.meth); 2036 genArgs(tree.args, 2037 msym.externalType(types).getParameterTypes()); 2038 if (!msym.isDynamic()) { 2039 code.statBegin(tree.pos); 2040 } 2041 if (patternMatchingCatchConfiguration.invocations().contains(tree)) { 2042 int start = code.curCP(); 2043 result = m.invoke(); 2044 patternMatchingCatchConfiguration.ranges().add(new int[] {start, code.curCP()}); 2045 } else { 2046 if (msym.isConstructor() && TreeInfo.isConstructorCall(tree)) { 2047 //if this is a this(...) or super(...) call, there is a pending 2048 //"uninitialized this" before this call. One catch handler cannot 2049 //handle exceptions that may come from places with "uninitialized this" 2050 //and (initialized) this, hence generate one set of handlers here 2051 //for the "uninitialized this" case, and another set of handlers 2052 //will be generated at the end of the method for the initialized this, 2053 //if needed: 2054 generatePatternMatchingCatch(env); 2055 result = m.invoke(); 2056 patternMatchingCatchConfiguration = 2057 patternMatchingCatchConfiguration.restart(code.state.dup()); 2058 } else { 2059 result = m.invoke(); 2060 } 2061 } 2062 } 2063 2064 public void visitConditional(JCConditional tree) { 2065 Chain thenExit = null; 2066 code.statBegin(tree.cond.pos); 2067 CondItem c = genCond(tree.cond, CRT_FLOW_CONTROLLER); 2068 Chain elseChain = c.jumpFalse(); 2069 if (!c.isFalse()) { 2070 code.resolve(c.trueJumps); 2071 int startpc = genCrt ? code.curCP() : 0; 2072 code.statBegin(tree.truepart.pos); 2073 genExpr(tree.truepart, pt).load(); 2074 code.state.forceStackTop(tree.type); 2075 if (genCrt) code.crt.put(tree.truepart, CRT_FLOW_TARGET, 2076 startpc, code.curCP()); 2077 thenExit = code.branch(goto_); 2078 } 2079 if (elseChain != null) { 2080 code.resolve(elseChain); 2081 int startpc = genCrt ? code.curCP() : 0; 2082 code.statBegin(tree.falsepart.pos); 2083 genExpr(tree.falsepart, pt).load(); 2084 code.state.forceStackTop(tree.type); 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 static class GenContext { 2648 2649 /** A chain for all unresolved jumps that exit the current environment. 2650 */ 2651 Chain exit = null; 2652 2653 /** A chain for all unresolved jumps that continue in the 2654 * current environment. 2655 */ 2656 Chain cont = null; 2657 2658 /** A closure that generates the finalizer of the current environment. 2659 * Only set for Synchronized and Try contexts. 2660 */ 2661 GenFinalizer finalize = null; 2662 2663 /** Is this a switch statement? If so, allocate registers 2664 * even when the variable declaration is unreachable. 2665 */ 2666 boolean isSwitch = false; 2667 2668 /** A list buffer containing all gaps in the finalizer range, 2669 * where a catch all exception should not apply. 2670 */ 2671 ListBuffer<Integer> gaps = null; 2672 2673 /** Add given chain to exit chain. 2674 */ 2675 void addExit(Chain c) { 2676 exit = Code.mergeChains(c, exit); 2677 } 2678 2679 /** Add given chain to cont chain. 2680 */ 2681 void addCont(Chain c) { 2682 cont = Code.mergeChains(c, cont); 2683 } 2684 } 2685 2686 record PatternMatchingCatchConfiguration(Set<JCMethodInvocation> invocations, 2687 ListBuffer<int[]> ranges, 2688 JCCatch handler, 2689 State startState) { 2690 public PatternMatchingCatchConfiguration restart(State newState) { 2691 return new PatternMatchingCatchConfiguration(invocations(), 2692 new ListBuffer<int[]>(), 2693 handler(), 2694 newState); 2695 } 2696 } 2697 }