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.io.PrintStream;
031: import java.util.Hashtable;
032:
033: /**
034: * WARNING: The contents of this source file are not part of any
035: * supported API. Code that depends on them does so at its own risk:
036: * they are subject to change or removal without notice.
037: */
038: public abstract class AssignOpExpression extends BinaryAssignExpression {
039: protected Type itype; // Type of intermediate result, before assigning
040: final int NOINC = Integer.MAX_VALUE;
041:
042: protected FieldUpdater updater = null; // Used also in 'AssignAddExpression'.
043:
044: /**
045: * Constructor
046: */
047: public AssignOpExpression(int op, long where, Expression left,
048: Expression right) {
049: super (op, where, left, right);
050: }
051:
052: /**
053: * Select the type
054: *
055: */
056:
057: final void selectType(Environment env, Context ctx, int tm) {
058: Type rtype = null; // special conversion type for RHS
059: switch (op) {
060: case ASGADD:
061: if (left.type == Type.tString) {
062: if (right.type == Type.tVoid) {
063: // The type of the right hand side can be
064: // anything except void. Fix for 4119864.
065: env.error(where, "incompatible.type", opNames[op],
066: Type.tVoid, Type.tString);
067: type = Type.tError;
068: } else {
069: type = itype = Type.tString;
070: }
071: return;
072: }
073: /* Fall through */
074: case ASGDIV:
075: case ASGMUL:
076: case ASGSUB:
077: case ASGREM:
078: if ((tm & TM_DOUBLE) != 0) {
079: itype = Type.tDouble;
080: } else if ((tm & TM_FLOAT) != 0) {
081: itype = Type.tFloat;
082: } else if ((tm & TM_LONG) != 0) {
083: itype = Type.tLong;
084: } else {
085: itype = Type.tInt;
086: }
087: break;
088:
089: case ASGBITAND:
090: case ASGBITOR:
091: case ASGBITXOR:
092: if ((tm & TM_BOOLEAN) != 0) {
093: itype = Type.tBoolean;
094: } else if ((tm & TM_LONG) != 0) {
095: itype = Type.tLong;
096: } else {
097: itype = Type.tInt;
098: }
099: break;
100:
101: case ASGLSHIFT:
102: case ASGRSHIFT:
103: case ASGURSHIFT:
104: rtype = Type.tInt;
105:
106: // Fix for bug 4134459.
107: // We allow any integral type (even long) to
108: // be the right hand side of a shift operation.
109: if (right.type.inMask(TM_INTEGER)) {
110: right = new ConvertExpression(where, Type.tInt, right);
111: }
112: // The intermediate type of the expression is the
113: // type of the left hand side after undergoing
114: // unary (not binary) type promotion. We ignore
115: // tm -- it contains information about both left
116: // and right hand sides -- and we compute the
117: // type only from the type of the lhs.
118: if (left.type == Type.tLong) {
119: itype = Type.tLong;
120: } else {
121: itype = Type.tInt;
122: }
123:
124: break;
125:
126: default:
127: throw new CompilerError("Bad assignOp type: " + op);
128: }
129: if (rtype == null) {
130: rtype = itype;
131: }
132: right = convert(env, ctx, rtype, right);
133: // The result is always the type of the left operand.
134:
135: type = left.type;
136: }
137:
138: /**
139: * Get the increment, return NOINC if an increment is not possible
140: */
141: int getIncrement() {
142: if ((left.op == IDENT) && type.isType(TC_INT)
143: && (right.op == INTVAL))
144: if ((op == ASGADD) || (op == ASGSUB))
145: if (((IdentifierExpression) left).field.isLocal()) {
146: int val = ((IntExpression) right).value;
147: if (op == ASGSUB)
148: val = -val;
149: if (val == (short) val)
150: return val;
151: }
152: return NOINC;
153: }
154:
155: /**
156: * Check an assignment expression
157: */
158: public Vset checkValue(Environment env, Context ctx, Vset vset,
159: Hashtable exp) {
160: vset = left.checkAssignOp(env, ctx, vset, exp, this );
161: vset = right.checkValue(env, ctx, vset, exp);
162: int tm = left.type.getTypeMask() | right.type.getTypeMask();
163: if ((tm & TM_ERROR) != 0) {
164: return vset;
165: }
166: selectType(env, ctx, tm);
167: if (!type.isType(TC_ERROR)) {
168: convert(env, ctx, itype, left);
169: }
170: updater = left.getUpdater(env, ctx); // Must be called after 'checkAssignOp'.
171: return vset;
172: }
173:
174: /**
175: * Inline
176: */
177: public Expression inlineValue(Environment env, Context ctx) {
178: // Why not inlineLHS? But that does not work.
179: left = left.inlineValue(env, ctx);
180: right = right.inlineValue(env, ctx);
181: if (updater != null) {
182: updater = updater.inline(env, ctx);
183: }
184: return this ;
185: }
186:
187: /**
188: * Create a copy of the expression for method inlining
189: */
190: public Expression copyInline(Context ctx) {
191: AssignOpExpression e = (AssignOpExpression) clone();
192: e.left = left.copyInline(ctx);
193: e.right = right.copyInline(ctx);
194: if (updater != null) {
195: e.updater = updater.copyInline(ctx);
196: }
197: return e;
198: }
199:
200: /**
201: * The cost of inlining this statement
202: */
203: public int costInline(int thresh, Environment env, Context ctx) {
204: /*----------*
205: return (getIncrement() != NOINC)
206: ? 2
207: : (3 + super.costInline(thresh, env, ctx));
208: *----------*/
209: if (updater == null) {
210: return (getIncrement() != NOINC)
211: // Increment variable in place. Count 3 bytes for 'iinc'.
212: ? 3
213: // Cost of rhs expression + cost of lhs expression + cost
214: // of load/op/store instructions. E.g.: iload = 1 or 2,
215: // istore = 1 or 2, iadd = 1. Cost could be higher if
216: // getfield/putfield or conversions needed, lower if rhs is
217: // a small constant. Costs are highly approximate.
218: : right.costInline(thresh, env, ctx)
219: + left.costInline(thresh, env, ctx) + 4;
220: } else {
221: // Cost of rhs expression + (2 * cost of access method call) +
222: // cost of operator. Does not account for cost of conversions,
223: // or duplications in value-needed context.
224: return right.costInline(thresh, env, ctx)
225: + updater.costInline(thresh, env, ctx, true) + 1;
226: }
227: }
228:
229: /**
230: * Code
231: */
232: void code(Environment env, Context ctx, Assembler asm,
233: boolean valNeeded) {
234:
235: // Handle cases in which a '+=' or '-=' operator can be optimized using
236: // the 'iinc' instruction. See also 'IncDecExpression.codeIncDec'.
237: // The 'iinc' instruction cannot be used if an access method call is required.
238: int val = getIncrement();
239: if (val != NOINC && updater == null) {
240: int v = ((LocalMember) ((IdentifierExpression) left).field).number;
241: int[] operands = { v, val };
242: asm.add(where, opc_iinc, operands);
243: if (valNeeded) {
244: left.codeValue(env, ctx, asm);
245: }
246: return;
247: }
248:
249: if (updater == null) {
250: // Field is directly accessible.
251: int depth = left.codeLValue(env, ctx, asm);
252: codeDup(env, ctx, asm, depth, 0);
253: left.codeLoad(env, ctx, asm);
254: codeConversion(env, ctx, asm, left.type, itype);
255: right.codeValue(env, ctx, asm);
256: codeOperation(env, ctx, asm);
257: codeConversion(env, ctx, asm, itype, type);
258: if (valNeeded) {
259: codeDup(env, ctx, asm, type.stackSize(), depth);
260: }
261: left.codeStore(env, ctx, asm);
262: } else {
263: // Must use access methods.
264: updater.startUpdate(env, ctx, asm, false);
265: codeConversion(env, ctx, asm, left.type, itype);
266: right.codeValue(env, ctx, asm);
267: codeOperation(env, ctx, asm);
268: codeConversion(env, ctx, asm, itype, type);
269: updater.finishUpdate(env, ctx, asm, valNeeded);
270: }
271: }
272:
273: public void codeValue(Environment env, Context ctx, Assembler asm) {
274: code(env, ctx, asm, true);
275: }
276:
277: public void code(Environment env, Context ctx, Assembler asm) {
278: code(env, ctx, asm, false);
279: }
280:
281: /**
282: * Print
283: */
284: public void print(PrintStream out) {
285: out.print("(" + opNames[op] + " ");
286: left.print(out);
287: out.print(" ");
288: right.print(out);
289: out.print(")");
290: }
291: }
|