001: /*
002: * Copyright 1994-2003 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package sun.tools.tree;
027:
028: import sun.tools.java.*;
029: import sun.tools.asm.Assembler;
030: import java.util.Hashtable;
031:
032: /**
033: * WARNING: The contents of this source file are not part of any
034: * supported API. Code that depends on them does so at its own risk:
035: * they are subject to change or removal without notice.
036: */
037: public class IncDecExpression extends UnaryExpression {
038:
039: private FieldUpdater updater = null;
040:
041: /**
042: * Constructor
043: */
044: public IncDecExpression(int op, long where, Expression right) {
045: super (op, where, right.type, right);
046: }
047:
048: /**
049: * Check an increment or decrement expression
050: */
051: public Vset checkValue(Environment env, Context ctx, Vset vset,
052: Hashtable exp) {
053: vset = right.checkAssignOp(env, ctx, vset, exp, this );
054: if (right.type.inMask(TM_NUMBER)) {
055: type = right.type;
056: } else {
057: if (!right.type.isType(TC_ERROR)) {
058: env.error(where, "invalid.arg.type", right.type,
059: opNames[op]);
060: }
061: type = Type.tError;
062: }
063: updater = right.getUpdater(env, ctx); // Must be called after 'checkAssignOp'.
064: return vset;
065: }
066:
067: /**
068: * Check void expression
069: */
070: public Vset check(Environment env, Context ctx, Vset vset,
071: Hashtable exp) {
072: return checkValue(env, ctx, vset, exp);
073: }
074:
075: /**
076: * Inline
077: */
078: public Expression inline(Environment env, Context ctx) {
079: return inlineValue(env, ctx);
080: }
081:
082: public Expression inlineValue(Environment env, Context ctx) {
083: // Why not inlineLHS? But that does not work.
084: right = right.inlineValue(env, ctx);
085: if (updater != null) {
086: updater = updater.inline(env, ctx);
087: }
088: return this ;
089: }
090:
091: public int costInline(int thresh, Environment env, Context ctx) {
092: if (updater == null) {
093: if ((right.op == IDENT) && type.isType(TC_INT)
094: && (((IdentifierExpression) right).field.isLocal())) {
095: // Increment variable in place. Count 3 bytes for 'iinc'.
096: return 3;
097: }
098: // Cost to load lhs reference, fetch local, increment, and store.
099: // Load/store cost will be higher if variable is a field. Note that
100: // costs are highly approximate. See 'AssignOpExpression.costInline'
101: // Does not account for cost of conversions,or duplications in
102: // value-needed context..
103: return right.costInline(thresh, env, ctx) + 4;
104: } else {
105: // Cost of two access method calls (get/set) + cost of increment.
106: return updater.costInline(thresh, env, ctx, true) + 1;
107: }
108: }
109:
110: /**
111: * Code
112: */
113:
114: private void codeIncDecOp(Assembler asm, boolean inc) {
115: switch (type.getTypeCode()) {
116: case TC_BYTE:
117: asm.add(where, opc_ldc, new Integer(1));
118: asm.add(where, inc ? opc_iadd : opc_isub);
119: asm.add(where, opc_i2b);
120: break;
121: case TC_SHORT:
122: asm.add(where, opc_ldc, new Integer(1));
123: asm.add(where, inc ? opc_iadd : opc_isub);
124: asm.add(where, opc_i2s);
125: break;
126: case TC_CHAR:
127: asm.add(where, opc_ldc, new Integer(1));
128: asm.add(where, inc ? opc_iadd : opc_isub);
129: asm.add(where, opc_i2c);
130: break;
131: case TC_INT:
132: asm.add(where, opc_ldc, new Integer(1));
133: asm.add(where, inc ? opc_iadd : opc_isub);
134: break;
135: case TC_LONG:
136: asm.add(where, opc_ldc2_w, new Long(1));
137: asm.add(where, inc ? opc_ladd : opc_lsub);
138: break;
139: case TC_FLOAT:
140: asm.add(where, opc_ldc, new Float(1));
141: asm.add(where, inc ? opc_fadd : opc_fsub);
142: break;
143: case TC_DOUBLE:
144: asm.add(where, opc_ldc2_w, new Double(1));
145: asm.add(where, inc ? opc_dadd : opc_dsub);
146: break;
147: default:
148: throw new CompilerError("invalid type");
149: }
150: }
151:
152: void codeIncDec(Environment env, Context ctx, Assembler asm,
153: boolean inc, boolean prefix, boolean valNeeded) {
154:
155: // The 'iinc' instruction cannot be used if an access method call is required.
156: if ((right.op == IDENT) && type.isType(TC_INT)
157: && (((IdentifierExpression) right).field.isLocal())
158: && updater == null) {
159: if (valNeeded && !prefix) {
160: right.codeLoad(env, ctx, asm);
161: }
162: int v = ((LocalMember) ((IdentifierExpression) right).field).number;
163: int[] operands = { v, inc ? 1 : -1 };
164: asm.add(where, opc_iinc, operands);
165: if (valNeeded && prefix) {
166: right.codeLoad(env, ctx, asm);
167: }
168: return;
169:
170: }
171:
172: if (updater == null) {
173: // Field is directly accessible.
174: int depth = right.codeLValue(env, ctx, asm);
175: codeDup(env, ctx, asm, depth, 0);
176: right.codeLoad(env, ctx, asm);
177: if (valNeeded && !prefix) {
178: codeDup(env, ctx, asm, type.stackSize(), depth);
179: }
180: codeIncDecOp(asm, inc);
181: if (valNeeded && prefix) {
182: codeDup(env, ctx, asm, type.stackSize(), depth);
183: }
184: right.codeStore(env, ctx, asm);
185: } else {
186: // Must use access methods.
187: updater.startUpdate(env, ctx, asm, (valNeeded && !prefix));
188: codeIncDecOp(asm, inc);
189: updater.finishUpdate(env, ctx, asm, (valNeeded && prefix));
190: }
191: }
192:
193: }
|