blob: 5388e89e72ab41f19ffc3fc8b470373942d84ada [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1994-2003 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.tools.tree;
27
28import sun.tools.java.*;
29import sun.tools.asm.Assembler;
30import sun.tools.asm.LocalVariable;
31import java.io.PrintStream;
32import java.util.Hashtable;
33
34/**
35 * WARNING: The contents of this source file are not part of any
36 * supported API. Code that depends on them does so at its own risk:
37 * they are subject to change or removal without notice.
38 */
39public
40class VarDeclarationStatement extends Statement {
41 LocalMember field;
42 Expression expr;
43
44 /**
45 * Constructor
46 */
47 public VarDeclarationStatement(long where, Expression expr) {
48 super(VARDECLARATION, where);
49 this.expr = expr;
50 }
51 public VarDeclarationStatement(long where, LocalMember field, Expression expr) {
52 super(VARDECLARATION, where);
53 this.field = field;
54 this.expr = expr;
55 }
56
57 /**
58 * Check statement
59 */
60 Vset checkDeclaration(Environment env, Context ctx, Vset vset, int mod, Type t, Hashtable exp) {
61 if (labels != null) {
62 env.error(where, "declaration.with.label", labels[0]);
63 }
64 if (field != null) {
65 if (ctx.getLocalClass(field.getName()) != null
66 && field.isInnerClass()) {
67 env.error(where, "local.class.redefined", field.getName());
68 }
69
70 ctx.declare(env, field);
71 if (field.isInnerClass()) {
72 ClassDefinition body = field.getInnerClass();
73 try {
74 vset = body.checkLocalClass(env, ctx, vset,
75 null, null, null);
76 } catch (ClassNotFound ee) {
77 env.error(where, "class.not.found", ee.name, opNames[op]);
78 }
79 return vset;
80 }
81 vset.addVar(field.number);
82 return (expr != null) ? expr.checkValue(env, ctx, vset, exp) : vset;
83 }
84
85 // Argument 'expr' is either an IdentifierExpression for a declaration of
86 // the form 'type x' or an AssignmentExpression for a declaration of the
87 // form 'type x = initvalue'. Note that these expressions are treated
88 // specially in this context, and don't have much connection to their ordinary
89 // meaning.
90
91 Expression e = expr;
92
93 if (e.op == ASSIGN) {
94 expr = ((AssignExpression)e).right;
95 e = ((AssignExpression)e).left;
96 } else {
97 expr = null;
98 }
99
100 boolean declError = t.isType(TC_ERROR);
101 while (e.op == ARRAYACCESS) {
102 ArrayAccessExpression array = (ArrayAccessExpression)e;
103 if (array.index != null) {
104 env.error(array.index.where, "array.dim.in.type");
105 declError = true;
106 }
107 e = array.right;
108 t = Type.tArray(t);
109 }
110 if (e.op == IDENT) {
111 Identifier id = ((IdentifierExpression)e).id;
112 if (ctx.getLocalField(id) != null) {
113 env.error(where, "local.redefined", id);
114 }
115
116 field = new LocalMember(e.where, ctx.field.getClassDefinition(), mod, t, id);
117 ctx.declare(env, field);
118
119 if (expr != null) {
120 vset = expr.checkInitializer(env, ctx, vset, t, exp);
121 expr = convert(env, ctx, t, expr);
122 field.setValue(expr); // for the sake of non-blank finals
123 if (field.isConstant()) {
124 // Keep in mind that isConstant() only means expressions
125 // that are constant according to the JLS. They might
126 // not be either constants or evaluable (eg. 1/0).
127 field.addModifiers(M_INLINEABLE);
128 }
129 vset.addVar(field.number);
130 } else if (declError) {
131 vset.addVar(field.number);
132 } else {
133 vset.addVarUnassigned(field.number);
134 }
135 return vset;
136 }
137 env.error(e.where, "invalid.decl");
138 return vset;
139 }
140
141 /**
142 * Inline
143 */
144 public Statement inline(Environment env, Context ctx) {
145 if (field.isInnerClass()) {
146 ClassDefinition body = field.getInnerClass();
147 body.inlineLocalClass(env);
148 return null;
149 }
150
151 // Don't generate code for variable if unused and
152 // optimization is on, whether or not debugging is on
153 if (env.opt() && !field.isUsed()) {
154 return new ExpressionStatement(where, expr).inline(env, ctx);
155 }
156
157 ctx.declare(env, field);
158
159 if (expr != null) {
160 expr = expr.inlineValue(env, ctx);
161 field.setValue(expr); // for the sake of non-blank finals
162 if (env.opt() && (field.writecount == 0)) {
163 if (expr.op == IDENT) {
164
165 // This code looks like it tests whether a final variable
166 // is being initialized by an identifier expression.
167 // Then if the identifier is a local of the same method
168 // it makes the final variable eligible to be inlined.
169 // BUT: why isn't the local also checked to make sure
170 // it is itself final? Unknown.
171
172 IdentifierExpression e = (IdentifierExpression)expr;
173 if (e.field.isLocal() && ((ctx = ctx.getInlineContext()) != null) &&
174 (((LocalMember)e.field).number < ctx.varNumber)) {
175 //System.out.println("FINAL IDENT = " + field + " in " + ctx.field);
176 field.setValue(expr);
177 field.addModifiers(M_INLINEABLE);
178
179 // The two lines below used to elide the declaration
180 // of inlineable variables, on the theory that there
181 // wouldn't be any references. But this breaks the
182 // translation of nested classes, which might refer to
183 // the variable.
184
185 //expr = null;
186 //return null;
187 }
188 }
189 if (expr.isConstant() || (expr.op == THIS) || (expr.op == SUPER)) {
190 //System.out.println("FINAL = " + field + " in " + ctx.field);
191 field.setValue(expr);
192 field.addModifiers(M_INLINEABLE);
193
194 // The two lines below used to elide the declaration
195 // of inlineable variables, on the theory that there
196 // wouldn't be any references. But this breaks the
197 // translation of nested classes, which might refer to
198 // the variable. Fix for 4073244.
199
200 //expr = null;
201 //return null;
202 }
203 }
204 }
205 return this;
206 }
207
208 /**
209 * Create a copy of the statement for method inlining
210 */
211 public Statement copyInline(Context ctx, boolean valNeeded) {
212 VarDeclarationStatement s = (VarDeclarationStatement)clone();
213 if (expr != null) {
214 s.expr = expr.copyInline(ctx);
215 }
216 return s;
217 }
218
219 /**
220 * The cost of inlining this statement
221 */
222 public int costInline(int thresh, Environment env, Context ctx) {
223 if (field != null && field.isInnerClass()) {
224 return thresh; // don't copy classes...
225 }
226 return (expr != null) ? expr.costInline(thresh, env, ctx) : 0;
227 }
228
229 /**
230 * Code
231 */
232 public void code(Environment env, Context ctx, Assembler asm) {
233 if (expr != null && !expr.type.isType(TC_VOID)) {
234 // The two lines of code directly following this comment used
235 // to be in the opposite order. They were switched so that
236 // lines like the following:
237 //
238 // int j = (j = 4);
239 //
240 // will compile correctly. (Constructions like the above are
241 // legal. JLS 14.3.2 says that the scope of a local variable
242 // includes its own initializer.) It is important that we
243 // declare `field' before we code `expr', because otherwise
244 // situations can arise where `field' thinks it is assigned
245 // a local variable slot that is, in actuality, assigned to
246 // an entirely different variable. (Bug id 4076729)
247 ctx.declare(env, field);
248 expr.codeValue(env, ctx, asm);
249
250 asm.add(where, opc_istore + field.getType().getTypeCodeOffset(),
251 new LocalVariable(field, field.number));
252 } else {
253 ctx.declare(env, field);
254 if (expr != null) {
255 // an initial side effect, rather than an initial value
256 expr.code(env, ctx, asm);
257 }
258 }
259 }
260
261 /**
262 * Print
263 */
264 public void print(PrintStream out, int indent) {
265 out.print("local ");
266 if (field != null) {
267 out.print(field + "#" + field.hashCode());
268 if (expr != null) {
269 out.print(" = ");
270 expr.print(out);
271 }
272 } else {
273 expr.print(out);
274 out.print(";");
275 }
276 }
277}