0001: /*
0002: * Copyright 1994-2003 Sun Microsystems, Inc. All Rights Reserved.
0003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004: *
0005: * This code is free software; you can redistribute it and/or modify it
0006: * under the terms of the GNU General Public License version 2 only, as
0007: * published by the Free Software Foundation. Sun designates this
0008: * particular file as subject to the "Classpath" exception as provided
0009: * by Sun in the LICENSE file that accompanied this code.
0010: *
0011: * This code is distributed in the hope that it will be useful, but WITHOUT
0012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0014: * version 2 for more details (a copy is included in the LICENSE file that
0015: * accompanied this code).
0016: *
0017: * You should have received a copy of the GNU General Public License version
0018: * 2 along with this work; if not, write to the Free Software Foundation,
0019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020: *
0021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022: * CA 95054 USA or visit www.sun.com if you need additional information or
0023: * have any questions.
0024: */
0025:
0026: package sun.tools.tree;
0027:
0028: import sun.tools.java.*;
0029: import sun.tools.asm.Assembler;
0030: import java.io.PrintStream;
0031: import java.util.Hashtable;
0032:
0033: /**
0034: * WARNING: The contents of this source file are not part of any
0035: * supported API. Code that depends on them does so at its own risk:
0036: * they are subject to change or removal without notice.
0037: */
0038: public class MethodExpression extends NaryExpression {
0039: Identifier id;
0040: ClassDefinition clazz; // The class in which the called method is defined
0041: MemberDefinition field;
0042: Expression implementation;
0043:
0044: private boolean isSuper; // Set if qualified by 'super' or '<class>.super'.
0045:
0046: /**
0047: * constructor
0048: */
0049: public MethodExpression(long where, Expression right,
0050: Identifier id, Expression args[]) {
0051: super (METHOD, where, Type.tError, right, args);
0052: this .id = id;
0053: }
0054:
0055: public MethodExpression(long where, Expression right,
0056: MemberDefinition field, Expression args[]) {
0057: super (METHOD, where, field.getType().getReturnType(), right,
0058: args);
0059: this .id = field.getName();
0060: this .field = field;
0061: this .clazz = field.getClassDefinition();
0062: }
0063:
0064: // This is a hack used only within certain access methods generated by
0065: // 'SourceClass.getAccessMember'. It allows an 'invokespecial' instruction
0066: // to be forced even though 'super' does not appear within the call.
0067: // Such access methods are needed for access to protected methods when using
0068: // the qualified '<class>.super.<method>(...)' notation.
0069: public MethodExpression(long where, Expression right,
0070: MemberDefinition field, Expression args[],
0071: boolean forceSuper) {
0072: this (where, right, field, args);
0073: this .isSuper = forceSuper;
0074: }
0075:
0076: public Expression getImplementation() {
0077: if (implementation != null)
0078: return implementation;
0079: return this ;
0080: }
0081:
0082: /**
0083: * Check expression type
0084: */
0085: public Vset checkValue(Environment env, Context ctx, Vset vset,
0086: Hashtable exp) {
0087: ClassDeclaration c = null;
0088: boolean isArray = false;
0089: boolean staticRef = false;
0090:
0091: // Access method to use if required.
0092: MemberDefinition implMethod = null;
0093:
0094: ClassDefinition ctxClass = ctx.field.getClassDefinition();
0095:
0096: // When calling a constructor, we may need to add an
0097: // additional argument to transmit the outer instance link.
0098: Expression args[] = this .args;
0099: if (id.equals(idInit)) {
0100: ClassDefinition conCls = ctxClass;
0101: try {
0102: Expression conOuter = null;
0103: if (right instanceof SuperExpression) {
0104: // outer.super(...)
0105: conCls = conCls.getSuperClass().getClassDefinition(
0106: env);
0107: conOuter = ((SuperExpression) right).outerArg;
0108: } else if (right instanceof ThisExpression) {
0109: // outer.this(...)
0110: conOuter = ((ThisExpression) right).outerArg;
0111: }
0112: args = NewInstanceExpression.insertOuterLink(env, ctx,
0113: where, conCls, conOuter, args);
0114: } catch (ClassNotFound ee) {
0115: // the same error is handled elsewhere
0116: }
0117: }
0118:
0119: Type argTypes[] = new Type[args.length];
0120:
0121: // The effective accessing class, for access checking.
0122: // This is normally the immediately enclosing class.
0123: ClassDefinition sourceClass = ctxClass;
0124:
0125: try {
0126: if (right == null) {
0127: staticRef = ctx.field.isStatic();
0128: // Find the first outer scope that mentions the method.
0129: ClassDefinition cdef = ctxClass;
0130: MemberDefinition m = null;
0131: for (; cdef != null; cdef = cdef.getOuterClass()) {
0132: m = cdef.findAnyMethod(env, id);
0133: if (m != null) {
0134: break;
0135: }
0136: }
0137: if (m == null) {
0138: // this is the scope for error diagnosis
0139: c = ctx.field.getClassDeclaration();
0140: } else {
0141: // found the innermost scope in which m occurs
0142: c = cdef.getClassDeclaration();
0143:
0144: // Maybe an inherited method hides an apparent method.
0145: // Keep looking at enclosing scopes to find out.
0146: if (m.getClassDefinition() != cdef) {
0147: ClassDefinition cdef2 = cdef;
0148: while ((cdef2 = cdef2.getOuterClass()) != null) {
0149: MemberDefinition m2 = cdef2.findAnyMethod(
0150: env, id);
0151: if (m2 != null
0152: && m2.getClassDefinition() == cdef2) {
0153: env.error(where,
0154: "inherited.hides.method", id,
0155: cdef.getClassDeclaration(),
0156: cdef2.getClassDeclaration());
0157: break;
0158: }
0159: }
0160: }
0161: }
0162: } else {
0163: if (id.equals(idInit)) {
0164: int this N = ctx.getThisNumber();
0165: if (!ctx.field.isConstructor()) {
0166: env.error(where, "invalid.constr.invoke");
0167: return vset.addVar(this N);
0168: }
0169: // As a consequence of the DA/DU rules in the JLS (draft of
0170: // forthcoming 2e), all variables are both definitely assigned
0171: // and definitely unassigned in unreachable code. Normally, this
0172: // correctly suppresses DA/DU-related errors in such code.
0173: // The use of the DA status of the 'this' variable for the extra
0174: // check below on correct constructor usage, however, does not quite
0175: // fit into this DA/DU scheme. The current representation of
0176: // Vsets for unreachable dead-ends, does not allow 'clearVar'
0177: // to work, as the DA/DU bits (all on) are implicitly represented
0178: // by the fact that the Vset is a dead-end. The DA/DU status
0179: // of the 'this' variable is supposed to be temporarily
0180: // cleared at the beginning of a constructor and during the
0181: // checking of constructor arguments (see below in this method).
0182: // Since 'clearVar' has no effect on dead-ends, we may
0183: // find the 'this' variable in an erroneously definitely-assigned state.
0184: // As a workaround, we suppress the following error message when
0185: // the Vset is a dead-end, i.e., when we are in unreachable code.
0186: // Unfortunately, the special-case treatment of reachability for
0187: // if-then and if-then-else allows unreachable code in some circumstances,
0188: // thus it is possible that no error message will be emitted at all.
0189: // While this behavior is strictly incorrect (thus we call this a
0190: // workaround), the problematic code is indeed unreachable and will
0191: // not be executed. In fact, it will be entirely omitted from the
0192: // translated program, and can cause no harm at runtime. A correct
0193: // solution would require modifying the representation of the DA/DU
0194: // analysis to use finite Vsets only, restricting the universe
0195: // of variables about which assertions are made (even in unreachable
0196: // code) to variables that are actually in scope. Alternatively, the
0197: // Vset extension and the dead-end marker (currently a reserved value
0198: // of the extension) could be represented orthogonally. In either case,
0199: // 'clearVar' could then be made to work on (non-canonical) dead ends.
0200: // See file 'Vset.java'.
0201: if (!vset.isReallyDeadEnd() && vset.testVar(this N)) {
0202: env.error(where, "constr.invoke.not.first");
0203: return vset;
0204: }
0205: vset = vset.addVar(this N);
0206: if (right instanceof SuperExpression) {
0207: // supers require this specific kind of checking
0208: vset = right.checkAmbigName(env, ctx, vset,
0209: exp, this );
0210: } else {
0211: vset = right.checkValue(env, ctx, vset, exp);
0212: }
0213: } else {
0214: vset = right.checkAmbigName(env, ctx, vset, exp,
0215: this );
0216: if (right.type == Type.tPackage) {
0217: FieldExpression.reportFailedPackagePrefix(env,
0218: right);
0219: return vset;
0220: }
0221: if (right instanceof TypeExpression) {
0222: staticRef = true;
0223: }
0224: }
0225: if (right.type.isType(TC_CLASS)) {
0226: c = env.getClassDeclaration(right.type);
0227: } else if (right.type.isType(TC_ARRAY)) {
0228: isArray = true;
0229: c = env.getClassDeclaration(Type.tObject);
0230: } else {
0231: if (!right.type.isType(TC_ERROR)) {
0232: env.error(where, "invalid.method.invoke",
0233: right.type);
0234: }
0235: return vset;
0236: }
0237:
0238: // Normally, the effective accessing class is the innermost
0239: // class surrounding the current method call, but, for calls
0240: // of the form '<class>.super.<method>(...)', it is <class>.
0241: // This allows access to protected members of a superclass
0242: // from within a class nested within one of its subclasses.
0243: // Otherwise, for example, the call below to 'matchMethod'
0244: // may fail due to the rules for visibility of inaccessible
0245: // members. For consistency, we treat qualified 'this' in
0246: // the same manner, as error diagnostics will be affected.
0247: // QUERY: Are there subtle unexplored language issues here?
0248: if (right instanceof FieldExpression) {
0249: Identifier id = ((FieldExpression) right).id;
0250: if (id == idThis) {
0251: sourceClass = ((FieldExpression) right).clazz;
0252: } else if (id == idSuper) {
0253: isSuper = true;
0254: sourceClass = ((FieldExpression) right).clazz;
0255: }
0256: } else if (right instanceof SuperExpression) {
0257: isSuper = true;
0258: }
0259:
0260: // Fix for 4158650. When we extend a protected inner
0261: // class in a different package, we may not have access
0262: // to the type of our superclass. Allow the call to
0263: // the superclass constructor from within our constructor
0264: // Note that this check does not apply to constructor
0265: // calls in new instance expressions -- those are part
0266: // of NewInstanceExpression#check().
0267: if (id != idInit) {
0268: // Required by JLS 6.6.1. Fixes 4143715.
0269: // (See also 4094658.)
0270: if (!FieldExpression.isTypeAccessible(where, env,
0271: right.type, sourceClass)) {
0272: ClassDeclaration cdecl = sourceClass
0273: .getClassDeclaration();
0274: if (staticRef) {
0275: env.error(where, "no.type.access", id,
0276: right.type.toString(), cdecl);
0277: } else {
0278: env.error(where, "cant.access.member.type",
0279: id, right.type.toString(), cdecl);
0280: }
0281: }
0282: }
0283: }
0284:
0285: // Compose a list of argument types
0286: boolean hasErrors = false;
0287:
0288: // "this" is not defined during argument checking
0289: if (id.equals(idInit)) {
0290: vset = vset.clearVar(ctx.getThisNumber());
0291: }
0292:
0293: for (int i = 0; i < args.length; i++) {
0294: vset = args[i].checkValue(env, ctx, vset, exp);
0295: argTypes[i] = args[i].type;
0296: hasErrors = hasErrors || argTypes[i].isType(TC_ERROR);
0297: }
0298:
0299: // "this" is defined after the constructor invocation
0300: if (id.equals(idInit)) {
0301: vset = vset.addVar(ctx.getThisNumber());
0302: }
0303:
0304: // Check if there are any type errors in the arguments
0305: if (hasErrors) {
0306: return vset;
0307: }
0308:
0309: // Get the method field, given the argument types
0310: clazz = c.getClassDefinition(env);
0311:
0312: if (field == null) {
0313:
0314: field = clazz.matchMethod(env, sourceClass, id,
0315: argTypes);
0316:
0317: if (field == null) {
0318: if (id.equals(idInit)) {
0319: if (diagnoseMismatch(env, args, argTypes))
0320: return vset;
0321: String sig = clazz.getName().getName()
0322: .toString();
0323: sig = Type.tMethod(Type.tError, argTypes)
0324: .typeString(sig, false, false);
0325: env.error(where, "unmatched.constr", sig, c);
0326: return vset;
0327: }
0328: String sig = id.toString();
0329: sig = Type.tMethod(Type.tError, argTypes)
0330: .typeString(sig, false, false);
0331: if (clazz.findAnyMethod(env, id) == null) {
0332: if (ctx.getField(env, id) != null) {
0333: env.error(where, "invalid.method", id, c);
0334: } else {
0335: env.error(where, "undef.meth", sig, c);
0336: }
0337: } else if (diagnoseMismatch(env, args, argTypes)) {
0338: } else {
0339: env.error(where, "unmatched.meth", sig, c);
0340: }
0341: return vset;
0342: }
0343:
0344: }
0345:
0346: type = field.getType().getReturnType();
0347:
0348: // Make sure that static references are allowed
0349: if (staticRef && !field.isStatic()) {
0350: env.error(where, "no.static.meth.access", field, field
0351: .getClassDeclaration());
0352: return vset;
0353: }
0354:
0355: if (field.isProtected()
0356: && !(right == null)
0357: && !(right instanceof SuperExpression
0358: // Extension of JLS 6.6.2 for qualified 'super'.
0359: || (right instanceof FieldExpression && ((FieldExpression) right).id == idSuper))
0360: && !sourceClass.protectedAccess(env, field,
0361: right.type)) {
0362: env.error(where, "invalid.protected.method.use", field
0363: .getName(), field.getClassDeclaration(),
0364: right.type);
0365: return vset;
0366: }
0367:
0368: // In <class>.super.<method>(), we cannot simply evaluate
0369: // <class>.super to an object reference (as we would for
0370: // <class>.super.<field>) and then perform an 'invokespecial'.
0371: // An 'invokespecial' must be performed from within (a subclass of)
0372: // the class in which the target method is located.
0373: if (right instanceof FieldExpression
0374: && ((FieldExpression) right).id == idSuper) {
0375: if (!field.isPrivate()) {
0376: // The private case is handled below.
0377: // Use an access method unless the effective accessing class
0378: // (the class qualifying the 'super') is the same as the
0379: // immediately enclosing class, i.e., the qualification was
0380: // unnecessary.
0381: if (sourceClass != ctxClass) {
0382: implMethod = sourceClass.getAccessMember(env,
0383: ctx, field, true);
0384: }
0385: }
0386: }
0387:
0388: // Access method for private field if not in the same class.
0389: if (implMethod == null && field.isPrivate()) {
0390: ClassDefinition cdef = field.getClassDefinition();
0391: if (cdef != ctxClass) {
0392: implMethod = cdef.getAccessMember(env, ctx, field,
0393: false);
0394: }
0395: }
0396:
0397: // Make sure that we are not invoking an abstract method
0398: if (field.isAbstract() && (right != null)
0399: && (right.op == SUPER)) {
0400: env.error(where, "invoke.abstract", field, field
0401: .getClassDeclaration());
0402: return vset;
0403: }
0404:
0405: if (field.reportDeprecated(env)) {
0406: if (field.isConstructor()) {
0407: env
0408: .error(where, "warn.constr.is.deprecated",
0409: field);
0410: } else {
0411: env.error(where, "warn.meth.is.deprecated", field,
0412: field.getClassDefinition());
0413: }
0414: }
0415:
0416: // Check for recursive constructor
0417: if (field.isConstructor() && ctx.field.equals(field)) {
0418: env.error(where, "recursive.constr", field);
0419: }
0420:
0421: // When a package-private class defines public or protected
0422: // members, those members may sometimes be accessed from
0423: // outside of the package in public subclasses. In these
0424: // cases, we need to massage the method call to refer to
0425: // to an accessible subclass rather than the package-private
0426: // parent class. Part of fix for 4135692.
0427:
0428: // Find out if the class which contains this method
0429: // call has access to the class which declares the
0430: // public or protected method referent.
0431: // We don't perform this translation on constructor calls.
0432: if (sourceClass == ctxClass) {
0433: ClassDefinition declarer = field.getClassDefinition();
0434: if (!field.isConstructor()
0435: && declarer.isPackagePrivate()
0436: && !declarer.getName().getQualifier().equals(
0437: sourceClass.getName().getQualifier())) {
0438:
0439: //System.out.println("The access of member " +
0440: // field + " declared in class " +
0441: // declarer +
0442: // " is not allowed by the VM from class " +
0443: // accessor +
0444: // ". Replacing with an access of class " +
0445: // clazz);
0446:
0447: // We cannot make this access at the VM level.
0448: // Construct a member which will stand for this
0449: // method in clazz and set `field' to refer to it.
0450: field = MemberDefinition.makeProxyMember(field,
0451: clazz, env);
0452: }
0453: }
0454:
0455: sourceClass.addDependency(field.getClassDeclaration());
0456: if (sourceClass != ctxClass) {
0457: ctxClass.addDependency(field.getClassDeclaration());
0458: }
0459:
0460: } catch (ClassNotFound ee) {
0461: env.error(where, "class.not.found", ee.name, ctx.field);
0462: return vset;
0463:
0464: } catch (AmbiguousMember ee) {
0465: env.error(where, "ambig.field", id, ee.field1, ee.field2);
0466: return vset;
0467: }
0468:
0469: // Make sure it is qualified
0470: if ((right == null) && !field.isStatic()) {
0471: right = ctx.findOuterLink(env, where, field);
0472: vset = right.checkValue(env, ctx, vset, exp);
0473: }
0474:
0475: // Cast arguments
0476: argTypes = field.getType().getArgumentTypes();
0477: for (int i = 0; i < args.length; i++) {
0478: args[i] = convert(env, ctx, argTypes[i], args[i]);
0479: }
0480:
0481: if (field.isConstructor()) {
0482: MemberDefinition m = field;
0483: if (implMethod != null) {
0484: m = implMethod;
0485: }
0486: int nargs = args.length;
0487: Expression[] newargs = args;
0488: if (nargs > this .args.length) {
0489: // Argument was added above.
0490: // Maintain the model for hidden outer args in outer.super(...):
0491: Expression rightI;
0492: if (right instanceof SuperExpression) {
0493: rightI = new SuperExpression(right.where, ctx);
0494: ((SuperExpression) right).outerArg = args[0];
0495: } else if (right instanceof ThisExpression) {
0496: rightI = new ThisExpression(right.where, ctx);
0497: } else {
0498: throw new CompilerError("this.init");
0499: }
0500: if (implMethod != null) {
0501: // Need dummy argument for access method.
0502: // Dummy argument follows outer instance link.
0503: // Leave 'this.args' equal to 'newargs' but
0504: // without the outer instance link.
0505: newargs = new Expression[nargs + 1];
0506: this .args = new Expression[nargs];
0507: newargs[0] = args[0]; // outer instance
0508: this .args[0] = newargs[1] = new NullExpression(
0509: where); // dummy argument
0510: for (int i = 1; i < nargs; i++) {
0511: this .args[i] = newargs[i + 1] = args[i];
0512: }
0513: } else {
0514: // Strip outer instance link from 'this.args'.
0515: // ASSERT(this.arg.length == nargs-1);
0516: for (int i = 1; i < nargs; i++) {
0517: this .args[i - 1] = args[i];
0518: }
0519: }
0520: implementation = new MethodExpression(where, rightI, m,
0521: newargs);
0522: implementation.type = type; // Is this needed?
0523: } else {
0524: // No argument was added.
0525: if (implMethod != null) {
0526: // Need dummy argument for access method.
0527: // Dummy argument is first, as there is no outer instance link.
0528: newargs = new Expression[nargs + 1];
0529: newargs[0] = new NullExpression(where);
0530: for (int i = 0; i < nargs; i++) {
0531: newargs[i + 1] = args[i];
0532: }
0533: }
0534: implementation = new MethodExpression(where, right, m,
0535: newargs);
0536: }
0537: } else {
0538: // Have ordinary method.
0539: // Argument should have been added only for a constructor.
0540: if (args.length > this .args.length) {
0541: throw new CompilerError("method arg");
0542: }
0543: if (implMethod != null) {
0544: //System.out.println("Calling " + field + " via " + implMethod);
0545: Expression oldargs[] = this .args;
0546: if (field.isStatic()) {
0547: Expression call = new MethodExpression(where, null,
0548: implMethod, oldargs);
0549: implementation = new CommaExpression(where, right,
0550: call);
0551: } else {
0552: // Access method needs an explicit 'this' pointer.
0553: int nargs = oldargs.length;
0554: Expression newargs[] = new Expression[nargs + 1];
0555: newargs[0] = right;
0556: for (int i = 0; i < nargs; i++) {
0557: newargs[i + 1] = oldargs[i];
0558: }
0559: implementation = new MethodExpression(where, null,
0560: implMethod, newargs);
0561: }
0562: }
0563: }
0564:
0565: // Follow super() by variable initializations
0566: if (ctx.field.isConstructor() && field.isConstructor()
0567: && (right != null) && (right.op == SUPER)) {
0568: Expression e = makeVarInits(env, ctx);
0569: if (e != null) {
0570: if (implementation == null)
0571: implementation = (Expression) this .clone();
0572: implementation = new CommaExpression(where,
0573: implementation, e);
0574: }
0575: }
0576:
0577: // Throw the declared exceptions.
0578: ClassDeclaration exceptions[] = field.getExceptions(env);
0579: if (isArray && (field.getName() == idClone)
0580: && (field.getType().getArgumentTypes().length == 0)) {
0581: /* Arrays pretend that they have "public Object clone()" that doesn't
0582: * throw anything, according to the language spec.
0583: */
0584: exceptions = new ClassDeclaration[0];
0585: /* See if there's a bogus catch for it, to issue a warning. */
0586: for (Context p = ctx; p != null; p = p.prev) {
0587: if (p.node != null && p.node.op == TRY) {
0588: ((TryStatement) p.node).arrayCloneWhere = where;
0589: }
0590: }
0591: }
0592: for (int i = 0; i < exceptions.length; i++) {
0593: if (exp.get(exceptions[i]) == null) {
0594: exp.put(exceptions[i], this );
0595: }
0596: }
0597:
0598: // Mark all blank finals as definitely assigned following 'this(...)'.
0599: // Correctness follows inductively from the requirement that all blank finals
0600: // be definitely assigned at the completion of every constructor.
0601: if (ctx.field.isConstructor() && field.isConstructor()
0602: && (right != null) && (right.op == THIS)) {
0603: ClassDefinition cls = field.getClassDefinition();
0604: for (MemberDefinition f = cls.getFirstMember(); f != null; f = f
0605: .getNextMember()) {
0606: if (f.isVariable() && f.isBlankFinal() && !f.isStatic()) {
0607: // Static variables should also be considered defined as well, but this
0608: // is handled in 'SourceClass.checkMembers', and we should not interfere.
0609: vset = vset.addVar(ctx.getFieldNumber(f));
0610: }
0611: }
0612: }
0613:
0614: return vset;
0615: }
0616:
0617: /**
0618: * Check void expression
0619: */
0620: public Vset check(Environment env, Context ctx, Vset vset,
0621: Hashtable exp) {
0622: return checkValue(env, ctx, vset, exp);
0623: }
0624:
0625: /**
0626: * We're about to report a "unmatched method" error.
0627: * Try to issue a better diagnostic by comparing the actual argument types
0628: * with the method (or methods) available.
0629: * In particular, if there is an argument which fails to match <em>any</em>
0630: * method, we report a type mismatch error against that particular argument.
0631: * The diagnostic will report a target type taken from one of the methods.
0632: * <p>
0633: * Return false if we couldn't think of anything smart to say.
0634: */
0635: boolean diagnoseMismatch(Environment env, Expression args[],
0636: Type argTypes[]) throws ClassNotFound {
0637: Type margType[] = new Type[1];
0638: boolean saidSomething = false;
0639: int start = 0;
0640: while (start < argTypes.length) {
0641: int code = clazz.diagnoseMismatch(env, id, argTypes, start,
0642: margType);
0643: String opName = (id.equals(idInit)) ? "constructor"
0644: : opNames[op];
0645: if (code == -2) {
0646: env.error(where, "wrong.number.args", opName);
0647: saidSomething = true;
0648: }
0649: if (code < 0)
0650: break;
0651: int i = code >> 2;
0652: boolean castOK = (code & 2) != 0;
0653: boolean ambig = (code & 1) != 0;
0654: Type targetType = margType[0];
0655:
0656: // At least one argument is offensive to all overloadings.
0657: // targetType is one of the argument types it does not match.
0658: String ttype = "" + targetType;
0659:
0660: // The message might be slightly misleading, if there are other
0661: // argument types that also would match. Hint at this:
0662: //if (ambig) ttype = "{"+ttype+";...}";
0663:
0664: if (castOK)
0665: env.error(args[i].where, "explicit.cast.needed",
0666: opName, argTypes[i], ttype);
0667: else
0668: env.error(args[i].where, "incompatible.type", opName,
0669: argTypes[i], ttype);
0670: saidSomething = true;
0671: start = i + 1; // look for other bad arguments, too
0672: }
0673: return saidSomething;
0674: }
0675:
0676: /**
0677: * Inline
0678: */
0679: static final int MAXINLINECOST = Statement.MAXINLINECOST;
0680:
0681: private Expression inlineMethod(Environment env, Context ctx,
0682: Statement s, boolean valNeeded) {
0683: if (env.dump()) {
0684: System.out.println("INLINE METHOD " + field + " in "
0685: + ctx.field);
0686: }
0687: LocalMember v[] = LocalMember.copyArguments(ctx, field);
0688: Statement body[] = new Statement[v.length + 2];
0689:
0690: int n = 0;
0691: if (field.isStatic()) {
0692: body[0] = new ExpressionStatement(where, right);
0693: } else {
0694: if ((right != null) && (right.op == SUPER)) {
0695: right = new ThisExpression(right.where, ctx);
0696: }
0697: body[0] = new VarDeclarationStatement(where, v[n++], right);
0698: }
0699: for (int i = 0; i < args.length; i++) {
0700: body[i + 1] = new VarDeclarationStatement(where, v[n++],
0701: args[i]);
0702: }
0703: //System.out.print("BEFORE:"); s.print(System.out); System.out.println();
0704: // Note: If !valNeeded, then all returns in the body of the method
0705: // change to void returns.
0706: body[body.length - 1] = (s != null) ? s.copyInline(ctx,
0707: valNeeded) : null;
0708: //System.out.print("COPY:"); body[body.length - 1].print(System.out); System.out.println();
0709: LocalMember.doneWithArguments(ctx, v);
0710:
0711: // Make sure the type matches what the return statements are returning.
0712: Type type = valNeeded ? this .type : Type.tVoid;
0713: Expression e = new InlineMethodExpression(where, type, field,
0714: new CompoundStatement(where, body));
0715: return valNeeded ? e.inlineValue(env, ctx) : e.inline(env, ctx);
0716: }
0717:
0718: public Expression inline(Environment env, Context ctx) {
0719: if (implementation != null)
0720: return implementation.inline(env, ctx);
0721: try {
0722: if (right != null) {
0723: right = field.isStatic() ? right.inline(env, ctx)
0724: : right.inlineValue(env, ctx);
0725: }
0726: for (int i = 0; i < args.length; i++) {
0727: args[i] = args[i].inlineValue(env, ctx);
0728: }
0729:
0730: // ctxClass is the current class trying to inline this method
0731: ClassDefinition ctxClass = ctx.field.getClassDefinition();
0732:
0733: Expression e = this ;
0734: if (env.opt()
0735: && field.isInlineable(env, clazz.isFinal())
0736: &&
0737:
0738: // Don't inline if a qualified non-static method: the call
0739: // itself might throw NullPointerException as a side effect
0740: ((right == null) || (right.op == THIS) || field
0741: .isStatic())
0742: &&
0743:
0744: // We only allow the inlining if the current class can access
0745: // the field, the field's class, and right's declared type.
0746: ctxClass.permitInlinedAccess(env, field
0747: .getClassDeclaration())
0748: && ctxClass.permitInlinedAccess(env, field)
0749: && (right == null || ctxClass.permitInlinedAccess(
0750: env, env.getClassDeclaration(right.type)))
0751: &&
0752:
0753: ((id == null) || !id.equals(idInit))
0754: && (!ctx.field.isInitializer())
0755: && ctx.field.isMethod()
0756: && (ctx.getInlineMemberContext(field) == null)) {
0757: Statement s = (Statement) field.getValue(env);
0758: if ((s == null)
0759: || (s.costInline(MAXINLINECOST, env, ctx) < MAXINLINECOST)) {
0760: e = inlineMethod(env, ctx, s, false);
0761: }
0762: }
0763: return e;
0764:
0765: } catch (ClassNotFound e) {
0766: throw new CompilerError(e);
0767: }
0768: }
0769:
0770: public Expression inlineValue(Environment env, Context ctx) {
0771: if (implementation != null)
0772: return implementation.inlineValue(env, ctx);
0773: try {
0774: if (right != null) {
0775: right = field.isStatic() ? right.inline(env, ctx)
0776: : right.inlineValue(env, ctx);
0777: }
0778: if (field.getName().equals(idInit)) {
0779: ClassDefinition refc = field.getClassDefinition();
0780: UplevelReference r = refc.getReferencesFrozen();
0781: if (r != null) {
0782: r.willCodeArguments(env, ctx);
0783: }
0784: }
0785: for (int i = 0; i < args.length; i++) {
0786: args[i] = args[i].inlineValue(env, ctx);
0787: }
0788:
0789: // ctxClass is the current class trying to inline this method
0790: ClassDefinition ctxClass = ctx.field.getClassDefinition();
0791:
0792: if (env.opt()
0793: && field.isInlineable(env, clazz.isFinal())
0794: &&
0795:
0796: // Don't inline if a qualified non-static method: the call
0797: // itself might throw NullPointerException as a side effect
0798: ((right == null) || (right.op == THIS) || field
0799: .isStatic())
0800: &&
0801:
0802: // We only allow the inlining if the current class can access
0803: // the field, the field's class, and right's declared type.
0804: ctxClass.permitInlinedAccess(env, field
0805: .getClassDeclaration())
0806: && ctxClass.permitInlinedAccess(env, field)
0807: && (right == null || ctxClass.permitInlinedAccess(
0808: env, env.getClassDeclaration(right.type)))
0809: &&
0810:
0811: (!ctx.field.isInitializer())
0812: && ctx.field.isMethod()
0813: && (ctx.getInlineMemberContext(field) == null)) {
0814: Statement s = (Statement) field.getValue(env);
0815: if ((s == null)
0816: || (s.costInline(MAXINLINECOST, env, ctx) < MAXINLINECOST)) {
0817: return inlineMethod(env, ctx, s, true);
0818: }
0819: }
0820: return this ;
0821: } catch (ClassNotFound e) {
0822: throw new CompilerError(e);
0823: }
0824: }
0825:
0826: public Expression copyInline(Context ctx) {
0827: if (implementation != null)
0828: return implementation.copyInline(ctx);
0829: return super .copyInline(ctx);
0830: }
0831:
0832: public int costInline(int thresh, Environment env, Context ctx) {
0833: if (implementation != null)
0834: return implementation.costInline(thresh, env, ctx);
0835:
0836: // for now, don't allow calls to super() to be inlined. We may fix
0837: // this later
0838: if ((right != null) && (right.op == SUPER)) {
0839: return thresh;
0840: }
0841: return super .costInline(thresh, env, ctx);
0842: }
0843:
0844: /*
0845: * Grab all instance initializer code from the class definition,
0846: * and return as one bolus. Note that we are assuming the
0847: * the relevant fields have already been checked.
0848: * (See the pre-pass in SourceClass.checkMembers which ensures this.)
0849: */
0850: private Expression makeVarInits(Environment env, Context ctx) {
0851: // insert instance initializers
0852: ClassDefinition clazz = ctx.field.getClassDefinition();
0853: Expression e = null;
0854: for (MemberDefinition f = clazz.getFirstMember(); f != null; f = f
0855: .getNextMember()) {
0856: if ((f.isVariable() || f.isInitializer()) && !f.isStatic()) {
0857: try {
0858: f.check(env);
0859: } catch (ClassNotFound ee) {
0860: env.error(f.getWhere(), "class.not.found", ee.name,
0861: f.getClassDefinition());
0862: }
0863: Expression val = null;
0864: if (f.isUplevelValue()) {
0865: if (f != clazz.findOuterMember()) {
0866: // it's too early to accumulate these
0867: continue;
0868: }
0869: IdentifierExpression arg = new IdentifierExpression(
0870: where, f.getName());
0871: if (!arg.bind(env, ctx)) {
0872: throw new CompilerError("bind " + arg.id);
0873: }
0874: val = arg;
0875: } else if (f.isInitializer()) {
0876: Statement s = (Statement) f.getValue();
0877: val = new InlineMethodExpression(where, Type.tVoid,
0878: f, s);
0879: } else {
0880: val = (Expression) f.getValue();
0881: }
0882: // append all initializers to "e":
0883: // This section used to check for variables which were
0884: // initialized to their default values and elide such
0885: // initialization. This is specifically disallowed by
0886: // JLS 12.5 numeral 4, which requires a textual ordering
0887: // on the execution of initializers.
0888: if ((val != null)) { // && !val.equals(0)) {
0889: long p = f.getWhere();
0890: val = val.copyInline(ctx);
0891: Expression init = val;
0892: if (f.isVariable()) {
0893: Expression v = new ThisExpression(p, ctx);
0894: v = new FieldExpression(p, v, f);
0895: init = new AssignExpression(p, v, val);
0896: }
0897: e = (e == null) ? init : new CommaExpression(p, e,
0898: init);
0899: }
0900: }
0901: }
0902: return e;
0903: }
0904:
0905: /**
0906: * Code
0907: */
0908: public void codeValue(Environment env, Context ctx, Assembler asm) {
0909: if (implementation != null)
0910: throw new CompilerError("codeValue");
0911: int i = 0; // argument index
0912: if (field.isStatic()) {
0913: if (right != null) {
0914: right.code(env, ctx, asm);
0915: }
0916: } else if (right == null) {
0917: asm.add(where, opc_aload, new Integer(0));
0918: } else if (right.op == SUPER) {
0919: // 'super.<method>(...)', 'super(...)', or '<expr>.super(...)'
0920: /*****
0921: isSuper = true;
0922: *****/
0923: right.codeValue(env, ctx, asm);
0924: if (idInit.equals(id)) {
0925: // 'super(...)' or '<expr>.super(...)' only
0926: ClassDefinition refc = field.getClassDefinition();
0927: UplevelReference r = refc.getReferencesFrozen();
0928: if (r != null) {
0929: // When calling a constructor for a class with
0930: // embedded uplevel references, add extra arguments.
0931: if (r.isClientOuterField()) {
0932: // the extra arguments are inserted after this one
0933: args[i++].codeValue(env, ctx, asm);
0934: }
0935: r.codeArguments(env, ctx, asm, where, field);
0936: }
0937: }
0938: } else {
0939: right.codeValue(env, ctx, asm);
0940: /*****
0941: if (right.op == FIELD &&
0942: ((FieldExpression)right).id == idSuper) {
0943: // '<class>.super.<method>(...)'
0944: isSuper = true;
0945: }
0946: *****/
0947: }
0948:
0949: for (; i < args.length; i++) {
0950: args[i].codeValue(env, ctx, asm);
0951: }
0952:
0953: if (field.isStatic()) {
0954: asm.add(where, opc_invokestatic, field);
0955: } else if (field.isConstructor() || field.isPrivate()
0956: || isSuper) {
0957: asm.add(where, opc_invokespecial, field);
0958: } else if (field.getClassDefinition().isInterface()) {
0959: asm.add(where, opc_invokeinterface, field);
0960: } else {
0961: asm.add(where, opc_invokevirtual, field);
0962: }
0963:
0964: if (right != null && right.op == SUPER && idInit.equals(id)) {
0965: // 'super(...)' or '<expr>.super(...)'
0966: ClassDefinition refc = ctx.field.getClassDefinition();
0967: UplevelReference r = refc.getReferencesFrozen();
0968: if (r != null) {
0969: // After calling a superclass constructor in a class with
0970: // embedded uplevel references, initialize uplevel fields.
0971: r.codeInitialization(env, ctx, asm, where, field);
0972: }
0973: }
0974: }
0975:
0976: /**
0977: * Check if the first thing is a constructor invocation
0978: */
0979: public Expression firstConstructor() {
0980: return id.equals(idInit) ? this : null;
0981: }
0982:
0983: /**
0984: * Print
0985: */
0986: public void print(PrintStream out) {
0987: out.print("(" + opNames[op]);
0988: if (right != null) {
0989: out.print(" ");
0990: right.print(out);
0991: }
0992: out.print(" " + ((id == null) ? idInit : id));
0993: for (int i = 0; i < args.length; i++) {
0994: out.print(" ");
0995: if (args[i] != null) {
0996: args[i].print(out);
0997: } else {
0998: out.print("<null>");
0999: }
1000: }
1001: out.print(")");
1002: if (implementation != null) {
1003: out.print("/IMPL=");
1004: implementation.print(out);
1005: }
1006: }
1007: }
|