775 lines · 26.1 KB · Java
RawDownload
/* * Copyright (c) 1994, 2004, 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.Label;import sun.tools.asm.Assembler;import java.io.PrintStream;import java.util.Hashtable; /** * 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 Expression extends Node {    Type type;     /**     * Constructor     */    Expression(int op, long where, Type type) {        super(op, where);        this.type = type;    }     /**     * Type checking may assign a more complex implementation     * to an innocuous-looking expression (like an identifier).     * Return that implementation, or the original expression itself     * if there is no special implementation.     * <p>     * This appears at present to be dead code, and is not called     * from within javac.  Access to the implementation generally     * occurs within the same class, and thus uses the underlying     * field directly.     */    public Expression getImplementation() {        return this;    }     public Type getType() {        return type;    }     /**     * Return the precedence of the operator     */    int precedence() {        return (op < opPrecedence.length) ? opPrecedence[op] : 100;    }     /**     * Order the expression based on precedence     */    public Expression order() {        return this;    }     /**     * Return true if constant, according to JLS 15.27.     * A constant expression must inline away to a literal constant.     */    public boolean isConstant() {        return false;    }     /**     * Return the constant value.     */    public Object getValue() {        return null;    }     /**     * Check if the expression is known to be equal to a given value.     * Returns false for any expression other than a literal constant,     * thus should be called only after simplification (inlining) has     * been performed.     */    public boolean equals(int i) {        return false;    }    public boolean equals(boolean b) {        return false;    }    public boolean equals(Identifier id) {        return false;    }    public boolean equals(String s) {        return false;    }     /**     * Check if the expression must be a null reference.     */    public boolean isNull() {        return false;    }     /**     * Check if the expression cannot be a null reference.     */    public boolean isNonNull() {        return false;    }     /**     * Check if the expression is equal to its default static value     */    public boolean equalsDefault() {        return false;    }      /**     * Convert an expresion to a type     */    Type toType(Environment env, Context ctx) {        env.error(where, "invalid.type.expr");        return Type.tError;    }     /**     * Convert an expresion to a type in a context where a qualified     * type name is expected, e.g., in the prefix of a qualified type     * name.     */    /*-----------------------------------------------------*    Type toQualifiedType(Environment env, Context ctx) {        env.error(where, "invalid.type.expr");        return Type.tError;    }    *-----------------------------------------------------*/     /**     * See if this expression fits in the given type.     * This is useful because some larger numbers fit into     * smaller types.     * <p>     * If it is an "int" constant expression, inline it, if necessary,     * to examine its numerical value.  See JLS 5.2 and 15.24.     */    public boolean fitsType(Environment env, Context ctx, Type t) {        try {            if (env.isMoreSpecific(this.type, t)) {                return true;            }            if (this.type.isType(TC_INT) && this.isConstant() && ctx != null) {                // Tentative inlining is harmless for constant expressions.                Expression n = this.inlineValue(env, ctx);                if (n != this && n instanceof ConstantExpression) {                    return n.fitsType(env, ctx, t);                }            }            return false;        } catch (ClassNotFound e) {            return false;        }    }     /** @deprecated (for backward compatibility) */    @Deprecated    public boolean fitsType(Environment env, Type t) {        return fitsType(env, (Context) null, t);    }     /**     * Check an expression     */    public Vset checkValue(Environment env, Context ctx, Vset vset, Hashtable exp) {        return vset;    }    public Vset checkInitializer(Environment env, Context ctx, Vset vset, Type t, Hashtable exp) {        return checkValue(env, ctx, vset, exp);    }    public Vset check(Environment env, Context ctx, Vset vset, Hashtable exp) {        throw new CompilerError("check failed");    }     public Vset checkLHS(Environment env, Context ctx,                            Vset vset, Hashtable exp) {        env.error(where, "invalid.lhs.assignment");        type = Type.tError;        return vset;    }     /**     * Return a <code>FieldUpdater</code> object to be used in updating the     * value of the location denoted by <code>this</code>, which must be an     * expression suitable for the left-hand side of an assignment.     * This is used for implementing assignments to private fields for which     * an access method is required.  Returns null if no access method is     * needed, in which case the assignment is handled in the usual way, by     * direct access.  Only simple assignment expressions are handled here     * Assignment operators and pre/post increment/decrement operators are     * are handled by 'getUpdater' below.     * <p>     * Called during the checking phase.     */     public FieldUpdater getAssigner(Environment env, Context ctx) {        throw new CompilerError("getAssigner lhs");    }     /**     * Return a <code>FieldUpdater</code> object to be used in updating the value of the     * location denoted by <code>this</code>, which must be an expression suitable for the     * left-hand side of an assignment.  This is used for implementing the assignment     * operators and the increment/decrement operators on private fields that require an     * access method, e.g., uplevel from an inner class.  Returns null if no access method     * is needed.     * <p>     * Called during the checking phase.     */     public FieldUpdater getUpdater(Environment env, Context ctx) {        throw new CompilerError("getUpdater lhs");    }     public Vset checkAssignOp(Environment env, Context ctx,                              Vset vset, Hashtable exp, Expression outside) {        if (outside instanceof IncDecExpression)            env.error(where, "invalid.arg", opNames[outside.op]);        else            env.error(where, "invalid.lhs.assignment");        type = Type.tError;        return vset;    }     /**     * Check something that might be an AmbiguousName (refman 6.5.2).     * A string of dot-separated identifiers might be, in order of preference:     * <nl>     * <li> a variable name followed by fields or types     * <li> a type name followed by fields or types     * <li> a package name followed a type and then fields or types     * </nl>     * If a type name is found, it rewrites itself as a <tt>TypeExpression</tt>.     * If a node decides it can only be a package prefix, it sets its     * type to <tt>Type.tPackage</tt>.  The caller must detect this     * and act appropriately to verify the full package name.     * @arg loc the expression containing the ambiguous expression     */    public Vset checkAmbigName(Environment env, Context ctx, Vset vset, Hashtable exp,                               UnaryExpression loc) {        return checkValue(env, ctx, vset, exp);    }     /**     * Check a condition.  Return a ConditionVars(), which indicates when     * which variables are set if the condition is true, and which are set if     * the condition is false.     */    public ConditionVars checkCondition(Environment env, Context ctx,                                        Vset vset, Hashtable exp) {        ConditionVars cvars = new ConditionVars();        checkCondition(env, ctx, vset, exp, cvars);        return cvars;    }     /*     * Check a condition.     *     * cvars is modified so that     *    cvar.vsTrue indicates variables with a known value if result = true     *    cvars.vsFalse indicates variables with a known value if !result     *     * The default action is to simply call checkValue on the expression, and     * to see both vsTrue and vsFalse to the result.     */     public void checkCondition(Environment env, Context ctx,                               Vset vset, Hashtable exp, ConditionVars cvars) {        cvars.vsTrue = cvars.vsFalse = checkValue(env, ctx, vset, exp);        // unshare side effects:        cvars.vsFalse = cvars.vsFalse.copy();    }     /**     * Evaluate.     *     * Attempt to compute the value of an expression node.  If all operands are     * literal constants of the same kind (e.g., IntegerExpression nodes), a     * new constant node of the proper type is returned representing the value     * as computed at compile-time.  Otherwise, the original node 'this' is     * returned.     */    Expression eval() {        return this;    }     /**     * Simplify.     *     * Attempt to simplify an expression node by returning a semantically-     * equivalent expression that is presumably less costly to execute.  There     * is some overlap with the intent of 'eval', as compile-time evaluation of     * conditional expressions and the short-circuit boolean operators is     * performed here.  Other simplifications include logical identities     * involving logical negation and comparisons.  If no simplification is     * possible, the original node 'this' is returned.  It is assumed that the     * children of the node have previously been recursively simplified and     * evaluated.  A result of 'null' indicates that the expression may be     * elided entirely.     */    Expression simplify() {        return this;    }     /**     * Inline.     *     * Recursively simplify each child of an expression node, destructively     * replacing the child with the simplified result.  Also attempts to     * simplify the current node 'this', and returns the simplified result.     *     * The name 'inline' is somthing of a misnomer, as these methods are     * responsible for compile-time expression simplification in general.     * The 'eval' and 'simplify' methods apply to a single expression node     * only -- it is 'inline' and 'inlineValue' that drive the simplification     * of entire expressions.     */    public Expression inline(Environment env, Context ctx) {        return null;    }    public Expression inlineValue(Environment env, Context ctx) {        return this;    }     /**     * 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().     *     * See AddExpression#inlineValueSB() for detailed comments.     */    protected StringBuffer inlineValueSB(Environment env,                                         Context ctx,                                         StringBuffer buffer) {        Expression inlined = inlineValue(env, ctx);        Object val = inlined.getValue();         if (val == null && !inlined.isNull()){            // This (supposedly constant) expression refuses to yield            // a value.  This can happen, in particular, when we are            // trying to evaluate a division by zero.  It can also            // happen in cases where isConstant() is able to classify            // expressions as constant that the compiler's inlining            // mechanisms aren't able to evaluate; this is rare,            // and all such cases that we have found so far            // (e.g. 4082814, 4106244) have been plugged up.            //            // We return a null to indicate that we have failed to            // evaluate the concatenation.            return null;        }         // For boolean and character expressions, getValue() returns        // an Integer.  We need to take care, when appending the result        // of getValue(), that we preserve the type.        // Fix for 4103959, 4102672.        if (type == Type.tChar) {            buffer.append((char)((Integer)val).intValue());        } else if (type == Type.tBoolean) {            buffer.append(((Integer)val).intValue() != 0);        } else {            buffer.append(val);        }         return buffer;    }     public Expression inlineLHS(Environment env, Context ctx) {        return null;    }     /**     * The cost of inlining this expression.     * This cost controls the inlining of methods, and does not determine     * the compile-time simplifications performed by 'inline' and friends.     */    public int costInline(int thresh, Environment env, Context ctx) {        return 1;    }     /**     * Code     */    void codeBranch(Environment env, Context ctx, Assembler asm, Label lbl, boolean whenTrue) {        if (type.isType(TC_BOOLEAN)) {            codeValue(env, ctx, asm);            asm.add(where, whenTrue ? opc_ifne : opc_ifeq, lbl, whenTrue);        } else {            throw new CompilerError("codeBranch " + opNames[op]);        }    }    public void codeValue(Environment env, Context ctx, Assembler asm) {        if (type.isType(TC_BOOLEAN)) {            Label l1 = new Label();            Label l2 = new Label();             codeBranch(env, ctx, asm, l1, true);            asm.add(true, where, opc_ldc, new Integer(0));            asm.add(true, where, opc_goto, l2);            asm.add(l1);            asm.add(true, where, opc_ldc, new Integer(1));            asm.add(l2);        } else {            throw new CompilerError("codeValue");        }    }    public void code(Environment env, Context ctx, Assembler asm) {        codeValue(env, ctx, asm);         switch (type.getTypeCode()) {          case TC_VOID:            break;           case TC_DOUBLE:          case TC_LONG:            asm.add(where, opc_pop2);            break;           default:            asm.add(where, opc_pop);            break;        }    }    int codeLValue(Environment env, Context ctx, Assembler asm) {        print(System.out);        throw new CompilerError("invalid lhs");    }    void codeLoad(Environment env, Context ctx, Assembler asm) {        print(System.out);        throw new CompilerError("invalid load");    }    void codeStore(Environment env, Context ctx, Assembler asm) {        print(System.out);        throw new CompilerError("invalid store");    }     /**     * Convert this expression to a string.     */    void ensureString(Environment env, Context ctx, Assembler asm)            throws ClassNotFound, AmbiguousMember    {        if (type == Type.tString && isNonNull()) {            return;        }        // Make sure it's a non-null string.        ClassDefinition sourceClass = ctx.field.getClassDefinition();        ClassDeclaration stClass = env.getClassDeclaration(Type.tString);        ClassDefinition stClsDef = stClass.getClassDefinition(env);        // FIX FOR 4071548        // We use 'String.valueOf' to do the conversion, in order to        // correctly handle null references and efficiently handle        // primitive types.  For reference types, we force the argument        // to be interpreted as of 'Object' type, thus avoiding the        // the special-case overloading of 'valueOf' for character arrays.        // This special treatment would conflict with JLS 15.17.1.1.        if (type.inMask(TM_REFERENCE)) {            // Reference type            if (type != Type.tString) {                // Convert non-string object to string.  If object is                // a string, we don't need to convert it, except in the                // case that it is null, which is handled below.                Type argType1[] = {Type.tObject};

Lines 1–500 of 775.