001: /*
002: * Copyright 1994-2003 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package sun.tools.tree;
027:
028: import sun.tools.java.*;
029: import sun.tools.asm.Assembler;
030: import sun.tools.asm.LocalVariable;
031: import java.io.PrintStream;
032: import java.util.Hashtable;
033:
034: /**
035: * WARNING: The contents of this source file are not part of any
036: * supported API. Code that depends on them does so at its own risk:
037: * they are subject to change or removal without notice.
038: */
039: public class VarDeclarationStatement extends Statement {
040: LocalMember field;
041: Expression expr;
042:
043: /**
044: * Constructor
045: */
046: public VarDeclarationStatement(long where, Expression expr) {
047: super (VARDECLARATION, where);
048: this .expr = expr;
049: }
050:
051: public VarDeclarationStatement(long where, LocalMember field,
052: Expression expr) {
053: super (VARDECLARATION, where);
054: this .field = field;
055: this .expr = expr;
056: }
057:
058: /**
059: * Check statement
060: */
061: Vset checkDeclaration(Environment env, Context ctx, Vset vset,
062: int mod, Type t, Hashtable exp) {
063: if (labels != null) {
064: env.error(where, "declaration.with.label", labels[0]);
065: }
066: if (field != null) {
067: if (ctx.getLocalClass(field.getName()) != null
068: && field.isInnerClass()) {
069: env.error(where, "local.class.redefined", field
070: .getName());
071: }
072:
073: ctx.declare(env, field);
074: if (field.isInnerClass()) {
075: ClassDefinition body = field.getInnerClass();
076: try {
077: vset = body.checkLocalClass(env, ctx, vset, null,
078: null, null);
079: } catch (ClassNotFound ee) {
080: env.error(where, "class.not.found", ee.name,
081: opNames[op]);
082: }
083: return vset;
084: }
085: vset.addVar(field.number);
086: return (expr != null) ? expr
087: .checkValue(env, ctx, vset, exp) : vset;
088: }
089:
090: // Argument 'expr' is either an IdentifierExpression for a declaration of
091: // the form 'type x' or an AssignmentExpression for a declaration of the
092: // form 'type x = initvalue'. Note that these expressions are treated
093: // specially in this context, and don't have much connection to their ordinary
094: // meaning.
095:
096: Expression e = expr;
097:
098: if (e.op == ASSIGN) {
099: expr = ((AssignExpression) e).right;
100: e = ((AssignExpression) e).left;
101: } else {
102: expr = null;
103: }
104:
105: boolean declError = t.isType(TC_ERROR);
106: while (e.op == ARRAYACCESS) {
107: ArrayAccessExpression array = (ArrayAccessExpression) e;
108: if (array.index != null) {
109: env.error(array.index.where, "array.dim.in.type");
110: declError = true;
111: }
112: e = array.right;
113: t = Type.tArray(t);
114: }
115: if (e.op == IDENT) {
116: Identifier id = ((IdentifierExpression) e).id;
117: if (ctx.getLocalField(id) != null) {
118: env.error(where, "local.redefined", id);
119: }
120:
121: field = new LocalMember(e.where, ctx.field
122: .getClassDefinition(), mod, t, id);
123: ctx.declare(env, field);
124:
125: if (expr != null) {
126: vset = expr.checkInitializer(env, ctx, vset, t, exp);
127: expr = convert(env, ctx, t, expr);
128: field.setValue(expr); // for the sake of non-blank finals
129: if (field.isConstant()) {
130: // Keep in mind that isConstant() only means expressions
131: // that are constant according to the JLS. They might
132: // not be either constants or evaluable (eg. 1/0).
133: field.addModifiers(M_INLINEABLE);
134: }
135: vset.addVar(field.number);
136: } else if (declError) {
137: vset.addVar(field.number);
138: } else {
139: vset.addVarUnassigned(field.number);
140: }
141: return vset;
142: }
143: env.error(e.where, "invalid.decl");
144: return vset;
145: }
146:
147: /**
148: * Inline
149: */
150: public Statement inline(Environment env, Context ctx) {
151: if (field.isInnerClass()) {
152: ClassDefinition body = field.getInnerClass();
153: body.inlineLocalClass(env);
154: return null;
155: }
156:
157: // Don't generate code for variable if unused and
158: // optimization is on, whether or not debugging is on
159: if (env.opt() && !field.isUsed()) {
160: return new ExpressionStatement(where, expr)
161: .inline(env, ctx);
162: }
163:
164: ctx.declare(env, field);
165:
166: if (expr != null) {
167: expr = expr.inlineValue(env, ctx);
168: field.setValue(expr); // for the sake of non-blank finals
169: if (env.opt() && (field.writecount == 0)) {
170: if (expr.op == IDENT) {
171:
172: // This code looks like it tests whether a final variable
173: // is being initialized by an identifier expression.
174: // Then if the identifier is a local of the same method
175: // it makes the final variable eligible to be inlined.
176: // BUT: why isn't the local also checked to make sure
177: // it is itself final? Unknown.
178:
179: IdentifierExpression e = (IdentifierExpression) expr;
180: if (e.field.isLocal()
181: && ((ctx = ctx.getInlineContext()) != null)
182: && (((LocalMember) e.field).number < ctx.varNumber)) {
183: //System.out.println("FINAL IDENT = " + field + " in " + ctx.field);
184: field.setValue(expr);
185: field.addModifiers(M_INLINEABLE);
186:
187: // The two lines below used to elide the declaration
188: // of inlineable variables, on the theory that there
189: // wouldn't be any references. But this breaks the
190: // translation of nested classes, which might refer to
191: // the variable.
192:
193: //expr = null;
194: //return null;
195: }
196: }
197: if (expr.isConstant() || (expr.op == THIS)
198: || (expr.op == SUPER)) {
199: //System.out.println("FINAL = " + field + " in " + ctx.field);
200: field.setValue(expr);
201: field.addModifiers(M_INLINEABLE);
202:
203: // The two lines below used to elide the declaration
204: // of inlineable variables, on the theory that there
205: // wouldn't be any references. But this breaks the
206: // translation of nested classes, which might refer to
207: // the variable. Fix for 4073244.
208:
209: //expr = null;
210: //return null;
211: }
212: }
213: }
214: return this ;
215: }
216:
217: /**
218: * Create a copy of the statement for method inlining
219: */
220: public Statement copyInline(Context ctx, boolean valNeeded) {
221: VarDeclarationStatement s = (VarDeclarationStatement) clone();
222: if (expr != null) {
223: s.expr = expr.copyInline(ctx);
224: }
225: return s;
226: }
227:
228: /**
229: * The cost of inlining this statement
230: */
231: public int costInline(int thresh, Environment env, Context ctx) {
232: if (field != null && field.isInnerClass()) {
233: return thresh; // don't copy classes...
234: }
235: return (expr != null) ? expr.costInline(thresh, env, ctx) : 0;
236: }
237:
238: /**
239: * Code
240: */
241: public void code(Environment env, Context ctx, Assembler asm) {
242: if (expr != null && !expr.type.isType(TC_VOID)) {
243: // The two lines of code directly following this comment used
244: // to be in the opposite order. They were switched so that
245: // lines like the following:
246: //
247: // int j = (j = 4);
248: //
249: // will compile correctly. (Constructions like the above are
250: // legal. JLS 14.3.2 says that the scope of a local variable
251: // includes its own initializer.) It is important that we
252: // declare `field' before we code `expr', because otherwise
253: // situations can arise where `field' thinks it is assigned
254: // a local variable slot that is, in actuality, assigned to
255: // an entirely different variable. (Bug id 4076729)
256: ctx.declare(env, field);
257: expr.codeValue(env, ctx, asm);
258:
259: asm.add(where, opc_istore
260: + field.getType().getTypeCodeOffset(),
261: new LocalVariable(field, field.number));
262: } else {
263: ctx.declare(env, field);
264: if (expr != null) {
265: // an initial side effect, rather than an initial value
266: expr.code(env, ctx, asm);
267: }
268: }
269: }
270:
271: /**
272: * Print
273: */
274: public void print(PrintStream out, int indent) {
275: out.print("local ");
276: if (field != null) {
277: out.print(field + "#" + field.hashCode());
278: if (expr != null) {
279: out.print(" = ");
280: expr.print(out);
281: }
282: } else {
283: expr.print(out);
284: out.print(";");
285: }
286: }
287: }
|