0N/A/*
2362N/A * Copyright (c) 1994, 2003, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage sun.tools.tree;
0N/A
0N/Aimport sun.tools.java.*;
0N/Aimport sun.tools.asm.Assembler;
0N/A
0N/A/**
0N/A * WARNING: The contents of this source file are not part of any
0N/A * supported API. Code that depends on them does so at its own risk:
0N/A * they are subject to change or removal without notice.
0N/A */
0N/Apublic
0N/Aclass AddExpression extends BinaryArithmeticExpression {
0N/A /**
0N/A * constructor
0N/A */
0N/A public AddExpression(long where, Expression left, Expression right) {
0N/A super(ADD, where, left, right);
0N/A }
0N/A
0N/A /**
0N/A * Select the type
0N/A */
0N/A void selectType(Environment env, Context ctx, int tm) {
0N/A if ((left.type == Type.tString) && !right.type.isType(TC_VOID)) {
0N/A type = Type.tString;
0N/A return;
0N/A } else if ((right.type == Type.tString) && !left.type.isType(TC_VOID)) {
0N/A type = Type.tString;
0N/A return;
0N/A }
0N/A super.selectType(env, ctx, tm);
0N/A }
0N/A
0N/A public boolean isNonNull() {
0N/A // an addition expression cannot yield a null reference as a result
0N/A return true;
0N/A }
0N/A
0N/A /**
0N/A * Evaluate
0N/A */
0N/A Expression eval(int a, int b) {
0N/A return new IntExpression(where, a + b);
0N/A }
0N/A Expression eval(long a, long b) {
0N/A return new LongExpression(where, a + b);
0N/A }
0N/A Expression eval(float a, float b) {
0N/A return new FloatExpression(where, a + b);
0N/A }
0N/A Expression eval(double a, double b) {
0N/A return new DoubleExpression(where, a + b);
0N/A }
0N/A Expression eval(String a, String b) {
0N/A return new StringExpression(where, a + b);
0N/A }
0N/A
0N/A /**
0N/A * Inline the value of an AddExpression. If this AddExpression
0N/A * represents a concatenation of compile-time constant strings,
0N/A * dispatch to the special method inlineValueSB, which handles
0N/A * the inlining more efficiently.
0N/A */
0N/A public Expression inlineValue(Environment env, Context ctx) {
0N/A if (type == Type.tString && isConstant()) {
0N/A StringBuffer buffer = inlineValueSB(env, ctx, new StringBuffer());
0N/A if (buffer != null) {
0N/A // We were able to evaluate the String concatenation.
0N/A return new StringExpression(where, buffer.toString());
0N/A }
0N/A }
0N/A // For some reason inlinValueSB() failed to produce a value.
0N/A // Use the older, less efficient, inlining mechanism.
0N/A return super.inlineValue(env, ctx);
0N/A }
0N/A
0N/A /**
0N/A * Attempt to evaluate this expression. If this expression
0N/A * yields a value, append it to the StringBuffer `buffer'.
0N/A * If this expression cannot be evaluated at this time (for
0N/A * example if it contains a division by zero, a non-constant
0N/A * subexpression, or a subexpression which "refuses" to evaluate)
0N/A * then return `null' to indicate failure.
0N/A *
0N/A * It is anticipated that this method will be called to evaluate
0N/A * concatenations of compile-time constant strings. The call
0N/A * originates from AddExpression#inlineValue().
0N/A *
0N/A * This method does not use associativity to good effect in
0N/A * folding string concatenations. This is room for improvement.
0N/A *
0N/A * -------------
0N/A *
0N/A * A bit of history: this method was added because an
0N/A * expression like...
0N/A *
0N/A * "a" + "b" + "c" + "d"
0N/A *
0N/A * ...was evaluated at compile-time as...
0N/A *
0N/A * (new StringBuffer((new StringBuffer("a")).append("b").toString())).
0N/A * append((new StringBuffer("c")).append("d").toString()).toString()
0N/A *
0N/A * Alex Garthwaite, in profiling the memory allocation of the
0N/A * compiler, noticed this and suggested that the method inlineValueSB()
0N/A * be added to evaluate constant string concatenations in a more
0N/A * efficient manner. The compiler now builds the string in a
0N/A * top-down fashion, by accumulating the result in a StringBuffer
0N/A * which is allocated once and passed in as a parameter. The new
0N/A * evaluation scheme is equivalent to...
0N/A *
0N/A * (new StringBuffer("a")).append("b").append("c").append("d")
0N/A * .toString()
0N/A *
0N/A * ...which is more efficient. Since then, the code has been modified
0N/A * to fix certain problems. Now, for example, it can return `null'
0N/A * when it encounters a concatenation which it is not able to
0N/A * evaluate.
0N/A *
0N/A * See also Expression#inlineValueSB() and ExprExpression#inlineValueSB().
0N/A */
0N/A protected StringBuffer inlineValueSB(Environment env,
0N/A Context ctx,
0N/A StringBuffer buffer) {
0N/A if (type != Type.tString) {
0N/A // This isn't a concatenation. It is actually an addition
0N/A // of some sort. Call the generic inlineValueSB()
0N/A return super.inlineValueSB(env, ctx, buffer);
0N/A }
0N/A
0N/A buffer = left.inlineValueSB(env, ctx, buffer);
0N/A if (buffer != null) {
0N/A buffer = right.inlineValueSB(env, ctx, buffer);
0N/A }
0N/A return buffer;
0N/A }
0N/A
0N/A /**
0N/A * Simplify
0N/A */
0N/A Expression simplify() {
0N/A if (!type.isType(TC_CLASS)) {
0N/A // Can't simplify floating point add because of -0.0 strangeness
0N/A if (type.inMask(TM_INTEGER)) {
0N/A if (left.equals(0)) {
0N/A return right;
0N/A }
0N/A if (right.equals(0)) {
0N/A return left;
0N/A }
0N/A }
0N/A } else if (right.type.isType(TC_NULL)) {
0N/A right = new StringExpression(right.where, "null");
0N/A } else if (left.type.isType(TC_NULL)) {
0N/A left = new StringExpression(left.where, "null");
0N/A }
0N/A return this;
0N/A }
0N/A
0N/A /**
0N/A * The cost of inlining this expression
0N/A */
0N/A public int costInline(int thresh, Environment env, Context ctx) {
0N/A return (type.isType(TC_CLASS) ? 12 : 1)
0N/A + left.costInline(thresh, env, ctx)
0N/A + right.costInline(thresh, env, ctx);
0N/A }
0N/A
0N/A /**
0N/A * Code
0N/A */
0N/A void codeOperation(Environment env, Context ctx, Assembler asm) {
0N/A asm.add(where, opc_iadd + type.getTypeCodeOffset());
0N/A }
0N/A
0N/A /**
0N/A * Convert this expression to a string and append it to the string
0N/A * buffer on the top of the stack.
0N/A * If the needBuffer argument is true, the string buffer needs to be
0N/A * created, initialized, and pushed on the stack, first.
0N/A */
0N/A void codeAppend(Environment env, Context ctx, Assembler asm,
0N/A ClassDeclaration sbClass, boolean needBuffer)
0N/A throws ClassNotFound, AmbiguousMember {
0N/A if (type.isType(TC_CLASS)) {
0N/A left.codeAppend(env, ctx, asm, sbClass, needBuffer);
0N/A right.codeAppend(env, ctx, asm, sbClass, false);
0N/A } else {
0N/A super.codeAppend(env, ctx, asm, sbClass, needBuffer);
0N/A }
0N/A }
0N/A
0N/A public void codeValue(Environment env, Context ctx, Assembler asm) {
0N/A if (type.isType(TC_CLASS)) {
0N/A try {
0N/A // optimize (""+foo) or (foo+"") to String.valueOf(foo)
0N/A if (left.equals("")) {
0N/A right.codeValue(env, ctx, asm);
0N/A right.ensureString(env, ctx, asm);
0N/A return;
0N/A }
0N/A if (right.equals("")) {
0N/A left.codeValue(env, ctx, asm);
0N/A left.ensureString(env, ctx, asm);
0N/A return;
0N/A }
0N/A
0N/A ClassDeclaration sbClass =
0N/A env.getClassDeclaration(idJavaLangStringBuffer);
0N/A ClassDefinition sourceClass = ctx.field.getClassDefinition();
0N/A // Create the string buffer and append to it.
0N/A codeAppend(env, ctx, asm, sbClass, true);
0N/A // Convert the string buffer to a string
0N/A MemberDefinition f =
0N/A sbClass.getClassDefinition(env).matchMethod(env,
0N/A sourceClass,
0N/A idToString);
0N/A asm.add(where, opc_invokevirtual, f);
0N/A } catch (ClassNotFound e) {
0N/A throw new CompilerError(e);
0N/A } catch (AmbiguousMember e) {
0N/A throw new CompilerError(e);
0N/A }
0N/A } else {
0N/A super.codeValue(env, ctx, asm);
0N/A }
0N/A }
0N/A}