/* * 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. Load more
/* * 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. */ public class 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};