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