1/* 2 * Copyright (c) 1994, 2003, Oracle and/or its affiliates. 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * 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<Object, Object> 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} 278