1 /* 2 * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.tools.javac.jvm; 27 28 import com.sun.tools.javac.code.*; 29 import com.sun.tools.javac.code.Symbol.*; 30 import com.sun.tools.javac.code.Type.*; 31 import com.sun.tools.javac.jvm.Code.*; 32 import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant; 33 import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant.BasicConstant; 34 import com.sun.tools.javac.tree.JCTree; 35 import com.sun.tools.javac.util.Assert; 36 37 import static com.sun.tools.javac.jvm.ByteCodes.*; 38 39 /** A helper class for code generation. Items are objects 40 * that stand for addressable entities in the bytecode. Each item 41 * supports a fixed protocol for loading the item on the stack, storing 42 * into it, converting it into a jump condition, and several others. 43 * There are many individual forms of items, such as local, static, 44 * indexed, or instance variables, values on the top of stack, the 45 * special values this or super, etc. Individual items are represented as 46 * inner classes in class Items. 47 * 48 * <p><b>This is NOT part of any supported API. 49 * If you write code that depends on this, you do so at your own risk. 50 * This code and its internal interfaces are subject to change or 51 * deletion without notice.</b> 52 */ 53 public class Items { 54 55 /** The current constant pool writer. 56 */ 57 PoolWriter poolWriter; 58 59 /** The current code buffer. 60 */ 61 Code code; 62 63 /** The current symbol table. 64 */ 65 Symtab syms; 66 67 /** Type utilities. */ 68 Types types; 69 70 /** Items that exist only once (flyweight pattern). 71 */ 72 private final Item voidItem; 73 private final Item thisItem; 74 private final Item superItem; 75 private final Item[] stackItem = new Item[TypeCodeCount]; 76 Items(PoolWriter poolWriter, Code code, Symtab syms, Types types)77 public Items(PoolWriter poolWriter, Code code, Symtab syms, Types types) { 78 this.code = code; 79 this.poolWriter = poolWriter; 80 this.types = types; 81 voidItem = new Item(VOIDcode) { 82 public String toString() { return "void"; } 83 }; 84 thisItem = new SelfItem(false); 85 superItem = new SelfItem(true); 86 for (int i = 0; i < VOIDcode; i++) stackItem[i] = new StackItem(i); 87 stackItem[VOIDcode] = voidItem; 88 this.syms = syms; 89 } 90 91 /** Make a void item 92 */ makeVoidItem()93 Item makeVoidItem() { 94 return voidItem; 95 } 96 /** Make an item representing `this'. 97 */ makeThisItem()98 Item makeThisItem() { 99 return thisItem; 100 } 101 102 /** Make an item representing `super'. 103 */ makeSuperItem()104 Item makeSuperItem() { 105 return superItem; 106 } 107 108 /** Make an item representing a value on stack. 109 * @param type The value's type. 110 */ makeStackItem(Type type)111 Item makeStackItem(Type type) { 112 return stackItem[Code.typecode(type)]; 113 } 114 115 /** Make an item representing a dynamically invoked method. 116 * @param member The represented symbol. 117 */ makeDynamicItem(Symbol member)118 Item makeDynamicItem(Symbol member) { 119 return new DynamicItem(member); 120 } 121 122 /** Make an item representing an indexed expression. 123 * @param type The expression's type. 124 */ makeIndexedItem(Type type)125 Item makeIndexedItem(Type type) { 126 return new IndexedItem(type); 127 } 128 129 /** Make an item representing a local variable. 130 * @param v The represented variable. 131 */ makeLocalItem(VarSymbol v)132 LocalItem makeLocalItem(VarSymbol v) { 133 return new LocalItem(v.erasure(types), v.adr); 134 } 135 136 /** Make an item representing a local anonymous variable. 137 * @param type The represented variable's type. 138 * @param reg The represented variable's register. 139 */ makeLocalItem(Type type, int reg)140 private LocalItem makeLocalItem(Type type, int reg) { 141 return new LocalItem(type, reg); 142 } 143 144 /** Make an item representing a static variable or method. 145 * @param member The represented symbol. 146 */ makeStaticItem(Symbol member)147 Item makeStaticItem(Symbol member) { 148 return new StaticItem(member); 149 } 150 151 /** Make an item representing an instance variable or method. 152 * @param member The represented symbol. 153 * @param nonvirtual Is the reference not virtual? (true for constructors 154 * and private members). 155 */ makeMemberItem(Symbol member, boolean nonvirtual)156 Item makeMemberItem(Symbol member, boolean nonvirtual) { 157 return new MemberItem(member, nonvirtual); 158 } 159 160 /** Make an item representing a literal. 161 * @param type The literal's type. 162 * @param value The literal's value. 163 */ makeImmediateItem(Type type, Object value)164 Item makeImmediateItem(Type type, Object value) { 165 return new ImmediateItem(type, value); 166 } 167 168 /** Make an item representing an assignment expression. 169 * @param lhs The item representing the assignment's left hand side. 170 */ makeAssignItem(Item lhs)171 Item makeAssignItem(Item lhs) { 172 return new AssignItem(lhs); 173 } 174 175 /** Make an item representing a conditional or unconditional jump. 176 * @param opcode The jump's opcode. 177 * @param trueJumps A chain encomassing all jumps that can be taken 178 * if the condition evaluates to true. 179 * @param falseJumps A chain encomassing all jumps that can be taken 180 * if the condition evaluates to false. 181 */ makeCondItem(int opcode, Chain trueJumps, Chain falseJumps)182 CondItem makeCondItem(int opcode, Chain trueJumps, Chain falseJumps) { 183 return new CondItem(opcode, trueJumps, falseJumps); 184 } 185 186 /** Make an item representing a conditional or unconditional jump. 187 * @param opcode The jump's opcode. 188 */ makeCondItem(int opcode)189 CondItem makeCondItem(int opcode) { 190 return makeCondItem(opcode, null, null); 191 } 192 193 /** The base class of all items, which implements default behavior. 194 */ 195 abstract class Item { 196 197 /** The type code of values represented by this item. 198 */ 199 int typecode; 200 Item(int typecode)201 Item(int typecode) { 202 this.typecode = typecode; 203 } 204 205 /** Generate code to load this item onto stack. 206 */ load()207 Item load() { 208 throw new AssertionError(); 209 } 210 211 /** Generate code to store top of stack into this item. 212 */ store()213 void store() { 214 throw new AssertionError("store unsupported: " + this); 215 } 216 217 /** Generate code to invoke method represented by this item. 218 */ invoke()219 Item invoke() { 220 throw new AssertionError(this); 221 } 222 223 /** Generate code to use this item twice. 224 */ duplicate()225 void duplicate() {} 226 227 /** Generate code to avoid having to use this item. 228 */ drop()229 void drop() {} 230 231 /** Generate code to stash a copy of top of stack - of typecode toscode - 232 * under this item. 233 */ stash(int toscode)234 void stash(int toscode) { 235 stackItem[toscode].duplicate(); 236 } 237 238 /** Generate code to turn item into a testable condition. 239 */ mkCond()240 CondItem mkCond() { 241 load(); 242 return makeCondItem(ifne); 243 } 244 245 /** Generate code to coerce item to given type code. 246 * @param targetcode The type code to coerce to. 247 */ coerce(int targetcode)248 Item coerce(int targetcode) { 249 if (typecode == targetcode) 250 return this; 251 else { 252 load(); 253 int typecode1 = Code.truncate(typecode); 254 int targetcode1 = Code.truncate(targetcode); 255 if (typecode1 != targetcode1) { 256 int offset = targetcode1 > typecode1 ? targetcode1 - 1 257 : targetcode1; 258 code.emitop0(i2l + typecode1 * 3 + offset); 259 } 260 if (targetcode != targetcode1) { 261 code.emitop0(int2byte + targetcode - BYTEcode); 262 } 263 return stackItem[targetcode]; 264 } 265 } 266 267 /** Generate code to coerce item to given type. 268 * @param targettype The type to coerce to. 269 */ coerce(Type targettype)270 Item coerce(Type targettype) { 271 return coerce(Code.typecode(targettype)); 272 } 273 274 /** Return the width of this item on stack as a number of words. 275 */ width()276 int width() { 277 return 0; 278 } 279 toString()280 public abstract String toString(); 281 } 282 283 /** An item representing a value on stack. 284 */ 285 class StackItem extends Item { 286 StackItem(int typecode)287 StackItem(int typecode) { 288 super(typecode); 289 } 290 load()291 Item load() { 292 return this; 293 } 294 duplicate()295 void duplicate() { 296 code.emitop0(width() == 2 ? dup2 : dup); 297 } 298 drop()299 void drop() { 300 code.emitop0(width() == 2 ? pop2 : pop); 301 } 302 stash(int toscode)303 void stash(int toscode) { 304 code.emitop0( 305 (width() == 2 ? dup_x2 : dup_x1) + 3 * (Code.width(toscode) - 1)); 306 } 307 width()308 int width() { 309 return Code.width(typecode); 310 } 311 toString()312 public String toString() { 313 return "stack(" + typecodeNames[typecode] + ")"; 314 } 315 } 316 317 /** An item representing an indexed expression. 318 */ 319 class IndexedItem extends Item { 320 IndexedItem(Type type)321 IndexedItem(Type type) { 322 super(Code.typecode(type)); 323 } 324 load()325 Item load() { 326 code.emitop0(iaload + typecode); 327 return stackItem[typecode]; 328 } 329 store()330 void store() { 331 code.emitop0(iastore + typecode); 332 } 333 duplicate()334 void duplicate() { 335 code.emitop0(dup2); 336 } 337 drop()338 void drop() { 339 code.emitop0(pop2); 340 } 341 stash(int toscode)342 void stash(int toscode) { 343 code.emitop0(dup_x2 + 3 * (Code.width(toscode) - 1)); 344 } 345 width()346 int width() { 347 return 2; 348 } 349 toString()350 public String toString() { 351 return "indexed(" + ByteCodes.typecodeNames[typecode] + ")"; 352 } 353 } 354 355 /** An item representing `this' or `super'. 356 */ 357 class SelfItem extends Item { 358 359 /** Flag which determines whether this item represents `this' or `super'. 360 */ 361 boolean isSuper; 362 SelfItem(boolean isSuper)363 SelfItem(boolean isSuper) { 364 super(OBJECTcode); 365 this.isSuper = isSuper; 366 } 367 load()368 Item load() { 369 code.emitop0(aload_0); 370 return stackItem[typecode]; 371 } 372 toString()373 public String toString() { 374 return isSuper ? "super" : "this"; 375 } 376 } 377 378 /** An item representing a local variable. 379 */ 380 class LocalItem extends Item { 381 382 /** The variable's register. 383 */ 384 int reg; 385 386 /** The variable's type. 387 */ 388 Type type; 389 LocalItem(Type type, int reg)390 LocalItem(Type type, int reg) { 391 super(Code.typecode(type)); 392 Assert.check(reg >= 0); 393 this.type = type; 394 this.reg = reg; 395 } 396 load()397 Item load() { 398 if (reg <= 3) 399 code.emitop0(iload_0 + Code.truncate(typecode) * 4 + reg); 400 else 401 code.emitop1w(iload + Code.truncate(typecode), reg); 402 return stackItem[typecode]; 403 } 404 store()405 void store() { 406 if (reg <= 3) 407 code.emitop0(istore_0 + Code.truncate(typecode) * 4 + reg); 408 else 409 code.emitop1w(istore + Code.truncate(typecode), reg); 410 code.setDefined(reg); 411 } 412 incr(int x)413 void incr(int x) { 414 if (typecode == INTcode && x >= -32768 && x <= 32767) { 415 code.emitop1w(iinc, reg, x); 416 } else { 417 load(); 418 if (x >= 0) { 419 makeImmediateItem(syms.intType, x).load(); 420 code.emitop0(iadd); 421 } else { 422 makeImmediateItem(syms.intType, -x).load(); 423 code.emitop0(isub); 424 } 425 makeStackItem(syms.intType).coerce(typecode); 426 store(); 427 } 428 } 429 toString()430 public String toString() { 431 return "localItem(type=" + type + "; reg=" + reg + ")"; 432 } 433 } 434 435 /** An item representing a static variable or method. 436 */ 437 class StaticItem extends Item { 438 439 /** The represented symbol. 440 */ 441 Symbol member; 442 StaticItem(Symbol member)443 StaticItem(Symbol member) { 444 super(Code.typecode(member.erasure(types))); 445 this.member = member; 446 } 447 load()448 Item load() { 449 code.emitop2(getstatic, member, PoolWriter::putMember); 450 return stackItem[typecode]; 451 } 452 store()453 void store() { 454 code.emitop2(putstatic, member, PoolWriter::putMember); 455 } 456 invoke()457 Item invoke() { 458 MethodType mtype = (MethodType)member.erasure(types); 459 int rescode = Code.typecode(mtype.restype); 460 code.emitInvokestatic(member, mtype); 461 return stackItem[rescode]; 462 } 463 toString()464 public String toString() { 465 return "static(" + member + ")"; 466 } 467 } 468 469 /** An item representing a dynamic call site. 470 */ 471 class DynamicItem extends StaticItem { DynamicItem(Symbol member)472 DynamicItem(Symbol member) { 473 super(member); 474 } 475 load()476 Item load() { 477 Assert.check(member.kind == Kinds.Kind.VAR); 478 Type type = member.erasure(types); 479 int rescode = Code.typecode(type); 480 code.emitLdc((DynamicVarSymbol)member); 481 return stackItem[rescode]; 482 } 483 store()484 void store() { Assert.error("this method shouldn't be invoked"); } 485 invoke()486 Item invoke() { 487 Assert.check(member.kind == Kinds.Kind.MTH); 488 MethodType mtype = (MethodType)member.erasure(types); 489 int rescode = Code.typecode(mtype.restype); 490 code.emitInvokedynamic((DynamicMethodSymbol)member, mtype); 491 return stackItem[rescode]; 492 } 493 toString()494 public String toString() { 495 return "dynamic(" + member + ")"; 496 } 497 } 498 499 /** An item representing an instance variable or method. 500 */ 501 class MemberItem extends Item { 502 503 /** The represented symbol. 504 */ 505 Symbol member; 506 507 /** Flag that determines whether or not access is virtual. 508 */ 509 boolean nonvirtual; 510 MemberItem(Symbol member, boolean nonvirtual)511 MemberItem(Symbol member, boolean nonvirtual) { 512 super(Code.typecode(member.erasure(types))); 513 this.member = member; 514 this.nonvirtual = nonvirtual; 515 } 516 load()517 Item load() { 518 code.emitop2(getfield, member, PoolWriter::putMember); 519 return stackItem[typecode]; 520 } 521 store()522 void store() { 523 code.emitop2(putfield, member, PoolWriter::putMember); 524 } 525 invoke()526 Item invoke() { 527 MethodType mtype = (MethodType)member.externalType(types); 528 int rescode = Code.typecode(mtype.restype); 529 if ((member.owner.flags() & Flags.INTERFACE) != 0 && !nonvirtual) { 530 code.emitInvokeinterface(member, mtype); 531 } else if (nonvirtual) { 532 code.emitInvokespecial(member, mtype); 533 } else { 534 code.emitInvokevirtual(member, mtype); 535 } 536 return stackItem[rescode]; 537 } 538 duplicate()539 void duplicate() { 540 stackItem[OBJECTcode].duplicate(); 541 } 542 drop()543 void drop() { 544 stackItem[OBJECTcode].drop(); 545 } 546 stash(int toscode)547 void stash(int toscode) { 548 stackItem[OBJECTcode].stash(toscode); 549 } 550 width()551 int width() { 552 return 1; 553 } 554 toString()555 public String toString() { 556 return "member(" + member + (nonvirtual ? " nonvirtual)" : ")"); 557 } 558 } 559 560 /** An item representing a literal. 561 */ 562 class ImmediateItem extends Item { 563 564 /** The literal's value. 565 */ 566 final LoadableConstant value; 567 ImmediateItem(Type type, Object value)568 ImmediateItem(Type type, Object value) { 569 super(Code.typecode(type)); 570 switch (typecode) { 571 case BYTEcode: 572 case SHORTcode: 573 case CHARcode: 574 case INTcode: 575 this.value = LoadableConstant.Int((int)value); 576 break; 577 case LONGcode: 578 this.value = LoadableConstant.Long((long)value); 579 break; 580 case FLOATcode: 581 this.value = LoadableConstant.Float((float)value); 582 break; 583 case DOUBLEcode: 584 this.value = LoadableConstant.Double((double)value); 585 break; 586 case OBJECTcode: 587 this.value = LoadableConstant.String((String)value); 588 break; 589 default: 590 throw new UnsupportedOperationException("unsupported tag: " + typecode); 591 } 592 } 593 ldc()594 private void ldc() { 595 if (typecode == LONGcode || typecode == DOUBLEcode) { 596 code.emitop2(ldc2w, value, PoolWriter::putConstant); 597 } else { 598 code.emitLdc(value); 599 } 600 } 601 numericValue()602 private Number numericValue() { 603 return (Number)((BasicConstant)value).data; 604 } 605 load()606 Item load() { 607 switch (typecode) { 608 case INTcode: case BYTEcode: case SHORTcode: case CHARcode: 609 int ival = numericValue().intValue(); 610 if (-1 <= ival && ival <= 5) 611 code.emitop0(iconst_0 + ival); 612 else if (Byte.MIN_VALUE <= ival && ival <= Byte.MAX_VALUE) 613 code.emitop1(bipush, ival); 614 else if (Short.MIN_VALUE <= ival && ival <= Short.MAX_VALUE) 615 code.emitop2(sipush, ival); 616 else 617 ldc(); 618 break; 619 case LONGcode: 620 long lval = numericValue().longValue(); 621 if (lval == 0 || lval == 1) 622 code.emitop0(lconst_0 + (int)lval); 623 else 624 ldc(); 625 break; 626 case FLOATcode: 627 float fval = numericValue().floatValue(); 628 if (isPosZero(fval) || fval == 1.0 || fval == 2.0) 629 code.emitop0(fconst_0 + (int)fval); 630 else { 631 ldc(); 632 } 633 break; 634 case DOUBLEcode: 635 double dval = numericValue().doubleValue(); 636 if (isPosZero(dval) || dval == 1.0) 637 code.emitop0(dconst_0 + (int)dval); 638 else 639 ldc(); 640 break; 641 case OBJECTcode: 642 ldc(); 643 break; 644 default: 645 Assert.error(); 646 } 647 return stackItem[typecode]; 648 } 649 //where 650 /** Return true iff float number is positive 0. 651 */ isPosZero(float x)652 private boolean isPosZero(float x) { 653 return x == 0.0f && 1.0f / x > 0.0f; 654 } 655 /** Return true iff double number is positive 0. 656 */ isPosZero(double x)657 private boolean isPosZero(double x) { 658 return x == 0.0d && 1.0d / x > 0.0d; 659 } 660 mkCond()661 CondItem mkCond() { 662 int ival = numericValue().intValue(); 663 return makeCondItem(ival != 0 ? goto_ : dontgoto); 664 } 665 coerce(int targetcode)666 Item coerce(int targetcode) { 667 if (typecode == targetcode) { 668 return this; 669 } else { 670 switch (targetcode) { 671 case INTcode: 672 if (Code.truncate(typecode) == INTcode) 673 return this; 674 else 675 return new ImmediateItem( 676 syms.intType, 677 numericValue().intValue()); 678 case LONGcode: 679 return new ImmediateItem( 680 syms.longType, 681 numericValue().longValue()); 682 case FLOATcode: 683 return new ImmediateItem( 684 syms.floatType, 685 numericValue().floatValue()); 686 case DOUBLEcode: 687 return new ImmediateItem( 688 syms.doubleType, 689 numericValue().doubleValue()); 690 case BYTEcode: 691 return new ImmediateItem( 692 syms.byteType, 693 (int)(byte)numericValue().intValue()); 694 case CHARcode: 695 return new ImmediateItem( 696 syms.charType, 697 (int)(char)numericValue().intValue()); 698 case SHORTcode: 699 return new ImmediateItem( 700 syms.shortType, 701 (int)(short)numericValue().intValue()); 702 default: 703 return super.coerce(targetcode); 704 } 705 } 706 } 707 toString()708 public String toString() { 709 return "immediate(" + value + ")"; 710 } 711 } 712 713 /** An item representing an assignment expressions. 714 */ 715 class AssignItem extends Item { 716 717 /** The item representing the assignment's left hand side. 718 */ 719 Item lhs; 720 AssignItem(Item lhs)721 AssignItem(Item lhs) { 722 super(lhs.typecode); 723 this.lhs = lhs; 724 } 725 load()726 Item load() { 727 lhs.stash(typecode); 728 lhs.store(); 729 return stackItem[typecode]; 730 } 731 duplicate()732 void duplicate() { 733 load().duplicate(); 734 } 735 drop()736 void drop() { 737 lhs.store(); 738 } 739 stash(int toscode)740 void stash(int toscode) { 741 Assert.error(); 742 } 743 width()744 int width() { 745 return lhs.width() + Code.width(typecode); 746 } 747 toString()748 public String toString() { 749 return "assign(lhs = " + lhs + ")"; 750 } 751 } 752 753 /** An item representing a conditional or unconditional jump. 754 */ 755 class CondItem extends Item { 756 757 /** A chain encomassing all jumps that can be taken 758 * if the condition evaluates to true. 759 */ 760 Chain trueJumps; 761 762 /** A chain encomassing all jumps that can be taken 763 * if the condition evaluates to false. 764 */ 765 Chain falseJumps; 766 767 /** The jump's opcode. 768 */ 769 int opcode; 770 771 /* 772 * An abstract syntax tree of this item. It is needed 773 * for branch entries in 'CharacterRangeTable' attribute. 774 */ 775 JCTree tree; 776 CondItem(int opcode, Chain truejumps, Chain falsejumps)777 CondItem(int opcode, Chain truejumps, Chain falsejumps) { 778 super(BYTEcode); 779 this.opcode = opcode; 780 this.trueJumps = truejumps; 781 this.falseJumps = falsejumps; 782 } 783 load()784 Item load() { 785 Chain trueChain = null; 786 Chain falseChain = jumpFalse(); 787 if (!isFalse()) { 788 code.resolve(trueJumps); 789 code.emitop0(iconst_1); 790 trueChain = code.branch(goto_); 791 } 792 if (falseChain != null) { 793 code.resolve(falseChain); 794 code.emitop0(iconst_0); 795 } 796 code.resolve(trueChain); 797 return stackItem[typecode]; 798 } 799 duplicate()800 void duplicate() { 801 load().duplicate(); 802 } 803 drop()804 void drop() { 805 load().drop(); 806 } 807 stash(int toscode)808 void stash(int toscode) { 809 Assert.error(); 810 } 811 mkCond()812 CondItem mkCond() { 813 return this; 814 } 815 jumpTrue()816 Chain jumpTrue() { 817 if (tree == null) return Code.mergeChains(trueJumps, code.branch(opcode)); 818 // we should proceed further in -Xjcov mode only 819 int startpc = code.curCP(); 820 Chain c = Code.mergeChains(trueJumps, code.branch(opcode)); 821 code.crt.put(tree, CRTable.CRT_BRANCH_TRUE, startpc, code.curCP()); 822 return c; 823 } 824 jumpFalse()825 Chain jumpFalse() { 826 if (tree == null) return Code.mergeChains(falseJumps, code.branch(Code.negate(opcode))); 827 // we should proceed further in -Xjcov mode only 828 int startpc = code.curCP(); 829 Chain c = Code.mergeChains(falseJumps, code.branch(Code.negate(opcode))); 830 code.crt.put(tree, CRTable.CRT_BRANCH_FALSE, startpc, code.curCP()); 831 return c; 832 } 833 negate()834 CondItem negate() { 835 CondItem c = new CondItem(Code.negate(opcode), falseJumps, trueJumps); 836 c.tree = tree; 837 return c; 838 } 839 width()840 int width() { 841 // a CondItem doesn't have a size on the stack per se. 842 throw new AssertionError(); 843 } 844 isTrue()845 boolean isTrue() { 846 return falseJumps == null && opcode == goto_; 847 } 848 isFalse()849 boolean isFalse() { 850 return trueJumps == null && opcode == dontgoto; 851 } 852 toString()853 public String toString() { 854 return "cond(" + Code.mnem(opcode) + ")"; 855 } 856 } 857 } 858