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:
031: /**
032: * WARNING: The contents of this source file are not part of any
033: * supported API. Code that depends on them does so at its own risk:
034: * they are subject to change or removal without notice.
035: */
036: public class AddExpression extends BinaryArithmeticExpression {
037: /**
038: * constructor
039: */
040: public AddExpression(long where, Expression left, Expression right) {
041: super (ADD, where, left, right);
042: }
043:
044: /**
045: * Select the type
046: */
047: void selectType(Environment env, Context ctx, int tm) {
048: if ((left.type == Type.tString) && !right.type.isType(TC_VOID)) {
049: type = Type.tString;
050: return;
051: } else if ((right.type == Type.tString)
052: && !left.type.isType(TC_VOID)) {
053: type = Type.tString;
054: return;
055: }
056: super .selectType(env, ctx, tm);
057: }
058:
059: public boolean isNonNull() {
060: // an addition expression cannot yield a null reference as a result
061: return true;
062: }
063:
064: /**
065: * Evaluate
066: */
067: Expression eval(int a, int b) {
068: return new IntExpression(where, a + b);
069: }
070:
071: Expression eval(long a, long b) {
072: return new LongExpression(where, a + b);
073: }
074:
075: Expression eval(float a, float b) {
076: return new FloatExpression(where, a + b);
077: }
078:
079: Expression eval(double a, double b) {
080: return new DoubleExpression(where, a + b);
081: }
082:
083: Expression eval(String a, String b) {
084: return new StringExpression(where, a + b);
085: }
086:
087: /**
088: * Inline the value of an AddExpression. If this AddExpression
089: * represents a concatenation of compile-time constant strings,
090: * dispatch to the special method inlineValueSB, which handles
091: * the inlining more efficiently.
092: */
093: public Expression inlineValue(Environment env, Context ctx) {
094: if (type == Type.tString && isConstant()) {
095: StringBuffer buffer = inlineValueSB(env, ctx,
096: new StringBuffer());
097: if (buffer != null) {
098: // We were able to evaluate the String concatenation.
099: return new StringExpression(where, buffer.toString());
100: }
101: }
102: // For some reason inlinValueSB() failed to produce a value.
103: // Use the older, less efficient, inlining mechanism.
104: return super .inlineValue(env, ctx);
105: }
106:
107: /**
108: * Attempt to evaluate this expression. If this expression
109: * yields a value, append it to the StringBuffer `buffer'.
110: * If this expression cannot be evaluated at this time (for
111: * example if it contains a division by zero, a non-constant
112: * subexpression, or a subexpression which "refuses" to evaluate)
113: * then return `null' to indicate failure.
114: *
115: * It is anticipated that this method will be called to evaluate
116: * concatenations of compile-time constant strings. The call
117: * originates from AddExpression#inlineValue().
118: *
119: * This method does not use associativity to good effect in
120: * folding string concatenations. This is room for improvement.
121: *
122: * -------------
123: *
124: * A bit of history: this method was added because an
125: * expression like...
126: *
127: * "a" + "b" + "c" + "d"
128: *
129: * ...was evaluated at compile-time as...
130: *
131: * (new StringBuffer((new StringBuffer("a")).append("b").toString())).
132: * append((new StringBuffer("c")).append("d").toString()).toString()
133: *
134: * Alex Garthwaite, in profiling the memory allocation of the
135: * compiler, noticed this and suggested that the method inlineValueSB()
136: * be added to evaluate constant string concatenations in a more
137: * efficient manner. The compiler now builds the string in a
138: * top-down fashion, by accumulating the result in a StringBuffer
139: * which is allocated once and passed in as a parameter. The new
140: * evaluation scheme is equivalent to...
141: *
142: * (new StringBuffer("a")).append("b").append("c").append("d")
143: * .toString()
144: *
145: * ...which is more efficient. Since then, the code has been modified
146: * to fix certain problems. Now, for example, it can return `null'
147: * when it encounters a concatenation which it is not able to
148: * evaluate.
149: *
150: * See also Expression#inlineValueSB() and ExprExpression#inlineValueSB().
151: */
152: protected StringBuffer inlineValueSB(Environment env, Context ctx,
153: StringBuffer buffer) {
154: if (type != Type.tString) {
155: // This isn't a concatenation. It is actually an addition
156: // of some sort. Call the generic inlineValueSB()
157: return super .inlineValueSB(env, ctx, buffer);
158: }
159:
160: buffer = left.inlineValueSB(env, ctx, buffer);
161: if (buffer != null) {
162: buffer = right.inlineValueSB(env, ctx, buffer);
163: }
164: return buffer;
165: }
166:
167: /**
168: * Simplify
169: */
170: Expression simplify() {
171: if (!type.isType(TC_CLASS)) {
172: // Can't simplify floating point add because of -0.0 strangeness
173: if (type.inMask(TM_INTEGER)) {
174: if (left.equals(0)) {
175: return right;
176: }
177: if (right.equals(0)) {
178: return left;
179: }
180: }
181: } else if (right.type.isType(TC_NULL)) {
182: right = new StringExpression(right.where, "null");
183: } else if (left.type.isType(TC_NULL)) {
184: left = new StringExpression(left.where, "null");
185: }
186: return this ;
187: }
188:
189: /**
190: * The cost of inlining this expression
191: */
192: public int costInline(int thresh, Environment env, Context ctx) {
193: return (type.isType(TC_CLASS) ? 12 : 1)
194: + left.costInline(thresh, env, ctx)
195: + right.costInline(thresh, env, ctx);
196: }
197:
198: /**
199: * Code
200: */
201: void codeOperation(Environment env, Context ctx, Assembler asm) {
202: asm.add(where, opc_iadd + type.getTypeCodeOffset());
203: }
204:
205: /**
206: * Convert this expression to a string and append it to the string
207: * buffer on the top of the stack.
208: * If the needBuffer argument is true, the string buffer needs to be
209: * created, initialized, and pushed on the stack, first.
210: */
211: void codeAppend(Environment env, Context ctx, Assembler asm,
212: ClassDeclaration sbClass, boolean needBuffer)
213: throws ClassNotFound, AmbiguousMember {
214: if (type.isType(TC_CLASS)) {
215: left.codeAppend(env, ctx, asm, sbClass, needBuffer);
216: right.codeAppend(env, ctx, asm, sbClass, false);
217: } else {
218: super .codeAppend(env, ctx, asm, sbClass, needBuffer);
219: }
220: }
221:
222: public void codeValue(Environment env, Context ctx, Assembler asm) {
223: if (type.isType(TC_CLASS)) {
224: try {
225: // optimize (""+foo) or (foo+"") to String.valueOf(foo)
226: if (left.equals("")) {
227: right.codeValue(env, ctx, asm);
228: right.ensureString(env, ctx, asm);
229: return;
230: }
231: if (right.equals("")) {
232: left.codeValue(env, ctx, asm);
233: left.ensureString(env, ctx, asm);
234: return;
235: }
236:
237: ClassDeclaration sbClass = env
238: .getClassDeclaration(idJavaLangStringBuffer);
239: ClassDefinition sourceClass = ctx.field
240: .getClassDefinition();
241: // Create the string buffer and append to it.
242: codeAppend(env, ctx, asm, sbClass, true);
243: // Convert the string buffer to a string
244: MemberDefinition f = sbClass.getClassDefinition(env)
245: .matchMethod(env, sourceClass, idToString);
246: asm.add(where, opc_invokevirtual, f);
247: } catch (ClassNotFound e) {
248: throw new CompilerError(e);
249: } catch (AmbiguousMember e) {
250: throw new CompilerError(e);
251: }
252: } else {
253: super.codeValue(env, ctx, asm);
254: }
255: }
256: }
|