001: /*
002: * Copyright 1994-2003 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package sun.tools.tree;
027:
028: import sun.tools.java.*;
029: import sun.tools.asm.Assembler;
030: import java.util.Hashtable;
031:
032: /**
033: * WARNING: The contents of this source file are not part of any
034: * supported API. Code that depends on them does so at its own risk:
035: * they are subject to change or removal without notice.
036: */
037: public class NewInstanceExpression extends NaryExpression {
038: MemberDefinition field;
039: Expression outerArg;
040: ClassDefinition body;
041:
042: // Access method for constructor, if needed.
043: MemberDefinition implMethod = null;
044:
045: /**
046: * Constructor
047: */
048: public NewInstanceExpression(long where, Expression right,
049: Expression args[]) {
050: super (NEWINSTANCE, where, Type.tError, right, args);
051: }
052:
053: public NewInstanceExpression(long where, Expression right,
054: Expression args[], Expression outerArg, ClassDefinition body) {
055: this (where, right, args);
056: this .outerArg = outerArg;
057: this .body = body;
058: }
059:
060: /**
061: * From the "new" in an expression of the form outer.new InnerCls(...),
062: * return the "outer" expression, or null if there is none.
063: */
064: public Expression getOuterArg() {
065: return outerArg;
066: }
067:
068: int precedence() {
069: return 100;
070: }
071:
072: public Expression order() {
073: // act like a method or field reference expression:
074: if (outerArg != null
075: && opPrecedence[FIELD] > outerArg.precedence()) {
076: UnaryExpression e = (UnaryExpression) outerArg;
077: outerArg = e.right;
078: e.right = order();
079: return e;
080: }
081: return this ;
082: }
083:
084: /**
085: * Check expression type
086: */
087: public Vset checkValue(Environment env, Context ctx, Vset vset,
088: Hashtable exp) {
089: // What type?
090: ClassDefinition def = null;
091:
092: Expression alreadyChecked = null;
093:
094: try {
095: if (outerArg != null) {
096: vset = outerArg.checkValue(env, ctx, vset, exp);
097:
098: // Remember the expression that we already checked
099: // so that we don't attempt to check it again when
100: // it appears as an argument to the constructor.
101: // Fix for 4030426.
102: alreadyChecked = outerArg;
103:
104: // Check outerArg and the type name together.
105: Identifier typeName = FieldExpression
106: .toIdentifier(right);
107:
108: // According to the inner classes spec, the type name in a
109: // qualified 'new' expression must be a single identifier.
110: if (typeName != null && typeName.isQualified()) {
111: env.error(where, "unqualified.name.required",
112: typeName);
113: }
114:
115: if (typeName == null || !outerArg.type.isType(TC_CLASS)) {
116: if (!outerArg.type.isType(TC_ERROR)) {
117: env.error(where, "invalid.field.reference",
118: idNew, outerArg.type);
119: }
120: outerArg = null;
121: } else {
122: // Don't perform checks on components of qualified name
123: // ('getQualifiedClassDefinition'), because a qualified
124: // name is illegal in this context, and will have previously
125: // been reported as an error.
126: ClassDefinition oc = env
127: .getClassDefinition(outerArg.type);
128: Identifier nm = oc.resolveInnerClass(env, typeName);
129: right = new TypeExpression(right.where, Type
130: .tClass(nm));
131: // Check access directly, since we're not calling toType().
132: env.resolve(right.where, ctx.field
133: .getClassDefinition(), right.type);
134: // and fall through to env.getClassDefinition() below
135: }
136: }
137:
138: if (!(right instanceof TypeExpression)) {
139: // The call to 'toType' should perform component access checks.
140: right = new TypeExpression(right.where, right.toType(
141: env, ctx));
142: }
143:
144: if (right.type.isType(TC_CLASS))
145: def = env.getClassDefinition(right.type);
146: } catch (AmbiguousClass ee) {
147: env.error(where, "ambig.class", ee.name1, ee.name2);
148: } catch (ClassNotFound ee) {
149: env.error(where, "class.not.found", ee.name, ctx.field);
150: }
151:
152: Type t = right.type;
153: boolean hasErrors = t.isType(TC_ERROR);
154:
155: if (!t.isType(TC_CLASS)) {
156: if (!hasErrors) {
157: env.error(where, "invalid.arg.type", t, opNames[op]);
158: hasErrors = true;
159: }
160: }
161:
162: // If we failed to find a class or a class was ambiguous, def
163: // may be null. Bail out. This allows us to report multiple
164: // unfound or ambiguous classes rather than tripping over an
165: // internal compiler error.
166: if (def == null) {
167: type = Type.tError;
168: return vset;
169: }
170:
171: // Add an extra argument, maybe.
172: Expression args[] = this .args;
173: args = NewInstanceExpression.insertOuterLink(env, ctx, where,
174: def, outerArg, args);
175: if (args.length > this .args.length)
176: outerArg = args[0]; // recopy the checked arg
177: else if (outerArg != null)
178: // else set it to void (maybe it has a side-effect)
179: outerArg = new CommaExpression(outerArg.where, outerArg,
180: null);
181:
182: // Compose a list of argument types
183: Type argTypes[] = new Type[args.length];
184:
185: for (int i = 0; i < args.length; i++) {
186: // Don't check 'outerArg' again. Fix for 4030426.
187: if (args[i] != alreadyChecked) {
188: vset = args[i].checkValue(env, ctx, vset, exp);
189: }
190: argTypes[i] = args[i].type;
191: hasErrors = hasErrors || argTypes[i].isType(TC_ERROR);
192: }
193:
194: try {
195: // Check if there are any type errors in the arguments
196: if (hasErrors) {
197: type = Type.tError;
198: return vset;
199: }
200:
201: // Get the source class that this declaration appears in.
202: ClassDefinition sourceClass = ctx.field
203: .getClassDefinition();
204:
205: ClassDeclaration c = env.getClassDeclaration(t);
206:
207: // If this is an anonymous class, handle it specially now.
208: if (body != null) {
209: // The current package.
210: Identifier packageName = sourceClass.getName()
211: .getQualifier();
212:
213: // This is an anonymous class.
214: ClassDefinition super Def = null;
215: if (def.isInterface()) {
216: // For interfaces, our superclass is java.lang.Object.
217: // We could just assume that java.lang.Object has
218: // one constructor with no arguments in the code
219: // that follows, but we don't. This way, if Object
220: // grows a new constructor (unlikely) then the
221: // compiler should handle it.
222: super Def = env.getClassDefinition(idJavaLangObject);
223: } else {
224: // Otherwise, def is actually our superclass.
225: super Def = def;
226: }
227: // Try to find a matching constructor in our superclass.
228: MemberDefinition constructor = super Def
229: .matchAnonConstructor(env, packageName,
230: argTypes);
231: if (constructor != null) {
232: // We've found one. Process the body.
233: //
234: // Note that we are passing in the constructors' argument
235: // types, rather than the argument types of the actual
236: // expressions, to checkLocalClass(). Previously,
237: // the expression types were passed in. This could
238: // lead to trouble when one of the argument types was
239: // the special internal type tNull. (bug 4054689).
240: if (tracing)
241: env
242: .dtEvent("NewInstanceExpression.checkValue: ANON CLASS "
243: + body + " SUPER " + def);
244: vset = body.checkLocalClass(env, ctx, vset, def,
245: args, constructor.getType()
246: .getArgumentTypes());
247:
248: // Set t to be the true type of this expression.
249: // (bug 4102056).
250: t = body.getClassDeclaration().getType();
251:
252: def = body;
253: }
254: } else {
255: // Check if it is an interface
256: if (def.isInterface()) {
257: env.error(where, "new.intf", c);
258: return vset;
259: }
260:
261: // Check for abstract class
262: if (def.mustBeAbstract(env)) {
263: env.error(where, "new.abstract", c);
264: return vset;
265: }
266: }
267:
268: // Get the constructor that the "new" expression should call.
269: field = def.matchMethod(env, sourceClass, idInit, argTypes);
270:
271: // Report an error if there is no matching constructor.
272: if (field == null) {
273: MemberDefinition anyInit = def.findAnyMethod(env,
274: idInit);
275: if (anyInit != null
276: && new MethodExpression(where, right, anyInit,
277: args).diagnoseMismatch(env, args,
278: argTypes))
279: return vset;
280: String sig = c.getName().getName().toString();
281: sig = Type.tMethod(Type.tError, argTypes).typeString(
282: sig, false, false);
283: env.error(where, "unmatched.constr", sig, c);
284: return vset;
285: }
286:
287: if (field.isPrivate()) {
288: ClassDefinition cdef = field.getClassDefinition();
289: if (cdef != sourceClass) {
290: // Use access method.
291: implMethod = cdef.getAccessMember(env, ctx, field,
292: false);
293: }
294: }
295:
296: // Check for abstract anonymous class
297: if (def.mustBeAbstract(env)) {
298: env.error(where, "new.abstract", c);
299: return vset;
300: }
301:
302: if (field.reportDeprecated(env)) {
303: env.error(where, "warn.constr.is.deprecated", field,
304: field.getClassDefinition());
305: }
306:
307: // According to JLS 6.6.2, a protected constructor may be accessed
308: // by a class instance creation expression only from within the
309: // package in which it is defined.
310: if (field.isProtected()
311: && !(sourceClass.getName().getQualifier()
312: .equals(field.getClassDeclaration()
313: .getName().getQualifier()))) {
314: env.error(where, "invalid.protected.constructor.use",
315: sourceClass);
316: }
317:
318: } catch (ClassNotFound ee) {
319: env.error(where, "class.not.found", ee.name, opNames[op]);
320: return vset;
321:
322: } catch (AmbiguousMember ee) {
323: env.error(where, "ambig.constr", ee.field1, ee.field2);
324: return vset;
325: }
326:
327: // Cast arguments
328: argTypes = field.getType().getArgumentTypes();
329: for (int i = 0; i < args.length; i++) {
330: args[i] = convert(env, ctx, argTypes[i], args[i]);
331: }
332: if (args.length > this .args.length) {
333: outerArg = args[0]; // recopy the checked arg
334: // maintain an accurate tree
335: for (int i = 1; i < args.length; i++) {
336: this .args[i - 1] = args[i];
337: }
338: }
339:
340: // Throw the declared exceptions.
341: ClassDeclaration exceptions[] = field.getExceptions(env);
342: for (int i = 0; i < exceptions.length; i++) {
343: if (exp.get(exceptions[i]) == null) {
344: exp.put(exceptions[i], this );
345: }
346: }
347:
348: type = t;
349:
350: return vset;
351: }
352:
353: /**
354: * Given a list of arguments for a constructor,
355: * return a possibly modified list which includes the hidden
356: * argument which initializes the uplevel self pointer.
357: * @arg def the class which perhaps contains an outer link.
358: * @arg outerArg if non-null, an explicit location in which to construct.
359: */
360: public static Expression[] insertOuterLink(Environment env,
361: Context ctx, long where, ClassDefinition def,
362: Expression outerArg, Expression args[]) {
363: if (!def.isTopLevel() && !def.isLocal()) {
364: Expression args2[] = new Expression[1 + args.length];
365: System.arraycopy(args, 0, args2, 1, args.length);
366: try {
367: if (outerArg == null)
368: outerArg = ctx.findOuterLink(env, where, def
369: .findAnyMethod(env, idInit));
370: } catch (ClassNotFound e) {
371: // die somewhere else
372: }
373: args2[0] = outerArg;
374: args = args2;
375: }
376: return args;
377: }
378:
379: /**
380: * Check void expression
381: */
382: public Vset check(Environment env, Context ctx, Vset vset,
383: Hashtable exp) {
384: return checkValue(env, ctx, vset, exp);
385: }
386:
387: /**
388: * Inline
389: */
390: final int MAXINLINECOST = Statement.MAXINLINECOST;
391:
392: public Expression copyInline(Context ctx) {
393: NewInstanceExpression e = (NewInstanceExpression) super
394: .copyInline(ctx);
395: if (outerArg != null) {
396: e.outerArg = outerArg.copyInline(ctx);
397: }
398: return e;
399: }
400:
401: Expression inlineNewInstance(Environment env, Context ctx,
402: Statement s) {
403: if (env.dump()) {
404: System.out.println("INLINE NEW INSTANCE " + field + " in "
405: + ctx.field);
406: }
407: LocalMember v[] = LocalMember.copyArguments(ctx, field);
408: Statement body[] = new Statement[v.length + 2];
409:
410: int o = 1;
411: if (outerArg != null && !outerArg.type.isType(TC_VOID)) {
412: o = 2;
413: body[1] = new VarDeclarationStatement(where, v[1], outerArg);
414: } else if (outerArg != null) {
415: body[0] = new ExpressionStatement(where, outerArg);
416: }
417: for (int i = 0; i < args.length; i++) {
418: body[i + o] = new VarDeclarationStatement(where, v[i + o],
419: args[i]);
420: }
421: //System.out.print("BEFORE:"); s.print(System.out); System.out.println();
422: body[body.length - 1] = (s != null) ? s.copyInline(ctx, false)
423: : null;
424: //System.out.print("COPY:"); body[body.length - 1].print(System.out); System.out.println();
425: //System.out.print("AFTER:"); s.print(System.out); System.out.println();
426: LocalMember.doneWithArguments(ctx, v);
427:
428: return new InlineNewInstanceExpression(where, type, field,
429: new CompoundStatement(where, body)).inline(env, ctx);
430: }
431:
432: public Expression inline(Environment env, Context ctx) {
433: return inlineValue(env, ctx);
434: }
435:
436: public Expression inlineValue(Environment env, Context ctx) {
437: if (body != null) {
438: body.inlineLocalClass(env);
439: }
440: ClassDefinition refc = field.getClassDefinition();
441: UplevelReference r = refc.getReferencesFrozen();
442: if (r != null) {
443: r.willCodeArguments(env, ctx);
444: }
445: //right = right.inlineValue(env, ctx);
446:
447: try {
448: if (outerArg != null) {
449: if (outerArg.type.isType(TC_VOID))
450: outerArg = outerArg.inline(env, ctx);
451: else
452: outerArg = outerArg.inlineValue(env, ctx);
453: }
454: for (int i = 0; i < args.length; i++) {
455: args[i] = args[i].inlineValue(env, ctx);
456: }
457: // This 'false' that fy put in is inexplicable to me
458: // the decision to not inline new instance expressions
459: // should be revisited. - dps
460: if (false && env.opt() && field.isInlineable(env, false)
461: && (!ctx.field.isInitializer())
462: && ctx.field.isMethod()
463: && (ctx.getInlineMemberContext(field) == null)) {
464: Statement s = (Statement) field.getValue(env);
465: if ((s == null)
466: || (s.costInline(MAXINLINECOST, env, ctx) < MAXINLINECOST)) {
467: return inlineNewInstance(env, ctx, s);
468: }
469: }
470: } catch (ClassNotFound e) {
471: throw new CompilerError(e);
472: }
473: if (outerArg != null && outerArg.type.isType(TC_VOID)) {
474: Expression e = outerArg;
475: outerArg = null;
476: return new CommaExpression(where, e, this );
477: }
478: return this ;
479: }
480:
481: public int costInline(int thresh, Environment env, Context ctx) {
482: if (body != null) {
483: return thresh; // don't copy classes...
484: }
485: if (ctx == null) {
486: return 2 + super .costInline(thresh, env, ctx);
487: }
488: // sourceClass is the current class trying to inline this method
489: ClassDefinition sourceClass = ctx.field.getClassDefinition();
490: try {
491: // We only allow the inlining if the current class can access
492: // the field and the field's class;
493: if (sourceClass.permitInlinedAccess(env, field
494: .getClassDeclaration())
495: && sourceClass.permitInlinedAccess(env, field)) {
496: return 2 + super .costInline(thresh, env, ctx);
497: }
498: } catch (ClassNotFound e) {
499: }
500: return thresh;
501: }
502:
503: /**
504: * Code
505: */
506: public void code(Environment env, Context ctx, Assembler asm) {
507: codeCommon(env, ctx, asm, false);
508: }
509:
510: public void codeValue(Environment env, Context ctx, Assembler asm) {
511: codeCommon(env, ctx, asm, true);
512: }
513:
514: private void codeCommon(Environment env, Context ctx,
515: Assembler asm, boolean forValue) {
516: asm.add(where, opc_new, field.getClassDeclaration());
517: if (forValue) {
518: asm.add(where, opc_dup);
519: }
520:
521: ClassDefinition refc = field.getClassDefinition();
522: UplevelReference r = refc.getReferencesFrozen();
523:
524: if (r != null) {
525: r.codeArguments(env, ctx, asm, where, field);
526: }
527:
528: if (outerArg != null) {
529: outerArg.codeValue(env, ctx, asm);
530: switch (outerArg.op) {
531: case THIS:
532: case SUPER:
533: case NEW:
534: // guaranteed non-null
535: break;
536: case FIELD: {
537: MemberDefinition f = ((FieldExpression) outerArg).field;
538: if (f != null && f.isNeverNull()) {
539: break;
540: }
541: // else fall through:
542: }
543: default:
544: // Test for nullity by invoking some trivial operation
545: // that can throw a NullPointerException.
546: try {
547: ClassDefinition c = env
548: .getClassDefinition(idJavaLangObject);
549: MemberDefinition getc = c.getFirstMatch(idGetClass);
550: asm.add(where, opc_dup);
551: asm.add(where, opc_invokevirtual, getc);
552: asm.add(where, opc_pop);
553: } catch (ClassNotFound e) {
554: }
555: }
556: }
557:
558: if (implMethod != null) {
559: // Constructor call will be via an access method.
560: // Pass 'null' as the value of the dummy argument.
561: asm.add(where, opc_aconst_null);
562: }
563:
564: for (int i = 0; i < args.length; i++) {
565: args[i].codeValue(env, ctx, asm);
566: }
567: asm.add(where, opc_invokespecial,
568: ((implMethod != null) ? implMethod : field));
569: }
570: }
|