949 lines · 41.5 KB · Java
RawDownload
                if (implMethod != null) {                    // Need dummy argument for access method.                    // Dummy argument is first, as there is no outer instance link.                    newargs = new Expression[nargs+1];                    newargs[0] = new NullExpression(where);                    for (int i = 0 ; i < nargs ; i++) {                        newargs[i+1] = args[i];                    }                }                implementation = new MethodExpression(where, right, m, newargs);            }        } else {            // Have ordinary method.            // Argument should have been added only for a constructor.            if (args.length > this.args.length) {                throw new CompilerError("method arg");            }            if (implMethod != null) {                //System.out.println("Calling " + field + " via " + implMethod);                Expression oldargs[] = this.args;                if (field.isStatic()) {                    Expression call = new MethodExpression(where, null, implMethod, oldargs);                    implementation = new CommaExpression(where, right, call);                } else {                    // Access method needs an explicit 'this' pointer.                    int nargs = oldargs.length;                    Expression newargs[] = new Expression[nargs+1];                    newargs[0] = right;                    for (int i = 0; i < nargs; i++) {                        newargs[i+1] = oldargs[i];                    }                    implementation = new MethodExpression(where, null, implMethod, newargs);                }            }        }         // Follow super() by variable initializations        if (ctx.field.isConstructor() &&            field.isConstructor() && (right != null) && (right.op == SUPER)) {            Expression e = makeVarInits(env, ctx);            if (e != null) {                if (implementation == null)                    implementation = (Expression)this.clone();                implementation = new CommaExpression(where, implementation, e);            }        }         // Throw the declared exceptions.        ClassDeclaration exceptions[] = field.getExceptions(env);        if (isArray && (field.getName() == idClone) &&               (field.getType().getArgumentTypes().length == 0)) {            /* Arrays pretend that they have "public Object clone()" that doesn't             * throw anything, according to the language spec.             */            exceptions = new ClassDeclaration[0];            /* See if there's a bogus catch for it, to issue a warning. */            for (Context p = ctx; p != null; p = p.prev) {                if (p.node != null && p.node.op == TRY) {                    ((TryStatement) p.node).arrayCloneWhere = where;                }            }        }        for (int i = 0 ; i < exceptions.length ; i++) {            if (exp.get(exceptions[i]) == null) {                exp.put(exceptions[i], this);            }        }         // Mark all blank finals as definitely assigned following 'this(...)'.        // Correctness follows inductively from the requirement that all blank finals        // be definitely assigned at the completion of every constructor.        if (ctx.field.isConstructor() &&            field.isConstructor() && (right != null) && (right.op == THIS)) {            ClassDefinition cls = field.getClassDefinition();            for (MemberDefinition f = cls.getFirstMember() ; f != null ; f = f.getNextMember()) {                if (f.isVariable() && f.isBlankFinal() && !f.isStatic()) {                    // Static variables should also be considered defined as well, but this                    // is handled in 'SourceClass.checkMembers', and we should not interfere.                    vset = vset.addVar(ctx.getFieldNumber(f));                }            }        }         return vset;    }     /**     * Check void expression     */    public Vset check(Environment env, Context ctx, Vset vset, Hashtable exp) {        return checkValue(env, ctx, vset, exp);    }     /**     * We're about to report a "unmatched method" error.     * Try to issue a better diagnostic by comparing the actual argument types     * with the method (or methods) available.     * In particular, if there is an argument which fails to match <em>any</em>     * method, we report a type mismatch error against that particular argument.     * The diagnostic will report a target type taken from one of the methods.     * <p>     * Return false if we couldn't think of anything smart to say.     */    boolean diagnoseMismatch(Environment env, Expression args[],                             Type argTypes[]) throws ClassNotFound {        Type margType[] = new Type[1];        boolean saidSomething = false;        int start = 0;        while (start < argTypes.length) {            int code = clazz.diagnoseMismatch(env, id, argTypes, start, margType);            String opName = (id.equals(idInit)) ? "constructor" : opNames[op];            if (code == -2) {                env.error(where, "wrong.number.args", opName);                saidSomething = true;            }            if (code < 0)  break;            int i = code >> 2;            boolean castOK = (code & 2) != 0;            boolean ambig = (code & 1) != 0;            Type targetType = margType[0];             // At least one argument is offensive to all overloadings.            // targetType is one of the argument types it does not match.            String ttype = ""+targetType;             // The message might be slightly misleading, if there are other            // argument types that also would match.  Hint at this:            //if (ambig)  ttype = "{"+ttype+";...}";             if (castOK)                env.error(args[i].where, "explicit.cast.needed", opName, argTypes[i], ttype);            else                env.error(args[i].where, "incompatible.type", opName, argTypes[i], ttype);            saidSomething = true;            start = i+1;        // look for other bad arguments, too        }        return saidSomething;    }     /**     * Inline     */    static final int MAXINLINECOST = Statement.MAXINLINECOST;     private    Expression inlineMethod(Environment env, Context ctx, Statement s, boolean valNeeded) {        if (env.dump()) {            System.out.println("INLINE METHOD " + field + " in " + ctx.field);        }        LocalMember v[] = LocalMember.copyArguments(ctx, field);        Statement body[] = new Statement[v.length + 2];         int n = 0;        if (field.isStatic()) {            body[0] = new ExpressionStatement(where, right);        } else {            if ((right != null) && (right.op == SUPER)) {                right = new ThisExpression(right.where, ctx);            }            body[0] = new VarDeclarationStatement(where, v[n++], right);        }        for (int i = 0 ; i < args.length ; i++) {            body[i + 1] = new VarDeclarationStatement(where, v[n++], args[i]);        }        //System.out.print("BEFORE:"); s.print(System.out); System.out.println();        // Note: If !valNeeded, then all returns in the body of the method        // change to void returns.        body[body.length - 1] = (s != null) ? s.copyInline(ctx, valNeeded) : null;        //System.out.print("COPY:"); body[body.length - 1].print(System.out); System.out.println();        LocalMember.doneWithArguments(ctx, v);         // Make sure the type matches what the return statements are returning.        Type type = valNeeded ? this.type : Type.tVoid;        Expression e = new InlineMethodExpression(where, type, field, new CompoundStatement(where, body));        return valNeeded ? e.inlineValue(env, ctx) : e.inline(env, ctx);    }     public Expression inline(Environment env, Context ctx) {        if (implementation != null)            return implementation.inline(env, ctx);        try {            if (right != null) {                right = field.isStatic() ? right.inline(env, ctx) : right.inlineValue(env, ctx);            }            for (int i = 0 ; i < args.length ; i++) {                args[i] = args[i].inlineValue(env, ctx);            }             // ctxClass is the current class trying to inline this method            ClassDefinition ctxClass = ctx.field.getClassDefinition();             Expression e = this;            if (env.opt() && field.isInlineable(env, clazz.isFinal()) &&                 // Don't inline if a qualified non-static method: the call                // itself might throw NullPointerException as a side effect                ((right == null) || (right.op==THIS) || field.isStatic()) &&                 // We only allow the inlining if the current class can access                // the field, the field's class, and right's declared type.                ctxClass.permitInlinedAccess(env,                              field.getClassDeclaration()) &&                ctxClass.permitInlinedAccess(env, field) &&                (right==null || ctxClass.permitInlinedAccess(env,                              env.getClassDeclaration(right.type)))  &&                 ((id == null) || !id.equals(idInit)) &&                (!ctx.field.isInitializer()) && ctx.field.isMethod() &&                (ctx.getInlineMemberContext(field) == null)) {                Statement s = (Statement)field.getValue(env);                if ((s == null) ||                    (s.costInline(MAXINLINECOST, env, ctx) < MAXINLINECOST))  {                    e = inlineMethod(env, ctx, s, false);                }            }            return e;         } catch (ClassNotFound e) {            throw new CompilerError(e);        }    }     public Expression inlineValue(Environment env, Context ctx) {        if (implementation != null)            return implementation.inlineValue(env, ctx);        try {            if (right != null) {                right = field.isStatic() ? right.inline(env, ctx) : right.inlineValue(env, ctx);            }            if (field.getName().equals(idInit)) {                ClassDefinition refc = field.getClassDefinition();                UplevelReference r = refc.getReferencesFrozen();                if (r != null) {                    r.willCodeArguments(env, ctx);                }            }            for (int i = 0 ; i < args.length ; i++) {                args[i] = args[i].inlineValue(env, ctx);            }             // ctxClass is the current class trying to inline this method            ClassDefinition ctxClass = ctx.field.getClassDefinition();             if (env.opt() && field.isInlineable(env, clazz.isFinal()) &&                 // Don't inline if a qualified non-static method: the call                // itself might throw NullPointerException as a side effect                ((right == null) || (right.op==THIS) || field.isStatic()) &&                 // We only allow the inlining if the current class can access                // the field, the field's class, and right's declared type.                ctxClass.permitInlinedAccess(env,                              field.getClassDeclaration()) &&                ctxClass.permitInlinedAccess(env, field) &&                (right==null || ctxClass.permitInlinedAccess(env,                              env.getClassDeclaration(right.type)))  &&                 (!ctx.field.isInitializer()) && ctx.field.isMethod() &&                (ctx.getInlineMemberContext(field) == null)) {                Statement s = (Statement)field.getValue(env);                if ((s == null) ||                    (s.costInline(MAXINLINECOST, env, ctx) < MAXINLINECOST))  {                    return inlineMethod(env, ctx, s, true);                }            }            return this;        } catch (ClassNotFound e) {            throw new CompilerError(e);        }    }     public Expression copyInline(Context ctx) {        if (implementation != null)            return implementation.copyInline(ctx);        return super.copyInline(ctx);    }     public int costInline(int thresh, Environment env, Context ctx) {        if (implementation != null)            return implementation.costInline(thresh, env, ctx);         // for now, don't allow calls to super() to be inlined.  We may fix        // this later        if ((right != null) && (right.op == SUPER)) {            return thresh;        }        return super.costInline(thresh, env, ctx);    }     /*     * Grab all instance initializer code from the class definition,     * and return as one bolus.  Note that we are assuming the     * the relevant fields have already been checked.     * (See the pre-pass in SourceClass.checkMembers which ensures this.)     */    private Expression makeVarInits(Environment env, Context ctx) {        // insert instance initializers        ClassDefinition clazz = ctx.field.getClassDefinition();        Expression e = null;        for (MemberDefinition f = clazz.getFirstMember() ; f != null ; f = f.getNextMember()) {            if ((f.isVariable() || f.isInitializer()) && !f.isStatic()) {                try {                    f.check(env);                } catch (ClassNotFound ee) {                    env.error(f.getWhere(), "class.not.found", ee.name,                              f.getClassDefinition());                }                Expression val = null;                if (f.isUplevelValue()) {                    if (f != clazz.findOuterMember()) {                        // it's too early to accumulate these                        continue;                    }                    IdentifierExpression arg =                        new IdentifierExpression(where, f.getName());                    if (!arg.bind(env, ctx)) {                        throw new CompilerError("bind "+arg.id);                    }                    val = arg;                } else if (f.isInitializer()) {                    Statement s = (Statement)f.getValue();                    val = new InlineMethodExpression(where, Type.tVoid, f, s);                } else {                    val = (Expression)f.getValue();                }                // append all initializers to "e":                // This section used to check for variables which were                // initialized to their default values and elide such                // initialization.  This is specifically disallowed by                // JLS 12.5 numeral 4, which requires a textual ordering                // on the execution of initializers.                if ((val != null)) { //  && !val.equals(0)) {                    long p = f.getWhere();                    val = val.copyInline(ctx);                    Expression init = val;                    if (f.isVariable()) {                        Expression v = new ThisExpression(p, ctx);                    v = new FieldExpression(p, v, f);                    init = new AssignExpression(p, v, val);                    }                    e = (e == null) ? init : new CommaExpression(p, e, init);                }            }        }        return e;    }     /**     * Code     */    public void codeValue(Environment env, Context ctx, Assembler asm) {        if (implementation != null)            throw new CompilerError("codeValue");        int i = 0;              // argument index        if (field.isStatic()) {            if (right != null) {                right.code(env, ctx, asm);            }        } else if (right == null) {            asm.add(where, opc_aload, new Integer(0));        } else if (right.op == SUPER) {            // 'super.<method>(...)', 'super(...)', or '<expr>.super(...)'            /*****            isSuper = true;            *****/            right.codeValue(env, ctx, asm);            if (idInit.equals(id)) {                // 'super(...)' or '<expr>.super(...)' only                ClassDefinition refc = field.getClassDefinition();                UplevelReference r = refc.getReferencesFrozen();                if (r != null) {                    // When calling a constructor for a class with                    // embedded uplevel references, add extra arguments.                    if (r.isClientOuterField()) {                        // the extra arguments are inserted after this one                        args[i++].codeValue(env, ctx, asm);                    }                    r.codeArguments(env, ctx, asm, where, field);                }            }        } else {            right.codeValue(env, ctx, asm);            /*****            if (right.op == FIELD &&                ((FieldExpression)right).id == idSuper) {                // '<class>.super.<method>(...)'                isSuper = true;            }            *****/        }         for ( ; i < args.length ; i++) {            args[i].codeValue(env, ctx, asm);        }         if (field.isStatic()) {            asm.add(where, opc_invokestatic, field);        } else if (field.isConstructor() || field.isPrivate() || isSuper) {            asm.add(where, opc_invokespecial, field);        } else if (field.getClassDefinition().isInterface()) {            asm.add(where, opc_invokeinterface, field);        } else {            asm.add(where, opc_invokevirtual, field);        }         if (right != null && right.op == SUPER && idInit.equals(id)) {            // 'super(...)' or '<expr>.super(...)'            ClassDefinition refc = ctx.field.getClassDefinition();            UplevelReference r = refc.getReferencesFrozen();            if (r != null) {                // After calling a superclass constructor in a class with                // embedded uplevel references, initialize uplevel fields.                r.codeInitialization(env, ctx, asm, where, field);            }        }    }     /**     * Check if the first thing is a constructor invocation     */    public Expression firstConstructor() {        return id.equals(idInit) ? this : null;    }     /**     * Print     */    public void print(PrintStream out) {        out.print("(" + opNames[op]);        if (right != null) {            out.print(" ");            right.print(out);        }        out.print(" " + ((id == null) ? idInit : id));        for (int i = 0 ; i < args.length ; i++) {            out.print(" ");            if (args[i] != null) {                args[i].print(out);            } else {                out.print("<null>");            }        }        out.print(")");        if (implementation != null) {            out.print("/IMPL=");            implementation.print(out);        }    }}

Lines 501–949 of 949. Previous lines