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