/*
 * Copyright (c) 1994, 2003, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package sun.tools.tree;

import sun.tools.java.*;
import sun.tools.asm.Assembler;

WARNING: The contents of this source file are not part of any supported API. Code that depends on them does so at its own risk: they are subject to change or removal without notice.
/** * WARNING: The contents of this source file are not part of any * supported API. Code that depends on them does so at its own risk: * they are subject to change or removal without notice. */
public class AddExpression extends BinaryArithmeticExpression {
constructor
/** * constructor */
public AddExpression(long where, Expression left, Expression right) { super(ADD, where, left, right); }
Select the type
/** * Select the type */
void selectType(Environment env, Context ctx, int tm) { if ((left.type == Type.tString) && !right.type.isType(TC_VOID)) { type = Type.tString; return; } else if ((right.type == Type.tString) && !left.type.isType(TC_VOID)) { type = Type.tString; return; } super.selectType(env, ctx, tm); } public boolean isNonNull() { // an addition expression cannot yield a null reference as a result return true; }
Evaluate
/** * Evaluate */
Expression eval(int a, int b) { return new IntExpression(where, a + b); } Expression eval(long a, long b) { return new LongExpression(where, a + b); } Expression eval(float a, float b) { return new FloatExpression(where, a + b); } Expression eval(double a, double b) { return new DoubleExpression(where, a + b); } Expression eval(String a, String b) { return new StringExpression(where, a + b); }
Inline the value of an AddExpression. If this AddExpression represents a concatenation of compile-time constant strings, dispatch to the special method inlineValueSB, which handles the inlining more efficiently.
/** * Inline the value of an AddExpression. If this AddExpression * represents a concatenation of compile-time constant strings, * dispatch to the special method inlineValueSB, which handles * the inlining more efficiently. */
public Expression inlineValue(Environment env, Context ctx) { if (type == Type.tString && isConstant()) { StringBuffer buffer = inlineValueSB(env, ctx, new StringBuffer()); if (buffer != null) { // We were able to evaluate the String concatenation. return new StringExpression(where, buffer.toString()); } } // For some reason inlinValueSB() failed to produce a value. // Use the older, less efficient, inlining mechanism. return super.inlineValue(env, ctx); }
Attempt to evaluate this expression. If this expression yields a value, append it to the StringBuffer `buffer'. If this expression cannot be evaluated at this time (for example if it contains a division by zero, a non-constant subexpression, or a subexpression which "refuses" to evaluate) then return `null' to indicate failure. It is anticipated that this method will be called to evaluate concatenations of compile-time constant strings. The call originates from AddExpression#inlineValue(). This method does not use associativity to good effect in folding string concatenations. This is room for improvement. ------------- A bit of history: this method was added because an expression like... "a" + "b" + "c" + "d" ...was evaluated at compile-time as... (new StringBuffer((new StringBuffer("a")).append("b").toString())). append((new StringBuffer("c")).append("d").toString()).toString() Alex Garthwaite, in profiling the memory allocation of the compiler, noticed this and suggested that the method inlineValueSB() be added to evaluate constant string concatenations in a more efficient manner. The compiler now builds the string in a top-down fashion, by accumulating the result in a StringBuffer which is allocated once and passed in as a parameter. The new evaluation scheme is equivalent to... (new StringBuffer("a")).append("b").append("c").append("d") .toString() ...which is more efficient. Since then, the code has been modified to fix certain problems. Now, for example, it can return `null' when it encounters a concatenation which it is not able to evaluate. See also Expression#inlineValueSB() and ExprExpression#inlineValueSB().
/** * Attempt to evaluate this expression. If this expression * yields a value, append it to the StringBuffer `buffer'. * If this expression cannot be evaluated at this time (for * example if it contains a division by zero, a non-constant * subexpression, or a subexpression which "refuses" to evaluate) * then return `null' to indicate failure. * * It is anticipated that this method will be called to evaluate * concatenations of compile-time constant strings. The call * originates from AddExpression#inlineValue(). * * This method does not use associativity to good effect in * folding string concatenations. This is room for improvement. * * ------------- * * A bit of history: this method was added because an * expression like... * * "a" + "b" + "c" + "d" * * ...was evaluated at compile-time as... * * (new StringBuffer((new StringBuffer("a")).append("b").toString())). * append((new StringBuffer("c")).append("d").toString()).toString() * * Alex Garthwaite, in profiling the memory allocation of the * compiler, noticed this and suggested that the method inlineValueSB() * be added to evaluate constant string concatenations in a more * efficient manner. The compiler now builds the string in a * top-down fashion, by accumulating the result in a StringBuffer * which is allocated once and passed in as a parameter. The new * evaluation scheme is equivalent to... * * (new StringBuffer("a")).append("b").append("c").append("d") * .toString() * * ...which is more efficient. Since then, the code has been modified * to fix certain problems. Now, for example, it can return `null' * when it encounters a concatenation which it is not able to * evaluate. * * See also Expression#inlineValueSB() and ExprExpression#inlineValueSB(). */
protected StringBuffer inlineValueSB(Environment env, Context ctx, StringBuffer buffer) { if (type != Type.tString) { // This isn't a concatenation. It is actually an addition // of some sort. Call the generic inlineValueSB() return super.inlineValueSB(env, ctx, buffer); } buffer = left.inlineValueSB(env, ctx, buffer); if (buffer != null) { buffer = right.inlineValueSB(env, ctx, buffer); } return buffer; }
Simplify
/** * Simplify */
Expression simplify() { if (!type.isType(TC_CLASS)) { // Can't simplify floating point add because of -0.0 strangeness if (type.inMask(TM_INTEGER)) { if (left.equals(0)) { return right; } if (right.equals(0)) { return left; } } } else if (right.type.isType(TC_NULL)) { right = new StringExpression(right.where, "null"); } else if (left.type.isType(TC_NULL)) { left = new StringExpression(left.where, "null"); } return this; }
The cost of inlining this expression
/** * The cost of inlining this expression */
public int costInline(int thresh, Environment env, Context ctx) { return (type.isType(TC_CLASS) ? 12 : 1) + left.costInline(thresh, env, ctx) + right.costInline(thresh, env, ctx); }
Code
/** * Code */
void codeOperation(Environment env, Context ctx, Assembler asm) { asm.add(where, opc_iadd + type.getTypeCodeOffset()); }
Convert this expression to a string and append it to the string buffer on the top of the stack. If the needBuffer argument is true, the string buffer needs to be created, initialized, and pushed on the stack, first.
/** * Convert this expression to a string and append it to the string * buffer on the top of the stack. * If the needBuffer argument is true, the string buffer needs to be * created, initialized, and pushed on the stack, first. */
void codeAppend(Environment env, Context ctx, Assembler asm, ClassDeclaration sbClass, boolean needBuffer) throws ClassNotFound, AmbiguousMember { if (type.isType(TC_CLASS)) { left.codeAppend(env, ctx, asm, sbClass, needBuffer); right.codeAppend(env, ctx, asm, sbClass, false); } else { super.codeAppend(env, ctx, asm, sbClass, needBuffer); } } public void codeValue(Environment env, Context ctx, Assembler asm) { if (type.isType(TC_CLASS)) { try { // optimize (""+foo) or (foo+"") to String.valueOf(foo) if (left.equals("")) { right.codeValue(env, ctx, asm); right.ensureString(env, ctx, asm); return; } if (right.equals("")) { left.codeValue(env, ctx, asm); left.ensureString(env, ctx, asm); return; } ClassDeclaration sbClass = env.getClassDeclaration(idJavaLangStringBuffer); ClassDefinition sourceClass = ctx.field.getClassDefinition(); // Create the string buffer and append to it. codeAppend(env, ctx, asm, sbClass, true); // Convert the string buffer to a string MemberDefinition f = sbClass.getClassDefinition(env).matchMethod(env, sourceClass, idToString); asm.add(where, opc_invokevirtual, f); } catch (ClassNotFound e) { throw new CompilerError(e); } catch (AmbiguousMember e) { throw new CompilerError(e); } } else { super.codeValue(env, ctx, asm); } } }