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