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