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