aoqi@0: /* aoqi@0: * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. aoqi@0: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. aoqi@0: * aoqi@0: * This code is free software; you can redistribute it and/or modify it aoqi@0: * under the terms of the GNU General Public License version 2 only, as aoqi@0: * published by the Free Software Foundation. Oracle designates this aoqi@0: * particular file as subject to the "Classpath" exception as provided aoqi@0: * by Oracle in the LICENSE file that accompanied this code. aoqi@0: * aoqi@0: * This code is distributed in the hope that it will be useful, but WITHOUT aoqi@0: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or aoqi@0: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License aoqi@0: * version 2 for more details (a copy is included in the LICENSE file that aoqi@0: * accompanied this code). aoqi@0: * aoqi@0: * You should have received a copy of the GNU General Public License version aoqi@0: * 2 along with this work; if not, write to the Free Software Foundation, aoqi@0: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. aoqi@0: * aoqi@0: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA aoqi@0: * or visit www.oracle.com if you need additional information or have any aoqi@0: * questions. aoqi@0: */ aoqi@0: aoqi@0: package com.sun.tools.javac.jvm; aoqi@0: aoqi@0: import com.sun.tools.javac.code.*; aoqi@0: import com.sun.tools.javac.code.Symbol.*; aoqi@0: import com.sun.tools.javac.code.Type.*; aoqi@0: import com.sun.tools.javac.jvm.Code.*; aoqi@0: import com.sun.tools.javac.tree.JCTree; aoqi@0: import com.sun.tools.javac.util.Assert; aoqi@0: aoqi@0: import static com.sun.tools.javac.jvm.ByteCodes.*; aoqi@0: aoqi@0: /** A helper class for code generation. Items are objects aoqi@0: * that stand for addressable entities in the bytecode. Each item aoqi@0: * supports a fixed protocol for loading the item on the stack, storing aoqi@0: * into it, converting it into a jump condition, and several others. aoqi@0: * There are many individual forms of items, such as local, static, aoqi@0: * indexed, or instance variables, values on the top of stack, the aoqi@0: * special values this or super, etc. Individual items are represented as aoqi@0: * inner classes in class Items. aoqi@0: * aoqi@0: *

This is NOT part of any supported API. aoqi@0: * If you write code that depends on this, you do so at your own risk. aoqi@0: * This code and its internal interfaces are subject to change or aoqi@0: * deletion without notice. aoqi@0: */ aoqi@0: public class Items { aoqi@0: aoqi@0: /** The current constant pool. aoqi@0: */ aoqi@0: Pool pool; aoqi@0: aoqi@0: /** The current code buffer. aoqi@0: */ aoqi@0: Code code; aoqi@0: aoqi@0: /** The current symbol table. aoqi@0: */ aoqi@0: Symtab syms; aoqi@0: aoqi@0: /** Type utilities. */ aoqi@0: Types types; aoqi@0: aoqi@0: /** Items that exist only once (flyweight pattern). aoqi@0: */ aoqi@0: private final Item voidItem; aoqi@0: private final Item thisItem; aoqi@0: private final Item superItem; aoqi@0: private final Item[] stackItem = new Item[TypeCodeCount]; aoqi@0: aoqi@0: public Items(Pool pool, Code code, Symtab syms, Types types) { aoqi@0: this.code = code; aoqi@0: this.pool = pool; aoqi@0: this.types = types; aoqi@0: voidItem = new Item(VOIDcode) { aoqi@0: public String toString() { return "void"; } aoqi@0: }; aoqi@0: thisItem = new SelfItem(false); aoqi@0: superItem = new SelfItem(true); aoqi@0: for (int i = 0; i < VOIDcode; i++) stackItem[i] = new StackItem(i); aoqi@0: stackItem[VOIDcode] = voidItem; aoqi@0: this.syms = syms; aoqi@0: } aoqi@0: aoqi@0: /** Make a void item aoqi@0: */ aoqi@0: Item makeVoidItem() { aoqi@0: return voidItem; aoqi@0: } aoqi@0: /** Make an item representing `this'. aoqi@0: */ aoqi@0: Item makeThisItem() { aoqi@0: return thisItem; aoqi@0: } aoqi@0: aoqi@0: /** Make an item representing `super'. aoqi@0: */ aoqi@0: Item makeSuperItem() { aoqi@0: return superItem; aoqi@0: } aoqi@0: aoqi@0: /** Make an item representing a value on stack. aoqi@0: * @param type The value's type. aoqi@0: */ aoqi@0: Item makeStackItem(Type type) { aoqi@0: return stackItem[Code.typecode(type)]; aoqi@0: } aoqi@0: aoqi@0: /** Make an item representing a dynamically invoked method. aoqi@0: * @param member The represented symbol. aoqi@0: */ aoqi@0: Item makeDynamicItem(Symbol member) { aoqi@0: return new DynamicItem(member); aoqi@0: } aoqi@0: aoqi@0: /** Make an item representing an indexed expression. aoqi@0: * @param type The expression's type. aoqi@0: */ aoqi@0: Item makeIndexedItem(Type type) { aoqi@0: return new IndexedItem(type); aoqi@0: } aoqi@0: aoqi@0: /** Make an item representing a local variable. aoqi@0: * @param v The represented variable. aoqi@0: */ aoqi@0: LocalItem makeLocalItem(VarSymbol v) { aoqi@0: return new LocalItem(v.erasure(types), v.adr); aoqi@0: } aoqi@0: aoqi@0: /** Make an item representing a local anonymous variable. aoqi@0: * @param type The represented variable's type. aoqi@0: * @param reg The represented variable's register. aoqi@0: */ aoqi@0: private LocalItem makeLocalItem(Type type, int reg) { aoqi@0: return new LocalItem(type, reg); aoqi@0: } aoqi@0: aoqi@0: /** Make an item representing a static variable or method. aoqi@0: * @param member The represented symbol. aoqi@0: */ aoqi@0: Item makeStaticItem(Symbol member) { aoqi@0: return new StaticItem(member); aoqi@0: } aoqi@0: aoqi@0: /** Make an item representing an instance variable or method. aoqi@0: * @param member The represented symbol. aoqi@0: * @param nonvirtual Is the reference not virtual? (true for constructors aoqi@0: * and private members). aoqi@0: */ aoqi@0: Item makeMemberItem(Symbol member, boolean nonvirtual) { aoqi@0: return new MemberItem(member, nonvirtual); aoqi@0: } aoqi@0: aoqi@0: /** Make an item representing a literal. aoqi@0: * @param type The literal's type. aoqi@0: * @param value The literal's value. aoqi@0: */ aoqi@0: Item makeImmediateItem(Type type, Object value) { aoqi@0: return new ImmediateItem(type, value); aoqi@0: } aoqi@0: aoqi@0: /** Make an item representing an assignment expression. aoqi@0: * @param lhs The item representing the assignment's left hand side. aoqi@0: */ aoqi@0: Item makeAssignItem(Item lhs) { aoqi@0: return new AssignItem(lhs); aoqi@0: } aoqi@0: aoqi@0: /** Make an item representing a conditional or unconditional jump. aoqi@0: * @param opcode The jump's opcode. aoqi@0: * @param trueJumps A chain encomassing all jumps that can be taken aoqi@0: * if the condition evaluates to true. aoqi@0: * @param falseJumps A chain encomassing all jumps that can be taken aoqi@0: * if the condition evaluates to false. aoqi@0: */ aoqi@0: CondItem makeCondItem(int opcode, Chain trueJumps, Chain falseJumps) { aoqi@0: return new CondItem(opcode, trueJumps, falseJumps); aoqi@0: } aoqi@0: aoqi@0: /** Make an item representing a conditional or unconditional jump. aoqi@0: * @param opcode The jump's opcode. aoqi@0: */ aoqi@0: CondItem makeCondItem(int opcode) { aoqi@0: return makeCondItem(opcode, null, null); aoqi@0: } aoqi@0: aoqi@0: /** The base class of all items, which implements default behavior. aoqi@0: */ aoqi@0: abstract class Item { aoqi@0: aoqi@0: /** The type code of values represented by this item. aoqi@0: */ aoqi@0: int typecode; aoqi@0: aoqi@0: Item(int typecode) { aoqi@0: this.typecode = typecode; aoqi@0: } aoqi@0: aoqi@0: /** Generate code to load this item onto stack. aoqi@0: */ aoqi@0: Item load() { aoqi@0: throw new AssertionError(); aoqi@0: } aoqi@0: aoqi@0: /** Generate code to store top of stack into this item. aoqi@0: */ aoqi@0: void store() { aoqi@0: throw new AssertionError("store unsupported: " + this); aoqi@0: } aoqi@0: aoqi@0: /** Generate code to invoke method represented by this item. aoqi@0: */ aoqi@0: Item invoke() { aoqi@0: throw new AssertionError(this); aoqi@0: } aoqi@0: aoqi@0: /** Generate code to use this item twice. aoqi@0: */ aoqi@0: void duplicate() {} aoqi@0: aoqi@0: /** Generate code to avoid having to use this item. aoqi@0: */ aoqi@0: void drop() {} aoqi@0: aoqi@0: /** Generate code to stash a copy of top of stack - of typecode toscode - aoqi@0: * under this item. aoqi@0: */ aoqi@0: void stash(int toscode) { aoqi@0: stackItem[toscode].duplicate(); aoqi@0: } aoqi@0: aoqi@0: /** Generate code to turn item into a testable condition. aoqi@0: */ aoqi@0: CondItem mkCond() { aoqi@0: load(); aoqi@0: return makeCondItem(ifne); aoqi@0: } aoqi@0: aoqi@0: /** Generate code to coerce item to given type code. aoqi@0: * @param targetcode The type code to coerce to. aoqi@0: */ aoqi@0: Item coerce(int targetcode) { aoqi@0: if (typecode == targetcode) aoqi@0: return this; aoqi@0: else { aoqi@0: load(); aoqi@0: int typecode1 = Code.truncate(typecode); aoqi@0: int targetcode1 = Code.truncate(targetcode); aoqi@0: if (typecode1 != targetcode1) { aoqi@0: int offset = targetcode1 > typecode1 ? targetcode1 - 1 aoqi@0: : targetcode1; aoqi@0: code.emitop0(i2l + typecode1 * 3 + offset); aoqi@0: } aoqi@0: if (targetcode != targetcode1) { aoqi@0: code.emitop0(int2byte + targetcode - BYTEcode); aoqi@0: } aoqi@0: return stackItem[targetcode]; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** Generate code to coerce item to given type. aoqi@0: * @param targettype The type to coerce to. aoqi@0: */ aoqi@0: Item coerce(Type targettype) { aoqi@0: return coerce(Code.typecode(targettype)); aoqi@0: } aoqi@0: aoqi@0: /** Return the width of this item on stack as a number of words. aoqi@0: */ aoqi@0: int width() { aoqi@0: return 0; aoqi@0: } aoqi@0: aoqi@0: public abstract String toString(); aoqi@0: } aoqi@0: aoqi@0: /** An item representing a value on stack. aoqi@0: */ aoqi@0: class StackItem extends Item { aoqi@0: aoqi@0: StackItem(int typecode) { aoqi@0: super(typecode); aoqi@0: } aoqi@0: aoqi@0: Item load() { aoqi@0: return this; aoqi@0: } aoqi@0: aoqi@0: void duplicate() { aoqi@0: code.emitop0(width() == 2 ? dup2 : dup); aoqi@0: } aoqi@0: aoqi@0: void drop() { aoqi@0: code.emitop0(width() == 2 ? pop2 : pop); aoqi@0: } aoqi@0: aoqi@0: void stash(int toscode) { aoqi@0: code.emitop0( aoqi@0: (width() == 2 ? dup_x2 : dup_x1) + 3 * (Code.width(toscode) - 1)); aoqi@0: } aoqi@0: aoqi@0: int width() { aoqi@0: return Code.width(typecode); aoqi@0: } aoqi@0: aoqi@0: public String toString() { aoqi@0: return "stack(" + typecodeNames[typecode] + ")"; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** An item representing an indexed expression. aoqi@0: */ aoqi@0: class IndexedItem extends Item { aoqi@0: aoqi@0: IndexedItem(Type type) { aoqi@0: super(Code.typecode(type)); aoqi@0: } aoqi@0: aoqi@0: Item load() { aoqi@0: code.emitop0(iaload + typecode); aoqi@0: return stackItem[typecode]; aoqi@0: } aoqi@0: aoqi@0: void store() { aoqi@0: code.emitop0(iastore + typecode); aoqi@0: } aoqi@0: aoqi@0: void duplicate() { aoqi@0: code.emitop0(dup2); aoqi@0: } aoqi@0: aoqi@0: void drop() { aoqi@0: code.emitop0(pop2); aoqi@0: } aoqi@0: aoqi@0: void stash(int toscode) { aoqi@0: code.emitop0(dup_x2 + 3 * (Code.width(toscode) - 1)); aoqi@0: } aoqi@0: aoqi@0: int width() { aoqi@0: return 2; aoqi@0: } aoqi@0: aoqi@0: public String toString() { aoqi@0: return "indexed(" + ByteCodes.typecodeNames[typecode] + ")"; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** An item representing `this' or `super'. aoqi@0: */ aoqi@0: class SelfItem extends Item { aoqi@0: aoqi@0: /** Flag which determines whether this item represents `this' or `super'. aoqi@0: */ aoqi@0: boolean isSuper; aoqi@0: aoqi@0: SelfItem(boolean isSuper) { aoqi@0: super(OBJECTcode); aoqi@0: this.isSuper = isSuper; aoqi@0: } aoqi@0: aoqi@0: Item load() { aoqi@0: code.emitop0(aload_0); aoqi@0: return stackItem[typecode]; aoqi@0: } aoqi@0: aoqi@0: public String toString() { aoqi@0: return isSuper ? "super" : "this"; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** An item representing a local variable. aoqi@0: */ aoqi@0: class LocalItem extends Item { aoqi@0: aoqi@0: /** The variable's register. aoqi@0: */ aoqi@0: int reg; aoqi@0: aoqi@0: /** The variable's type. aoqi@0: */ aoqi@0: Type type; aoqi@0: aoqi@0: LocalItem(Type type, int reg) { aoqi@0: super(Code.typecode(type)); aoqi@0: Assert.check(reg >= 0); aoqi@0: this.type = type; aoqi@0: this.reg = reg; aoqi@0: } aoqi@0: aoqi@0: Item load() { aoqi@0: if (reg <= 3) aoqi@0: code.emitop0(iload_0 + Code.truncate(typecode) * 4 + reg); aoqi@0: else aoqi@0: code.emitop1w(iload + Code.truncate(typecode), reg); aoqi@0: return stackItem[typecode]; aoqi@0: } aoqi@0: aoqi@0: void store() { aoqi@0: if (reg <= 3) aoqi@0: code.emitop0(istore_0 + Code.truncate(typecode) * 4 + reg); aoqi@0: else aoqi@0: code.emitop1w(istore + Code.truncate(typecode), reg); aoqi@0: code.setDefined(reg); aoqi@0: } aoqi@0: aoqi@0: void incr(int x) { aoqi@0: if (typecode == INTcode && x >= -32768 && x <= 32767) { aoqi@0: code.emitop1w(iinc, reg, x); aoqi@0: } else { aoqi@0: load(); aoqi@0: if (x >= 0) { aoqi@0: makeImmediateItem(syms.intType, x).load(); aoqi@0: code.emitop0(iadd); aoqi@0: } else { aoqi@0: makeImmediateItem(syms.intType, -x).load(); aoqi@0: code.emitop0(isub); aoqi@0: } aoqi@0: makeStackItem(syms.intType).coerce(typecode); aoqi@0: store(); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: public String toString() { aoqi@0: return "localItem(type=" + type + "; reg=" + reg + ")"; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** An item representing a static variable or method. aoqi@0: */ aoqi@0: class StaticItem extends Item { aoqi@0: aoqi@0: /** The represented symbol. aoqi@0: */ aoqi@0: Symbol member; aoqi@0: aoqi@0: StaticItem(Symbol member) { aoqi@0: super(Code.typecode(member.erasure(types))); aoqi@0: this.member = member; aoqi@0: } aoqi@0: aoqi@0: Item load() { aoqi@0: code.emitop2(getstatic, pool.put(member)); aoqi@0: return stackItem[typecode]; aoqi@0: } aoqi@0: aoqi@0: void store() { aoqi@0: code.emitop2(putstatic, pool.put(member)); aoqi@0: } aoqi@0: aoqi@0: Item invoke() { aoqi@0: MethodType mtype = (MethodType)member.erasure(types); aoqi@0: int rescode = Code.typecode(mtype.restype); aoqi@0: code.emitInvokestatic(pool.put(member), mtype); aoqi@0: return stackItem[rescode]; aoqi@0: } aoqi@0: aoqi@0: public String toString() { aoqi@0: return "static(" + member + ")"; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** An item representing a dynamic call site. aoqi@0: */ aoqi@0: class DynamicItem extends StaticItem { aoqi@0: DynamicItem(Symbol member) { aoqi@0: super(member); aoqi@0: } aoqi@0: aoqi@0: Item load() { aoqi@0: assert false; aoqi@0: return null; aoqi@0: } aoqi@0: aoqi@0: void store() { aoqi@0: assert false; aoqi@0: } aoqi@0: aoqi@0: Item invoke() { aoqi@0: // assert target.hasNativeInvokeDynamic(); aoqi@0: MethodType mtype = (MethodType)member.erasure(types); aoqi@0: int rescode = Code.typecode(mtype.restype); aoqi@0: code.emitInvokedynamic(pool.put(member), mtype); aoqi@0: return stackItem[rescode]; aoqi@0: } aoqi@0: aoqi@0: public String toString() { aoqi@0: return "dynamic(" + member + ")"; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** An item representing an instance variable or method. aoqi@0: */ aoqi@0: class MemberItem extends Item { aoqi@0: aoqi@0: /** The represented symbol. aoqi@0: */ aoqi@0: Symbol member; aoqi@0: aoqi@0: /** Flag that determines whether or not access is virtual. aoqi@0: */ aoqi@0: boolean nonvirtual; aoqi@0: aoqi@0: MemberItem(Symbol member, boolean nonvirtual) { aoqi@0: super(Code.typecode(member.erasure(types))); aoqi@0: this.member = member; aoqi@0: this.nonvirtual = nonvirtual; aoqi@0: } aoqi@0: aoqi@0: Item load() { aoqi@0: code.emitop2(getfield, pool.put(member)); aoqi@0: return stackItem[typecode]; aoqi@0: } aoqi@0: aoqi@0: void store() { aoqi@0: code.emitop2(putfield, pool.put(member)); aoqi@0: } aoqi@0: aoqi@0: Item invoke() { aoqi@0: MethodType mtype = (MethodType)member.externalType(types); aoqi@0: int rescode = Code.typecode(mtype.restype); aoqi@0: if ((member.owner.flags() & Flags.INTERFACE) != 0 && !nonvirtual) { aoqi@0: code.emitInvokeinterface(pool.put(member), mtype); aoqi@0: } else if (nonvirtual) { aoqi@0: code.emitInvokespecial(pool.put(member), mtype); aoqi@0: } else { aoqi@0: code.emitInvokevirtual(pool.put(member), mtype); aoqi@0: } aoqi@0: return stackItem[rescode]; aoqi@0: } aoqi@0: aoqi@0: void duplicate() { aoqi@0: stackItem[OBJECTcode].duplicate(); aoqi@0: } aoqi@0: aoqi@0: void drop() { aoqi@0: stackItem[OBJECTcode].drop(); aoqi@0: } aoqi@0: aoqi@0: void stash(int toscode) { aoqi@0: stackItem[OBJECTcode].stash(toscode); aoqi@0: } aoqi@0: aoqi@0: int width() { aoqi@0: return 1; aoqi@0: } aoqi@0: aoqi@0: public String toString() { aoqi@0: return "member(" + member + (nonvirtual ? " nonvirtual)" : ")"); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** An item representing a literal. aoqi@0: */ aoqi@0: class ImmediateItem extends Item { aoqi@0: aoqi@0: /** The literal's value. aoqi@0: */ aoqi@0: Object value; aoqi@0: aoqi@0: ImmediateItem(Type type, Object value) { aoqi@0: super(Code.typecode(type)); aoqi@0: this.value = value; aoqi@0: } aoqi@0: aoqi@0: private void ldc() { aoqi@0: int idx = pool.put(value); aoqi@0: if (typecode == LONGcode || typecode == DOUBLEcode) { aoqi@0: code.emitop2(ldc2w, idx); aoqi@0: } else { aoqi@0: code.emitLdc(idx); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: Item load() { aoqi@0: switch (typecode) { aoqi@0: case INTcode: case BYTEcode: case SHORTcode: case CHARcode: aoqi@0: int ival = ((Number)value).intValue(); aoqi@0: if (-1 <= ival && ival <= 5) aoqi@0: code.emitop0(iconst_0 + ival); aoqi@0: else if (Byte.MIN_VALUE <= ival && ival <= Byte.MAX_VALUE) aoqi@0: code.emitop1(bipush, ival); aoqi@0: else if (Short.MIN_VALUE <= ival && ival <= Short.MAX_VALUE) aoqi@0: code.emitop2(sipush, ival); aoqi@0: else aoqi@0: ldc(); aoqi@0: break; aoqi@0: case LONGcode: aoqi@0: long lval = ((Number)value).longValue(); aoqi@0: if (lval == 0 || lval == 1) aoqi@0: code.emitop0(lconst_0 + (int)lval); aoqi@0: else aoqi@0: ldc(); aoqi@0: break; aoqi@0: case FLOATcode: aoqi@0: float fval = ((Number)value).floatValue(); aoqi@0: if (isPosZero(fval) || fval == 1.0 || fval == 2.0) aoqi@0: code.emitop0(fconst_0 + (int)fval); aoqi@0: else { aoqi@0: ldc(); aoqi@0: } aoqi@0: break; aoqi@0: case DOUBLEcode: aoqi@0: double dval = ((Number)value).doubleValue(); aoqi@0: if (isPosZero(dval) || dval == 1.0) aoqi@0: code.emitop0(dconst_0 + (int)dval); aoqi@0: else aoqi@0: ldc(); aoqi@0: break; aoqi@0: case OBJECTcode: aoqi@0: ldc(); aoqi@0: break; aoqi@0: default: aoqi@0: Assert.error(); aoqi@0: } aoqi@0: return stackItem[typecode]; aoqi@0: } aoqi@0: //where aoqi@0: /** Return true iff float number is positive 0. aoqi@0: */ aoqi@0: private boolean isPosZero(float x) { aoqi@0: return x == 0.0f && 1.0f / x > 0.0f; aoqi@0: } aoqi@0: /** Return true iff double number is positive 0. aoqi@0: */ aoqi@0: private boolean isPosZero(double x) { aoqi@0: return x == 0.0d && 1.0d / x > 0.0d; aoqi@0: } aoqi@0: aoqi@0: CondItem mkCond() { aoqi@0: int ival = ((Number)value).intValue(); aoqi@0: return makeCondItem(ival != 0 ? goto_ : dontgoto); aoqi@0: } aoqi@0: aoqi@0: Item coerce(int targetcode) { aoqi@0: if (typecode == targetcode) { aoqi@0: return this; aoqi@0: } else { aoqi@0: switch (targetcode) { aoqi@0: case INTcode: aoqi@0: if (Code.truncate(typecode) == INTcode) aoqi@0: return this; aoqi@0: else aoqi@0: return new ImmediateItem( aoqi@0: syms.intType, aoqi@0: ((Number)value).intValue()); aoqi@0: case LONGcode: aoqi@0: return new ImmediateItem( aoqi@0: syms.longType, aoqi@0: ((Number)value).longValue()); aoqi@0: case FLOATcode: aoqi@0: return new ImmediateItem( aoqi@0: syms.floatType, aoqi@0: ((Number)value).floatValue()); aoqi@0: case DOUBLEcode: aoqi@0: return new ImmediateItem( aoqi@0: syms.doubleType, aoqi@0: ((Number)value).doubleValue()); aoqi@0: case BYTEcode: aoqi@0: return new ImmediateItem( aoqi@0: syms.byteType, aoqi@0: (int)(byte)((Number)value).intValue()); aoqi@0: case CHARcode: aoqi@0: return new ImmediateItem( aoqi@0: syms.charType, aoqi@0: (int)(char)((Number)value).intValue()); aoqi@0: case SHORTcode: aoqi@0: return new ImmediateItem( aoqi@0: syms.shortType, aoqi@0: (int)(short)((Number)value).intValue()); aoqi@0: default: aoqi@0: return super.coerce(targetcode); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: public String toString() { aoqi@0: return "immediate(" + value + ")"; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** An item representing an assignment expressions. aoqi@0: */ aoqi@0: class AssignItem extends Item { aoqi@0: aoqi@0: /** The item representing the assignment's left hand side. aoqi@0: */ aoqi@0: Item lhs; aoqi@0: aoqi@0: AssignItem(Item lhs) { aoqi@0: super(lhs.typecode); aoqi@0: this.lhs = lhs; aoqi@0: } aoqi@0: aoqi@0: Item load() { aoqi@0: lhs.stash(typecode); aoqi@0: lhs.store(); aoqi@0: return stackItem[typecode]; aoqi@0: } aoqi@0: aoqi@0: void duplicate() { aoqi@0: load().duplicate(); aoqi@0: } aoqi@0: aoqi@0: void drop() { aoqi@0: lhs.store(); aoqi@0: } aoqi@0: aoqi@0: void stash(int toscode) { aoqi@0: Assert.error(); aoqi@0: } aoqi@0: aoqi@0: int width() { aoqi@0: return lhs.width() + Code.width(typecode); aoqi@0: } aoqi@0: aoqi@0: public String toString() { aoqi@0: return "assign(lhs = " + lhs + ")"; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** An item representing a conditional or unconditional jump. aoqi@0: */ aoqi@0: class CondItem extends Item { aoqi@0: aoqi@0: /** A chain encomassing all jumps that can be taken aoqi@0: * if the condition evaluates to true. aoqi@0: */ aoqi@0: Chain trueJumps; aoqi@0: aoqi@0: /** A chain encomassing all jumps that can be taken aoqi@0: * if the condition evaluates to false. aoqi@0: */ aoqi@0: Chain falseJumps; aoqi@0: aoqi@0: /** The jump's opcode. aoqi@0: */ aoqi@0: int opcode; aoqi@0: aoqi@0: /* aoqi@0: * An abstract syntax tree of this item. It is needed aoqi@0: * for branch entries in 'CharacterRangeTable' attribute. aoqi@0: */ aoqi@0: JCTree tree; aoqi@0: aoqi@0: CondItem(int opcode, Chain truejumps, Chain falsejumps) { aoqi@0: super(BYTEcode); aoqi@0: this.opcode = opcode; aoqi@0: this.trueJumps = truejumps; aoqi@0: this.falseJumps = falsejumps; aoqi@0: } aoqi@0: aoqi@0: Item load() { aoqi@0: Chain trueChain = null; aoqi@0: Chain falseChain = jumpFalse(); aoqi@0: if (!isFalse()) { aoqi@0: code.resolve(trueJumps); aoqi@0: code.emitop0(iconst_1); aoqi@0: trueChain = code.branch(goto_); aoqi@0: } aoqi@0: if (falseChain != null) { aoqi@0: code.resolve(falseChain); aoqi@0: code.emitop0(iconst_0); aoqi@0: } aoqi@0: code.resolve(trueChain); aoqi@0: return stackItem[typecode]; aoqi@0: } aoqi@0: aoqi@0: void duplicate() { aoqi@0: load().duplicate(); aoqi@0: } aoqi@0: aoqi@0: void drop() { aoqi@0: load().drop(); aoqi@0: } aoqi@0: aoqi@0: void stash(int toscode) { aoqi@0: Assert.error(); aoqi@0: } aoqi@0: aoqi@0: CondItem mkCond() { aoqi@0: return this; aoqi@0: } aoqi@0: aoqi@0: Chain jumpTrue() { aoqi@0: if (tree == null) return Code.mergeChains(trueJumps, code.branch(opcode)); aoqi@0: // we should proceed further in -Xjcov mode only aoqi@0: int startpc = code.curCP(); aoqi@0: Chain c = Code.mergeChains(trueJumps, code.branch(opcode)); aoqi@0: code.crt.put(tree, CRTable.CRT_BRANCH_TRUE, startpc, code.curCP()); aoqi@0: return c; aoqi@0: } aoqi@0: aoqi@0: Chain jumpFalse() { aoqi@0: if (tree == null) return Code.mergeChains(falseJumps, code.branch(Code.negate(opcode))); aoqi@0: // we should proceed further in -Xjcov mode only aoqi@0: int startpc = code.curCP(); aoqi@0: Chain c = Code.mergeChains(falseJumps, code.branch(Code.negate(opcode))); aoqi@0: code.crt.put(tree, CRTable.CRT_BRANCH_FALSE, startpc, code.curCP()); aoqi@0: return c; aoqi@0: } aoqi@0: aoqi@0: CondItem negate() { aoqi@0: CondItem c = new CondItem(Code.negate(opcode), falseJumps, trueJumps); aoqi@0: c.tree = tree; aoqi@0: return c; aoqi@0: } aoqi@0: aoqi@0: int width() { aoqi@0: // a CondItem doesn't have a size on the stack per se. aoqi@0: throw new AssertionError(); aoqi@0: } aoqi@0: aoqi@0: boolean isTrue() { aoqi@0: return falseJumps == null && opcode == goto_; aoqi@0: } aoqi@0: aoqi@0: boolean isFalse() { aoqi@0: return trueJumps == null && opcode == dontgoto; aoqi@0: } aoqi@0: aoqi@0: public String toString() { aoqi@0: return "cond(" + Code.mnem(opcode) + ")"; aoqi@0: } aoqi@0: } aoqi@0: }