1 /* 2 * Copyright (c) 1997, 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 26 package sun.tools.tree; 27 28 import sun.tools.java.*; 29 import sun.tools.tree.*; 30 import sun.tools.asm.Assembler; 31 32 /** 33 * A reference from one scope to another. 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 * 39 */ 40 41 public 42 class UplevelReference implements Constants { 43 /** 44 * The class in which the reference occurs. 45 */ 46 ClassDefinition client; 47 48 /** 49 * The field being referenced. 50 * It is always a final argument or a final local variable. 51 * (An uplevel reference to a field of a class C is fetched 52 * through an implicit uplevel reference to C.this, which is 53 * an argument.) 54 */ 55 LocalMember target; 56 57 /** 58 * The local variable which bears a copy of the target's value, 59 * for all methods of the client class. 60 * Its name is "this$C" for <code>this.C</code> or 61 * "val$x" for other target variables <code>x</code>. 62 * <p> 63 * This local variable is always a constructor argument, 64 * and is therefore usable only in the constructor and in initializers. 65 * All other methods use the local field. 66 * @see #localField 67 */ 68 LocalMember localArgument; 69 70 /** 71 * A private synthetic field of the client class which 72 * bears a copy of the target's value. 73 * The compiler tries to avoid creating it if possible. 74 * The field has the same name and type as the localArgument. 75 * @see #localArgument 76 */ 77 MemberDefinition localField; 78 79 /** 80 * The next item on the references list of the client. 81 */ 82 UplevelReference next; 83 84 /** 85 * constructor 86 */ UplevelReference(ClassDefinition client, LocalMember target)87 public UplevelReference(ClassDefinition client, LocalMember target) { 88 this.client = client; 89 this.target = target; 90 91 // Choose a name and build a variable declaration node. 92 Identifier valName; 93 if (target.getName().equals(idThis)) { 94 ClassDefinition tc = target.getClassDefinition(); 95 // It should always be true that tc.enclosingClassOf(client). 96 // If it were false, the numbering scheme would fail 97 // to produce unique names, since we'd be trying 98 // to number classes which were not in the sequence 99 // of enclosing scopes. The next paragraph of this 100 // code robustly deals with that possibility, however, 101 // by detecting name collisions and perturbing the names. 102 int depth = 0; 103 for (ClassDefinition pd = tc; !pd.isTopLevel(); pd = pd.getOuterClass()) { 104 // The inner classes specification states that the name of 105 // a private field containing a reference to the outermost 106 // enclosing instance is named "this$0". That outermost 107 // enclosing instance is always the innermost toplevel class. 108 depth += 1; 109 } 110 // In this example, T1,T2,T3 are all top-level (static), 111 // while I4,I5,I6,I7 are all inner. Each of the inner classes 112 // will have a single up-level "this$N" reference to the next 113 // class out. Only the outermost "this$0" will refer to a 114 // top-level class, T3. 115 // 116 // class T1 { 117 // static class T2 { 118 // static class T3 { 119 // class I4 { 120 // class I5 { 121 // class I6 { 122 // // at this point we have these fields in various places: 123 // // I4 this$0; I5 this$1; I6 this$2; 124 // } 125 // } 126 // class I7 { 127 // // I4 this$0; I7 this$1; 128 // } 129 // } 130 // } 131 // } 132 // } 133 valName = Identifier.lookup(prefixThis + depth); 134 } else { 135 valName = Identifier.lookup(prefixVal + target.getName()); 136 } 137 138 // Make reasonably certain that valName is unique to this client. 139 // (This check can be fooled by malicious naming of explicit 140 // constructor arguments, or of inherited fields.) 141 Identifier base = valName; 142 int tick = 0; 143 while (true) { 144 boolean failed = (client.getFirstMatch(valName) != null); 145 for (UplevelReference r = client.getReferences(); 146 r != null; r = r.next) { 147 if (r.target.getName().equals(valName)) { 148 failed = true; 149 } 150 } 151 if (!failed) { 152 break; 153 } 154 // try another name 155 valName = Identifier.lookup(base + "$" + (++tick)); 156 } 157 158 // Build the constructor argument. 159 // Like "this", it wil be shared equally by all constructors of client. 160 localArgument = new LocalMember(target.getWhere(), 161 client, 162 M_FINAL | M_SYNTHETIC, 163 target.getType(), 164 valName); 165 } 166 167 /** 168 * Insert self into a list of references. 169 * Maintain "isEarlierThan" as an invariant of the list. 170 * This is important (a) to maximize stability of signatures, 171 * and (b) to allow uplevel "this" parameters to come at the 172 * front of every argument list they appear in. 173 */ insertInto(UplevelReference references)174 public UplevelReference insertInto(UplevelReference references) { 175 if (references == null || isEarlierThan(references)) { 176 next = references; 177 return this; 178 } else { 179 UplevelReference prev = references; 180 while (!(prev.next == null || isEarlierThan(prev.next))) { 181 prev = prev.next; 182 } 183 next = prev.next; 184 prev.next = this; 185 return references; 186 } 187 } 188 189 /** 190 * Tells if self precedes the other in the canonical ordering. 191 */ isEarlierThan(UplevelReference other)192 public final boolean isEarlierThan(UplevelReference other) { 193 // Outer fields always come first. 194 if (isClientOuterField()) { 195 return true; 196 } else if (other.isClientOuterField()) { 197 return false; 198 } 199 200 // Now it doesn't matter what the order is; use string comparison. 201 LocalMember target2 = other.target; 202 Identifier name = target.getName(); 203 Identifier name2 = target2.getName(); 204 int cmp = name.toString().compareTo(name2.toString()); 205 if (cmp != 0) { 206 return cmp < 0; 207 } 208 Identifier cname = target.getClassDefinition().getName(); 209 Identifier cname2 = target2.getClassDefinition().getName(); 210 int ccmp = cname.toString().compareTo(cname2.toString()); 211 return ccmp < 0; 212 } 213 214 /** 215 * the target of this reference 216 */ getTarget()217 public final LocalMember getTarget() { 218 return target; 219 } 220 221 /** 222 * the local argument for this reference 223 */ getLocalArgument()224 public final LocalMember getLocalArgument() { 225 return localArgument; 226 } 227 228 /** 229 * the field allocated in the client for this reference 230 */ getLocalField()231 public final MemberDefinition getLocalField() { 232 return localField; 233 } 234 235 /** 236 * Get the local field, creating one if necessary. 237 * The client class must not be frozen. 238 */ getLocalField(Environment env)239 public final MemberDefinition getLocalField(Environment env) { 240 if (localField == null) { 241 makeLocalField(env); 242 } 243 return localField; 244 } 245 246 /** 247 * the client class 248 */ getClient()249 public final ClassDefinition getClient() { 250 return client; 251 } 252 253 /** 254 * the next reference in the client's list 255 */ getNext()256 public final UplevelReference getNext() { 257 return next; 258 } 259 260 /** 261 * Tell if this uplevel reference is the up-level "this" pointer 262 * of an inner class. Such references are treated differently 263 * than others, because they affect constructor calls across 264 * compilation units. 265 */ isClientOuterField()266 public boolean isClientOuterField() { 267 MemberDefinition outerf = client.findOuterMember(); 268 return (outerf != null) && (localField == outerf); 269 } 270 271 /** 272 * Tell if my local argument is directly available in this context. 273 * If not, the uplevel reference will have to be via a class field. 274 * <p> 275 * This must be called in a context which is local 276 * to the client of the uplevel reference. 277 */ localArgumentAvailable(Environment env, Context ctx)278 public boolean localArgumentAvailable(Environment env, Context ctx) { 279 MemberDefinition reff = ctx.field; 280 if (reff.getClassDefinition() != client) { 281 throw new CompilerError("localArgumentAvailable"); 282 } 283 return ( reff.isConstructor() 284 || reff.isVariable() 285 || reff.isInitializer() ); 286 } 287 288 /** 289 * Process an uplevel reference. 290 * The only decision to make at this point is whether 291 * to build a "localField" instance variable, which 292 * is done (lazily) when localArgumentAvailable() proves false. 293 */ noteReference(Environment env, Context ctx)294 public void noteReference(Environment env, Context ctx) { 295 if (localField == null && !localArgumentAvailable(env, ctx)) { 296 // We need an instance variable unless client is a constructor. 297 makeLocalField(env); 298 } 299 } 300 makeLocalField(Environment env)301 private void makeLocalField(Environment env) { 302 // Cannot alter decisions like this one at a late date. 303 client.referencesMustNotBeFrozen(); 304 int mod = M_PRIVATE | M_FINAL | M_SYNTHETIC; 305 localField = env.makeMemberDefinition(env, 306 localArgument.getWhere(), 307 client, null, 308 mod, 309 localArgument.getType(), 310 localArgument.getName(), 311 null, null, null); 312 } 313 314 /** 315 * Assuming noteReference() is all taken care of, 316 * build an uplevel reference. 317 * <p> 318 * This must be called in a context which is local 319 * to the client of the uplevel reference. 320 */ makeLocalReference(Environment env, Context ctx)321 public Expression makeLocalReference(Environment env, Context ctx) { 322 if (ctx.field.getClassDefinition() != client) { 323 throw new CompilerError("makeLocalReference"); 324 } 325 if (localArgumentAvailable(env, ctx)) { 326 return new IdentifierExpression(0, localArgument); 327 } else { 328 return makeFieldReference(env, ctx); 329 } 330 } 331 332 /** 333 * As with makeLocalReference(), build a locally-usable reference. 334 * Ignore the availability of local arguments; always use a class field. 335 */ makeFieldReference(Environment env, Context ctx)336 public Expression makeFieldReference(Environment env, Context ctx) { 337 Expression e = ctx.findOuterLink(env, 0, localField); 338 return new FieldExpression(0, e, localField); 339 } 340 341 /** 342 * During the inline phase, call this on a list of references 343 * for which the code phase will later emit arguments. 344 * It will make sure that any "double-uplevel" values 345 * needed by the callee are also present at the call site. 346 * <p> 347 * If any reference is a "ClientOuterField", it is skipped 348 * by this method (and by willCodeArguments). This is because 349 */ willCodeArguments(Environment env, Context ctx)350 public void willCodeArguments(Environment env, Context ctx) { 351 if (!isClientOuterField()) { 352 ctx.noteReference(env, target); 353 } 354 355 if (next != null) { 356 next.willCodeArguments(env, ctx); 357 } 358 } 359 360 /** 361 * Code is being generated for a call to a constructor of 362 * the client class. Push an argument for the constructor. 363 */ codeArguments(Environment env, Context ctx, Assembler asm, long where, MemberDefinition conField)364 public void codeArguments(Environment env, Context ctx, Assembler asm, 365 long where, MemberDefinition conField) { 366 if (!isClientOuterField()) { 367 Expression e = ctx.makeReference(env, target); 368 e.codeValue(env, ctx, asm); 369 } 370 371 if (next != null) { 372 next.codeArguments(env, ctx, asm, where, conField); 373 } 374 } 375 376 /** 377 * Code is being generated for a constructor of the client class. 378 * Emit code which initializes the instance. 379 */ codeInitialization(Environment env, Context ctx, Assembler asm, long where, MemberDefinition conField)380 public void codeInitialization(Environment env, Context ctx, Assembler asm, 381 long where, MemberDefinition conField) { 382 // If the reference is a clientOuterField, then the initialization 383 // code is generated in MethodExpression.makeVarInits(). 384 // (Fix for bug 4075063.) 385 if (localField != null && !isClientOuterField()) { 386 Expression e = ctx.makeReference(env, target); 387 Expression f = makeFieldReference(env, ctx); 388 e = new AssignExpression(e.getWhere(), f, e); 389 e.type = localField.getType(); 390 e.code(env, ctx, asm); 391 } 392 393 if (next != null) { 394 next.codeInitialization(env, ctx, asm, where, conField); 395 } 396 } 397 toString()398 public String toString() { 399 return "[" + localArgument + " in " + client + "]"; 400 } 401 } 402