317 lines · 11.7 KB · Java
RawDownload
/* * Copyright (c) 1994, 2003, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.tools.tree; import sun.tools.java.*;import sun.tools.asm.Assembler;import sun.tools.asm.Label;import sun.tools.asm.TryData;import sun.tools.asm.CatchData;import java.io.PrintStream;import java.util.Enumeration;import java.util.Hashtable; /** * WARNING: The contents of this source file are not part of any * supported API.  Code that depends on them does so at its own risk: * they are subject to change or removal without notice. */publicclass TryStatement extends Statement {    Statement body;    Statement args[];    long arrayCloneWhere;       // private note posted from MethodExpression     /**     * Constructor     */    public TryStatement(long where, Statement body, Statement args[]) {        super(TRY, where);        this.body = body;        this.args = args;    }     /**     * Check statement     */    Vset check(Environment env, Context ctx, Vset vset, Hashtable exp) {        checkLabel(env, ctx);        try {            vset = reach(env, vset);            Hashtable newexp = new Hashtable();            CheckContext newctx =  new CheckContext(ctx, this);             // Check 'try' block.  A variable is DA (DU) before the try            // block if it is DA (DU) before the try statement.            Vset vs = body.check(env, newctx, vset.copy(), newexp);             // A variable is DA before a catch block if it is DA before the            // try statement.  A variable is DU before a catch block if it            // is DU after the try block and before any 'break', 'continue',            // 'throw', or 'return' contained therein. That is, the variable            // is DU upon entry to the try-statement and is not assigned to            // anywhere within the try block.            Vset cvs = Vset.firstDAandSecondDU(vset, vs.copy().join(newctx.vsTryExit));             for (int i = 0 ; i < args.length ; i++) {                // A variable is DA (DU) after a try statement if                // it is DA (DU) after every catch block.                vs = vs.join(args[i].check(env, newctx, cvs.copy(), exp));            }             // Check that catch statements are actually reached            for (int i = 1 ; i < args.length ; i++) {                CatchStatement cs = (CatchStatement)args[i];                if (cs.field == null) {                    continue;                }                Type type = cs.field.getType();                ClassDefinition def = env.getClassDefinition(type);                 for (int j = 0 ; j < i ; j++) {                    CatchStatement cs2 = (CatchStatement)args[j];                    if (cs2.field == null) {                        continue;                    }                    Type t = cs2.field.getType();                    ClassDeclaration c = env.getClassDeclaration(t);                    if (def.subClassOf(env, c)) {                        env.error(args[i].where, "catch.not.reached");                        break;                    }                }            }             ClassDeclaration ignore1 = env.getClassDeclaration(idJavaLangError);            ClassDeclaration ignore2 = env.getClassDeclaration(idJavaLangRuntimeException);             // Make sure the exception is actually throw in that part of the code            for (int i = 0 ; i < args.length ; i++) {                CatchStatement cs = (CatchStatement)args[i];                if (cs.field == null) {                    continue;                }                Type type = cs.field.getType();                if (!type.isType(TC_CLASS)) {                    // CatchStatement.checkValue() will have already printed                    // an error message                    continue;                }                 ClassDefinition def = env.getClassDefinition(type);                 // Anyone can throw these!                if (def.subClassOf(env, ignore1) || def.superClassOf(env, ignore1) ||                    def.subClassOf(env, ignore2) || def.superClassOf(env, ignore2)) {                    continue;                }                 // Make sure the exception is actually throw in that part of the code                boolean ok = false;                for (Enumeration e = newexp.keys() ; e.hasMoreElements() ; ) {                    ClassDeclaration c = (ClassDeclaration)e.nextElement();                    if (def.superClassOf(env, c) || def.subClassOf(env, c)) {                        ok = true;                        break;                    }                }                if (!ok && arrayCloneWhere != 0                    && def.getName().toString().equals("java.lang.CloneNotSupportedException")) {                    env.error(arrayCloneWhere, "warn.array.clone.supported", def.getName());                }                 if (!ok) {                    env.error(cs.where, "catch.not.thrown", def.getName());                }            }             // Only carry over exceptions that are not caught            for (Enumeration e = newexp.keys() ; e.hasMoreElements() ; ) {                ClassDeclaration c = (ClassDeclaration)e.nextElement();                ClassDefinition def = c.getClassDefinition(env);                boolean add = true;                for (int i = 0 ; i < args.length ; i++) {                    CatchStatement cs = (CatchStatement)args[i];                    if (cs.field == null) {                        continue;                    }                    Type type = cs.field.getType();                    if (type.isType(TC_ERROR))                        continue;                    if (def.subClassOf(env, env.getClassDeclaration(type))) {                        add = false;                        break;                    }                }                if (add) {                    exp.put(c, newexp.get(c));                }            }            // A variable is DA (DU) after a try statement if it is DA (DU)            // after the try block and after every catch block. These variables            // are represented by 'vs'.  If the try statement is labelled, we            // may also exit from it (including from within a catch block) via            // a break statement.            // If there is a finally block, the Vset returned here is further            // adjusted. Note that this 'TryStatement' node will be a child of            // a 'FinallyStatement' node in that case.            return ctx.removeAdditionalVars(vs.join(newctx.vsBreak));        } catch (ClassNotFound e) {            env.error(where, "class.not.found", e.name, opNames[op]);            return vset;        }    }     /**     * Inline     */    public Statement inline(Environment env, Context ctx) {        if (body != null) {            body = body.inline(env, new Context(ctx, this));        }        if (body == null) {            return null;        }        for (int i = 0 ; i < args.length ; i++) {            if (args[i] != null) {                args[i] = args[i].inline(env, new Context(ctx, this));            }        }        return (args.length == 0) ? eliminate(env, body) : this;    }     /**     * Create a copy of the statement for method inlining     */    public Statement copyInline(Context ctx, boolean valNeeded) {        TryStatement s = (TryStatement)clone();        if (body != null) {            s.body = body.copyInline(ctx, valNeeded);        }        s.args = new Statement[args.length];        for (int i = 0 ; i < args.length ; i++) {            if (args[i] != null) {                s.args[i] = args[i].copyInline(ctx, valNeeded);            }        }        return s;    }     /**     * Compute cost of inlining this statement     */    public int costInline(int thresh, Environment env, Context ctx){         // Don't inline methods containing try statements.        // If the try statement is being inlined in order to        // inline a method that returns a value which is        // a subexpression of an expression involving the        // operand stack, then the early operands may get lost.        // This shows up as a verifier error.  For example,        // in the following:        //        //    public static int test() {        //       try { return 2; } catch (Exception e)  { return 0; }        //    }        //        //    System.out.println(test());        //        // an inlined call to test() might look like this:        //        //     0 getstatic <Field java.io.PrintStream out>        //     3 iconst_2        //     4 goto 9        //     7 pop        //     8 iconst_0        //     9 invokevirtual <Method void println(int)>        //    12 return        //  Exception table:        //     from   to  target type        //       3     7     7   <Class java.lang.Exception>        //        // This fails to verify because the operand stored        // for System.out gets axed at an exception, leading to        // an inconsistent stack depth at pc=7.        //        // Note that although all code must be able to be inlined        // to implement initializers, this problem doesn't come up,        // as try statements themselves can never be expressions.        // It suffices here to make sure they are never inlined as part        // of optimization.         return thresh;    }     /**     * Code     */    public void code(Environment env, Context ctx, Assembler asm) {        CodeContext newctx = new CodeContext(ctx, this);         TryData td = new TryData();        for (int i = 0 ; i < args.length ; i++) {            Type t = ((CatchStatement)args[i]).field.getType();            if (t.isType(TC_CLASS)) {                td.add(env.getClassDeclaration(t));            } else {                td.add(t);            }        }        asm.add(where, opc_try, td);        if (body != null) {            body.code(env, newctx, asm);        }         asm.add(td.getEndLabel());        asm.add(where, opc_goto, newctx.breakLabel);         for (int i = 0 ; i < args.length ; i++) {            CatchData cd = td.getCatch(i);            asm.add(cd.getLabel());            args[i].code(env, newctx, asm);            asm.add(where, opc_goto, newctx.breakLabel);        }         asm.add(newctx.breakLabel);    }     /**     * Print     */    public void print(PrintStream out, int indent) {        super.print(out, indent);        out.print("try ");        if (body != null) {            body.print(out, indent);        } else {            out.print("<empty>");        }        for (int i = 0 ; i < args.length ; i++) {            out.print(" ");            args[i].print(out, indent);        }    }}