blob: 5976d33bbca3c2a6a8a0d1117da0a6be9e19a1ec [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 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 */
37public
38class 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 */
49 public NewInstanceExpression(long where, Expression right, Expression args[]) {
50 super(NEWINSTANCE, where, Type.tError, right, args);
51 }
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 */
64 public Expression getOuterArg() {
65 return outerArg;
66 }
67
68 int precedence() {
69 return 100;
70 }
71
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 */
86 public Vset checkValue(Environment env, Context ctx, Vset vset, Hashtable 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 */
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 */
369 public Vset check(Environment env, Context ctx, Vset vset, Hashtable exp) {
370 return checkValue(env, ctx, vset, exp);
371 }
372
373 /**
374 * Inline
375 */
376 final int MAXINLINECOST = Statement.MAXINLINECOST;
377
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
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
412 public Expression inline(Environment env, Context ctx) {
413 return inlineValue(env, ctx);
414 }
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
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 */
484 public void code(Environment env, Context ctx, Assembler asm) {
485 codeCommon(env, ctx, asm, false);
486 }
487 public void codeValue(Environment env, Context ctx, Assembler asm) {
488 codeCommon(env, ctx, asm, true);
489 }
490 private void codeCommon(Environment env, Context ctx, Assembler asm,
491 boolean forValue) {
492 asm.add(where, opc_new, field.getClassDeclaration());
493 if (forValue) {
494 asm.add(where, opc_dup);
495 }
496
497 ClassDefinition refc = field.getClassDefinition();
498 UplevelReference r = refc.getReferencesFrozen();
499
500 if (r != null) {
501 r.codeArguments(env, ctx, asm, where, field);
502 }
503
504 if (outerArg != null) {
505 outerArg.codeValue(env, ctx, asm);
506 switch (outerArg.op) {
507 case THIS:
508 case SUPER:
509 case NEW:
510 // guaranteed non-null
511 break;
512 case FIELD: {
513 MemberDefinition f = ((FieldExpression)outerArg).field;
514 if (f != null && f.isNeverNull()) {
515 break;
516 }
517 // else fall through:
518 }
519 default:
520 // Test for nullity by invoking some trivial operation
521 // that can throw a NullPointerException.
522 try {
523 ClassDefinition c = env.getClassDefinition(idJavaLangObject);
524 MemberDefinition getc = c.getFirstMatch(idGetClass);
525 asm.add(where, opc_dup);
526 asm.add(where, opc_invokevirtual, getc);
527 asm.add(where, opc_pop);
528 } catch (ClassNotFound e) {
529 }
530 }
531 }
532
533 if (implMethod != null) {
534 // Constructor call will be via an access method.
535 // Pass 'null' as the value of the dummy argument.
536 asm.add(where, opc_aconst_null);
537 }
538
539 for (int i = 0 ; i < args.length ; i++) {
540 args[i].codeValue(env, ctx, asm);
541 }
542 asm.add(where, opc_invokespecial,
543 ((implMethod != null) ? implMethod : field));
544 }
545}