253 lines · 9.3 KB · Java
RawDownload
/* * 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. */publicclass AddExpression extends BinaryArithmeticExpression {    /**     * constructor     */    public AddExpression(long where, Expression left, Expression right) {        super(ADD, where, left, right);    }     /**     * 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     */    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.     */    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().     */    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     */    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     */    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     */    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.     */    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);        }    }}