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 26 package sun.tools.tree; 27 28 import sun.tools.java.*; 29 import sun.tools.asm.Assembler; 30 import java.util.Hashtable; 31 32 /** 33 * WARNING: The contents of this source file are not part of any 34 * supported API. Code that depends on them does so at its own risk: 35 * they are subject to change or removal without notice. 36 */ 37 public 38 class NewInstanceExpression extends NaryExpression { 39 MemberDefinition field; 40 Expression outerArg; 41 ClassDefinition body; 42 43 // Access method for constructor, if needed. 44 MemberDefinition implMethod = null; 45 46 /** 47 * Constructor 48 */ NewInstanceExpression(long where, Expression right, Expression args[])49 public NewInstanceExpression(long where, Expression right, Expression args[]) { 50 super(NEWINSTANCE, where, Type.tError, right, args); 51 } NewInstanceExpression(long where, Expression right, Expression args[], Expression outerArg, ClassDefinition body)52 public NewInstanceExpression(long where, Expression right, 53 Expression args[], 54 Expression outerArg, ClassDefinition body) { 55 this(where, right, args); 56 this.outerArg = outerArg; 57 this.body = body; 58 } 59 60 /** 61 * From the "new" in an expression of the form outer.new InnerCls(...), 62 * return the "outer" expression, or null if there is none. 63 */ getOuterArg()64 public Expression getOuterArg() { 65 return outerArg; 66 } 67 precedence()68 int precedence() { 69 return 100; 70 } 71 order()72 public Expression order() { 73 // act like a method or field reference expression: 74 if (outerArg != null && opPrecedence[FIELD] > outerArg.precedence()) { 75 UnaryExpression e = (UnaryExpression)outerArg; 76 outerArg = e.right; 77 e.right = order(); 78 return e; 79 } 80 return this; 81 } 82 83 /** 84 * Check expression type 85 */ checkValue(Environment env, Context ctx, Vset vset, Hashtable<Object, Object> exp)86 public Vset checkValue(Environment env, Context ctx, Vset vset, Hashtable<Object, Object> exp) { 87 // What type? 88 ClassDefinition def = null; 89 90 Expression alreadyChecked = null; 91 92 try { 93 if (outerArg != null) { 94 vset = outerArg.checkValue(env, ctx, vset, exp); 95 96 // Remember the expression that we already checked 97 // so that we don't attempt to check it again when 98 // it appears as an argument to the constructor. 99 // Fix for 4030426. 100 alreadyChecked = outerArg; 101 102 // Check outerArg and the type name together. 103 Identifier typeName = FieldExpression.toIdentifier(right); 104 105 // According to the inner classes spec, the type name in a 106 // qualified 'new' expression must be a single identifier. 107 if (typeName != null && typeName.isQualified()) { 108 env.error(where, "unqualified.name.required", typeName); 109 } 110 111 if (typeName == null || !outerArg.type.isType(TC_CLASS)) { 112 if (!outerArg.type.isType(TC_ERROR)) { 113 env.error(where, "invalid.field.reference", 114 idNew, outerArg.type); 115 } 116 outerArg = null; 117 } else { 118 // Don't perform checks on components of qualified name 119 // ('getQualifiedClassDefinition'), because a qualified 120 // name is illegal in this context, and will have previously 121 // been reported as an error. 122 ClassDefinition oc = env.getClassDefinition(outerArg.type); 123 Identifier nm = oc.resolveInnerClass(env, typeName); 124 right = new TypeExpression(right.where, Type.tClass(nm)); 125 // Check access directly, since we're not calling toType(). 126 env.resolve(right.where, ctx.field.getClassDefinition(), 127 right.type); 128 // and fall through to env.getClassDefinition() below 129 } 130 } 131 132 if (!(right instanceof TypeExpression)) { 133 // The call to 'toType' should perform component access checks. 134 right = new TypeExpression(right.where, right.toType(env, ctx)); 135 } 136 137 if (right.type.isType(TC_CLASS)) 138 def = env.getClassDefinition(right.type); 139 } catch (AmbiguousClass ee) { 140 env.error(where, "ambig.class", ee.name1, ee.name2); 141 } catch (ClassNotFound ee) { 142 env.error(where, "class.not.found", ee.name, ctx.field); 143 } 144 145 Type t = right.type; 146 boolean hasErrors = t.isType(TC_ERROR); 147 148 if (!t.isType(TC_CLASS)) { 149 if (!hasErrors) { 150 env.error(where, "invalid.arg.type", t, opNames[op]); 151 hasErrors = true; 152 } 153 } 154 155 // If we failed to find a class or a class was ambiguous, def 156 // may be null. Bail out. This allows us to report multiple 157 // unfound or ambiguous classes rather than tripping over an 158 // internal compiler error. 159 if (def == null) { 160 type = Type.tError; 161 return vset; 162 } 163 164 // Add an extra argument, maybe. 165 Expression args[] = this.args; 166 args = NewInstanceExpression. 167 insertOuterLink(env, ctx, where, def, outerArg, args); 168 if (args.length > this.args.length) 169 outerArg = args[0]; // recopy the checked arg 170 else if (outerArg != null) 171 // else set it to void (maybe it has a side-effect) 172 outerArg = new CommaExpression(outerArg.where, outerArg, null); 173 174 // Compose a list of argument types 175 Type argTypes[] = new Type[args.length]; 176 177 for (int i = 0 ; i < args.length ; i++) { 178 // Don't check 'outerArg' again. Fix for 4030426. 179 if (args[i] != alreadyChecked) { 180 vset = args[i].checkValue(env, ctx, vset, exp); 181 } 182 argTypes[i] = args[i].type; 183 hasErrors = hasErrors || argTypes[i].isType(TC_ERROR); 184 } 185 186 try { 187 // Check if there are any type errors in the arguments 188 if (hasErrors) { 189 type = Type.tError; 190 return vset; 191 } 192 193 194 // Get the source class that this declaration appears in. 195 ClassDefinition sourceClass = ctx.field.getClassDefinition(); 196 197 ClassDeclaration c = env.getClassDeclaration(t); 198 199 // If this is an anonymous class, handle it specially now. 200 if (body != null) { 201 // The current package. 202 Identifier packageName = sourceClass.getName().getQualifier(); 203 204 // This is an anonymous class. 205 ClassDefinition superDef = null; 206 if (def.isInterface()) { 207 // For interfaces, our superclass is java.lang.Object. 208 // We could just assume that java.lang.Object has 209 // one constructor with no arguments in the code 210 // that follows, but we don't. This way, if Object 211 // grows a new constructor (unlikely) then the 212 // compiler should handle it. 213 superDef = env.getClassDefinition(idJavaLangObject); 214 } else { 215 // Otherwise, def is actually our superclass. 216 superDef = def; 217 } 218 // Try to find a matching constructor in our superclass. 219 MemberDefinition constructor = 220 superDef.matchAnonConstructor(env, packageName, argTypes); 221 if (constructor != null) { 222 // We've found one. Process the body. 223 // 224 // Note that we are passing in the constructors' argument 225 // types, rather than the argument types of the actual 226 // expressions, to checkLocalClass(). Previously, 227 // the expression types were passed in. This could 228 // lead to trouble when one of the argument types was 229 // the special internal type tNull. (bug 4054689). 230 if (tracing) 231 env.dtEvent( 232 "NewInstanceExpression.checkValue: ANON CLASS " + 233 body + " SUPER " + def); 234 vset = body.checkLocalClass(env, ctx, vset, 235 def, args, 236 constructor.getType() 237 .getArgumentTypes()); 238 239 // Set t to be the true type of this expression. 240 // (bug 4102056). 241 t = body.getClassDeclaration().getType(); 242 243 def = body; 244 } 245 } else { 246 // Check if it is an interface 247 if (def.isInterface()) { 248 env.error(where, "new.intf", c); 249 return vset; 250 } 251 252 // Check for abstract class 253 if (def.mustBeAbstract(env)) { 254 env.error(where, "new.abstract", c); 255 return vset; 256 } 257 } 258 259 // Get the constructor that the "new" expression should call. 260 field = def.matchMethod(env, sourceClass, idInit, argTypes); 261 262 // Report an error if there is no matching constructor. 263 if (field == null) { 264 MemberDefinition anyInit = def.findAnyMethod(env, idInit); 265 if (anyInit != null && 266 new MethodExpression(where, right, anyInit, args) 267 .diagnoseMismatch(env, args, argTypes)) 268 return vset; 269 String sig = c.getName().getName().toString(); 270 sig = Type.tMethod(Type.tError, argTypes).typeString(sig, false, false); 271 env.error(where, "unmatched.constr", sig, c); 272 return vset; 273 } 274 275 if (field.isPrivate()) { 276 ClassDefinition cdef = field.getClassDefinition(); 277 if (cdef != sourceClass) { 278 // Use access method. 279 implMethod = cdef.getAccessMember(env, ctx, field, false); 280 } 281 } 282 283 // Check for abstract anonymous class 284 if (def.mustBeAbstract(env)) { 285 env.error(where, "new.abstract", c); 286 return vset; 287 } 288 289 if (field.reportDeprecated(env)) { 290 env.error(where, "warn.constr.is.deprecated", 291 field, field.getClassDefinition()); 292 } 293 294 // According to JLS 6.6.2, a protected constructor may be accessed 295 // by a class instance creation expression only from within the 296 // package in which it is defined. 297 if (field.isProtected() && 298 !(sourceClass.getName().getQualifier().equals( 299 field.getClassDeclaration().getName().getQualifier()))) { 300 env.error(where, "invalid.protected.constructor.use", 301 sourceClass); 302 } 303 304 } catch (ClassNotFound ee) { 305 env.error(where, "class.not.found", ee.name, opNames[op]); 306 return vset; 307 308 } catch (AmbiguousMember ee) { 309 env.error(where, "ambig.constr", ee.field1, ee.field2); 310 return vset; 311 } 312 313 // Cast arguments 314 argTypes = field.getType().getArgumentTypes(); 315 for (int i = 0 ; i < args.length ; i++) { 316 args[i] = convert(env, ctx, argTypes[i], args[i]); 317 } 318 if (args.length > this.args.length) { 319 outerArg = args[0]; // recopy the checked arg 320 // maintain an accurate tree 321 for (int i = 1 ; i < args.length ; i++) { 322 this.args[i-1] = args[i]; 323 } 324 } 325 326 // Throw the declared exceptions. 327 ClassDeclaration exceptions[] = field.getExceptions(env); 328 for (int i = 0 ; i < exceptions.length ; i++) { 329 if (exp.get(exceptions[i]) == null) { 330 exp.put(exceptions[i], this); 331 } 332 } 333 334 type = t; 335 336 return vset; 337 } 338 339 /** 340 * Given a list of arguments for a constructor, 341 * return a possibly modified list which includes the hidden 342 * argument which initializes the uplevel self pointer. 343 * @arg def the class which perhaps contains an outer link. 344 * @arg outerArg if non-null, an explicit location in which to construct. 345 */ insertOuterLink(Environment env, Context ctx, long where, ClassDefinition def, Expression outerArg, Expression args[])346 public static Expression[] insertOuterLink(Environment env, Context ctx, 347 long where, ClassDefinition def, 348 Expression outerArg, 349 Expression args[]) { 350 if (!def.isTopLevel() && !def.isLocal()) { 351 Expression args2[] = new Expression[1+args.length]; 352 System.arraycopy(args, 0, args2, 1, args.length); 353 try { 354 if (outerArg == null) 355 outerArg = ctx.findOuterLink(env, where, 356 def.findAnyMethod(env, idInit)); 357 } catch (ClassNotFound e) { 358 // die somewhere else 359 } 360 args2[0] = outerArg; 361 args = args2; 362 } 363 return args; 364 } 365 366 /** 367 * Check void expression 368 */ check(Environment env, Context ctx, Vset vset, Hashtable<Object, Object> exp)369 public Vset check(Environment env, Context ctx, Vset vset, Hashtable<Object, Object> exp) { 370 return checkValue(env, ctx, vset, exp); 371 } 372 373 /** 374 * Inline 375 */ 376 final int MAXINLINECOST = Statement.MAXINLINECOST; 377 copyInline(Context ctx)378 public Expression copyInline(Context ctx) { 379 NewInstanceExpression e = (NewInstanceExpression)super.copyInline(ctx); 380 if (outerArg != null) { 381 e.outerArg = outerArg.copyInline(ctx); 382 } 383 return e; 384 } 385 inlineNewInstance(Environment env, Context ctx, Statement s)386 Expression inlineNewInstance(Environment env, Context ctx, Statement s) { 387 if (env.dump()) { 388 System.out.println("INLINE NEW INSTANCE " + field + " in " + ctx.field); 389 } 390 LocalMember v[] = LocalMember.copyArguments(ctx, field); 391 Statement body[] = new Statement[v.length + 2]; 392 393 int o = 1; 394 if (outerArg != null && !outerArg.type.isType(TC_VOID)) { 395 o = 2; 396 body[1] = new VarDeclarationStatement(where, v[1], outerArg); 397 } else if (outerArg != null) { 398 body[0] = new ExpressionStatement(where, outerArg); 399 } 400 for (int i = 0 ; i < args.length ; i++) { 401 body[i+o] = new VarDeclarationStatement(where, v[i+o], args[i]); 402 } 403 //System.out.print("BEFORE:"); s.print(System.out); System.out.println(); 404 body[body.length - 1] = (s != null) ? s.copyInline(ctx, false) : null; 405 //System.out.print("COPY:"); body[body.length - 1].print(System.out); System.out.println(); 406 //System.out.print("AFTER:"); s.print(System.out); System.out.println(); 407 LocalMember.doneWithArguments(ctx, v); 408 409 return new InlineNewInstanceExpression(where, type, field, new CompoundStatement(where, body)).inline(env, ctx); 410 } 411 inline(Environment env, Context ctx)412 public Expression inline(Environment env, Context ctx) { 413 return inlineValue(env, ctx); 414 } inlineValue(Environment env, Context ctx)415 public Expression inlineValue(Environment env, Context ctx) { 416 if (body != null) { 417 body.inlineLocalClass(env); 418 } 419 ClassDefinition refc = field.getClassDefinition(); 420 UplevelReference r = refc.getReferencesFrozen(); 421 if (r != null) { 422 r.willCodeArguments(env, ctx); 423 } 424 //right = right.inlineValue(env, ctx); 425 426 try { 427 if (outerArg != null) { 428 if (outerArg.type.isType(TC_VOID)) 429 outerArg = outerArg.inline(env, ctx); 430 else 431 outerArg = outerArg.inlineValue(env, ctx); 432 } 433 for (int i = 0 ; i < args.length ; i++) { 434 args[i] = args[i].inlineValue(env, ctx); 435 } 436 // This 'false' that fy put in is inexplicable to me 437 // the decision to not inline new instance expressions 438 // should be revisited. - dps 439 if (false && env.opt() && field.isInlineable(env, false) && 440 (!ctx.field.isInitializer()) && ctx.field.isMethod() && 441 (ctx.getInlineMemberContext(field) == null)) { 442 Statement s = (Statement)field.getValue(env); 443 if ((s == null) 444 || (s.costInline(MAXINLINECOST, env, ctx) < MAXINLINECOST)) { 445 return inlineNewInstance(env, ctx, s); 446 } 447 } 448 } catch (ClassNotFound e) { 449 throw new CompilerError(e); 450 } 451 if (outerArg != null && outerArg.type.isType(TC_VOID)) { 452 Expression e = outerArg; 453 outerArg = null; 454 return new CommaExpression(where, e, this); 455 } 456 return this; 457 } 458 costInline(int thresh, Environment env, Context ctx)459 public int costInline(int thresh, Environment env, Context ctx) { 460 if (body != null) { 461 return thresh; // don't copy classes... 462 } 463 if (ctx == null) { 464 return 2 + super.costInline(thresh, env, ctx); 465 } 466 // sourceClass is the current class trying to inline this method 467 ClassDefinition sourceClass = ctx.field.getClassDefinition(); 468 try { 469 // We only allow the inlining if the current class can access 470 // the field and the field's class; 471 if ( sourceClass.permitInlinedAccess(env, field.getClassDeclaration()) 472 && sourceClass.permitInlinedAccess(env, field)) { 473 return 2 + super.costInline(thresh, env, ctx); 474 } 475 } catch (ClassNotFound e) { 476 } 477 return thresh; 478 } 479 480 481 /** 482 * Code 483 */ code(Environment env, Context ctx, Assembler asm)484 public void code(Environment env, Context ctx, Assembler asm) { 485 codeCommon(env, ctx, asm, false); 486 } codeValue(Environment env, Context ctx, Assembler asm)487 public void codeValue(Environment env, Context ctx, Assembler asm) { 488 codeCommon(env, ctx, asm, true); 489 } 490 @SuppressWarnings("fallthrough") codeCommon(Environment env, Context ctx, Assembler asm, boolean forValue)491 private void codeCommon(Environment env, Context ctx, Assembler asm, 492 boolean forValue) { 493 asm.add(where, opc_new, field.getClassDeclaration()); 494 if (forValue) { 495 asm.add(where, opc_dup); 496 } 497 498 ClassDefinition refc = field.getClassDefinition(); 499 UplevelReference r = refc.getReferencesFrozen(); 500 501 if (r != null) { 502 r.codeArguments(env, ctx, asm, where, field); 503 } 504 505 if (outerArg != null) { 506 outerArg.codeValue(env, ctx, asm); 507 switch (outerArg.op) { 508 case THIS: 509 case SUPER: 510 case NEW: 511 // guaranteed non-null 512 break; 513 case FIELD: { 514 MemberDefinition f = ((FieldExpression)outerArg).field; 515 if (f != null && f.isNeverNull()) { 516 break; 517 } 518 // else fall through: 519 } 520 default: 521 // Test for nullity by invoking some trivial operation 522 // that can throw a NullPointerException. 523 try { 524 ClassDefinition c = env.getClassDefinition(idJavaLangObject); 525 MemberDefinition getc = c.getFirstMatch(idGetClass); 526 asm.add(where, opc_dup); 527 asm.add(where, opc_invokevirtual, getc); 528 asm.add(where, opc_pop); 529 } catch (ClassNotFound e) { 530 } 531 } 532 } 533 534 if (implMethod != null) { 535 // Constructor call will be via an access method. 536 // Pass 'null' as the value of the dummy argument. 537 asm.add(where, opc_aconst_null); 538 } 539 540 for (int i = 0 ; i < args.length ; i++) { 541 args[i].codeValue(env, ctx, asm); 542 } 543 asm.add(where, opc_invokespecial, 544 ((implMethod != null) ? implMethod : field)); 545 } 546 } 547