jdk/src/share/classes/sun/tools/tree/Statement.java
changeset 2 90ce3da70b43
child 5506 202f599c92aa
equal deleted inserted replaced
0:fd16c54261b3 2:90ce3da70b43
       
     1 /*
       
     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 
       
    26 package sun.tools.tree;
       
    27 
       
    28 import sun.tools.java.*;
       
    29 import sun.tools.asm.Assembler;
       
    30 import sun.tools.asm.Label;
       
    31 import java.io.PrintStream;
       
    32 import java.util.Hashtable;
       
    33 
       
    34 /**
       
    35  * WARNING: The contents of this source file are not part of any
       
    36  * supported API.  Code that depends on them does so at its own risk:
       
    37  * they are subject to change or removal without notice.
       
    38  */
       
    39 public
       
    40 class Statement extends Node {
       
    41     public static final Vset DEAD_END = Vset.DEAD_END;
       
    42     Identifier labels[] = null;
       
    43 
       
    44     /**
       
    45      * Constructor
       
    46      */
       
    47     Statement(int op, long where) {
       
    48         super(op, where);
       
    49     }
       
    50 
       
    51     /**
       
    52      * An empty statement.  Its costInline is infinite.
       
    53      */
       
    54     public static final Statement empty = new Statement(STAT, 0);
       
    55 
       
    56     /**
       
    57      * The largest possible interesting inline cost value.
       
    58      */
       
    59     public static final int MAXINLINECOST =
       
    60                       Integer.getInteger("javac.maxinlinecost",
       
    61                                          30).intValue();
       
    62 
       
    63     /**
       
    64      * Insert a bit of code at the front of a statement.
       
    65      * Side-effect s2, if it is a CompoundStatement.
       
    66      */
       
    67     public static Statement insertStatement(Statement s1, Statement s2) {
       
    68         if (s2 == null) {
       
    69             s2 = s1;
       
    70         } else if (s2 instanceof CompoundStatement) {
       
    71             // Do not add another level of block nesting.
       
    72             ((CompoundStatement)s2).insertStatement(s1);
       
    73         } else {
       
    74             Statement body[] = { s1, s2 };
       
    75             s2 = new CompoundStatement(s1.getWhere(), body);
       
    76         }
       
    77         return s2;
       
    78     }
       
    79 
       
    80     /**
       
    81      * Set the label of a statement
       
    82      */
       
    83     public void setLabel(Environment env, Expression e) {
       
    84         if (e.op == IDENT) {
       
    85             if (labels == null) {
       
    86                 labels = new Identifier[1];
       
    87             } else {
       
    88                 // this should almost never happen.  Multiple labels on
       
    89                 // the same statement.  But handle it gracefully.
       
    90                 Identifier newLabels[] = new Identifier[labels.length + 1];
       
    91                 System.arraycopy(labels, 0, newLabels, 1, labels.length);
       
    92                 labels = newLabels;
       
    93             }
       
    94             labels[0] = ((IdentifierExpression)e).id;
       
    95         } else {
       
    96             env.error(e.where, "invalid.label");
       
    97         }
       
    98     }
       
    99 
       
   100     /**
       
   101      * Check a statement
       
   102      */
       
   103     public Vset checkMethod(Environment env, Context ctx, Vset vset, Hashtable exp) {
       
   104         // Set up ctx.getReturnContext() for the sake of ReturnStatement.check().
       
   105         CheckContext mctx = new CheckContext(ctx, new Statement(METHOD, 0));
       
   106         ctx = mctx;
       
   107 
       
   108         vset = check(env, ctx, vset, exp);
       
   109 
       
   110         // Check for return
       
   111         if (!ctx.field.getType().getReturnType().isType(TC_VOID)) {
       
   112             // In general, we suppress further error messages due to
       
   113             // unreachable statements after reporting the first error
       
   114             // along a flow path (using 'clearDeadEnd').   Here, we
       
   115             // report an error anyway, because the end of the method
       
   116             // should be unreachable despite the earlier error.  The
       
   117             // difference in treatment is due to the fact that, in this
       
   118             // case, the error is reachability, not unreachability.
       
   119             // NOTE: In addition to this subtle difference in the quality
       
   120             // of the error diagnostics, this treatment is essential to
       
   121             // preserve the correctness of using 'clearDeadEnd' to implement
       
   122             // the special-case reachability rules for if-then and if-then-else.
       
   123             if (!vset.isDeadEnd()) {
       
   124                 env.error(ctx.field.getWhere(), "return.required.at.end", ctx.field);
       
   125             }
       
   126         }
       
   127 
       
   128         // Simulate a return at the end.
       
   129         vset = vset.join(mctx.vsBreak);
       
   130 
       
   131         return vset;
       
   132     }
       
   133     Vset checkDeclaration(Environment env, Context ctx, Vset vset, int mod, Type t, Hashtable exp) {
       
   134         throw new CompilerError("checkDeclaration");
       
   135     }
       
   136 
       
   137     /**
       
   138      * Make sure the labels on this statement do not duplicate the
       
   139      * labels on any enclosing statement.  Provided as a convenience
       
   140      * for subclasses.
       
   141      */
       
   142     protected void checkLabel(Environment env, Context ctx) {
       
   143         if (labels != null) {
       
   144             loop: for (int i = 0; i < labels.length; i++) {
       
   145                 // Make sure there is not a double label on this statement.
       
   146                 for (int j = i+1; j < labels.length; j++) {
       
   147                     if (labels[i] == labels[j]) {
       
   148                         env.error(where, "nested.duplicate.label", labels[i]);
       
   149                         continue loop;
       
   150                     }
       
   151                 }
       
   152 
       
   153                 // Make sure no enclosing statement has the same label.
       
   154                 CheckContext destCtx =
       
   155                     (CheckContext) ctx.getLabelContext(labels[i]);
       
   156 
       
   157                 if (destCtx != null) {
       
   158                     // Check to make sure the label is in not uplevel.
       
   159                     if (destCtx.frameNumber == ctx.frameNumber) {
       
   160                         env.error(where, "nested.duplicate.label", labels[i]);
       
   161                     }
       
   162                 }
       
   163             } // end loop
       
   164         }
       
   165     }
       
   166 
       
   167     Vset check(Environment env, Context ctx, Vset vset, Hashtable exp) {
       
   168         throw new CompilerError("check");
       
   169     }
       
   170 
       
   171     /** This is called in contexts where declarations are valid. */
       
   172     Vset checkBlockStatement(Environment env, Context ctx, Vset vset, Hashtable exp) {
       
   173         return check(env, ctx, vset, exp);
       
   174     }
       
   175 
       
   176     Vset reach(Environment env, Vset vset) {
       
   177         if (vset.isDeadEnd()) {
       
   178             env.error(where, "stat.not.reached");
       
   179             vset = vset.clearDeadEnd();
       
   180         }
       
   181         return vset;
       
   182     }
       
   183 
       
   184     /**
       
   185      * Inline
       
   186      */
       
   187     public Statement inline(Environment env, Context ctx) {
       
   188         return this;
       
   189     }
       
   190 
       
   191     /**
       
   192      * Eliminate this statement, which is only possible if it has no label.
       
   193      */
       
   194     public Statement eliminate(Environment env, Statement s) {
       
   195         if ((s != null) && (labels != null)) {
       
   196             Statement args[] = {s};
       
   197             s = new CompoundStatement(where, args);
       
   198             s.labels = labels;
       
   199         }
       
   200         return s;
       
   201     }
       
   202 
       
   203 
       
   204     /**
       
   205      * Code
       
   206      */
       
   207     public void code(Environment env, Context ctx, Assembler asm) {
       
   208         throw new CompilerError("code");
       
   209     }
       
   210 
       
   211     /**
       
   212      * Generate the code to call all finally's for a break, continue, or
       
   213      * return statement.  We must call "jsr" on all the cleanup code between
       
   214      * the current context "ctx", and the destination context "stopctx".
       
   215      * If 'save' isn't null, there is also a value on the top of the stack
       
   216      */
       
   217     void codeFinally(Environment env, Context ctx, Assembler asm,
       
   218                         Context stopctx, Type save) {
       
   219         Integer num = null;
       
   220         boolean haveCleanup = false; // there is a finally or synchronize;
       
   221         boolean haveNonLocalFinally = false; // some finally doesn't return;
       
   222 
       
   223         for (Context c = ctx; (c != null) && (c != stopctx); c = c.prev) {
       
   224             if (c.node == null)
       
   225                 continue;
       
   226             if (c.node.op == SYNCHRONIZED) {
       
   227                 haveCleanup = true;
       
   228             } else if (c.node.op == FINALLY
       
   229                           && ((CodeContext)c).contLabel != null) {
       
   230                 // c.contLabel == null indicates we're in the "finally" part
       
   231                 haveCleanup = true;
       
   232                 FinallyStatement st = ((FinallyStatement)(c.node));
       
   233                 if (!st.finallyCanFinish) {
       
   234                     haveNonLocalFinally = true;
       
   235                     // after hitting a non-local finally, no need generating
       
   236                     // further code, because it won't get executed.
       
   237                     break;
       
   238                 }
       
   239             }
       
   240         }
       
   241         if (!haveCleanup) {
       
   242             // there is no cleanup that needs to be done.  Just quit.
       
   243             return;
       
   244         }
       
   245         if (save != null) {
       
   246             // This statement has a return value on the stack.
       
   247             ClassDefinition def = ctx.field.getClassDefinition();
       
   248             if (!haveNonLocalFinally) {
       
   249                 // Save the return value in the register which should have
       
   250                 // been reserved.
       
   251                 LocalMember lf = ctx.getLocalField(idFinallyReturnValue);
       
   252                 num = new Integer(lf.number);
       
   253                 asm.add(where, opc_istore + save.getTypeCodeOffset(), num);
       
   254             } else {
       
   255                 // Pop the return value.
       
   256                 switch(ctx.field.getType().getReturnType().getTypeCode()) {
       
   257                     case TC_VOID:
       
   258                         break;
       
   259                     case TC_DOUBLE: case TC_LONG:
       
   260                         asm.add(where, opc_pop2); break;
       
   261                     default:
       
   262                         asm.add(where, opc_pop); break;
       
   263                 }
       
   264             }
       
   265         }
       
   266         // Call each of the cleanup functions, as necessary.
       
   267         for (Context c = ctx ; (c != null)  && (c != stopctx) ; c = c.prev) {
       
   268             if (c.node == null)
       
   269                 continue;
       
   270             if (c.node.op == SYNCHRONIZED) {
       
   271                 asm.add(where, opc_jsr, ((CodeContext)c).contLabel);
       
   272             } else if (c.node.op == FINALLY
       
   273                           && ((CodeContext)c).contLabel != null) {
       
   274                 FinallyStatement st = ((FinallyStatement)(c.node));
       
   275                 Label label = ((CodeContext)c).contLabel;
       
   276                 if (st.finallyCanFinish) {
       
   277                     asm.add(where, opc_jsr, label);
       
   278                 } else {
       
   279                     // the code never returns, so we're done.
       
   280                     asm.add(where, opc_goto, label);
       
   281                     break;
       
   282                 }
       
   283             }
       
   284         }
       
   285         // Move the return value from the register back to the stack.
       
   286         if (num != null) {
       
   287             asm.add(where, opc_iload + save.getTypeCodeOffset(), num);
       
   288         }
       
   289     }
       
   290 
       
   291     /*
       
   292      * Return true if the statement has the given label
       
   293      */
       
   294     public boolean hasLabel (Identifier lbl) {
       
   295         Identifier labels[] = this.labels;
       
   296         if (labels != null) {
       
   297             for (int i = labels.length; --i >= 0; ) {
       
   298                 if (labels[i].equals(lbl)) {
       
   299                     return true;
       
   300                 }
       
   301             }
       
   302         }
       
   303         return false;
       
   304     }
       
   305 
       
   306     /**
       
   307      * Check if the first thing is a constructor invocation
       
   308      */
       
   309     public Expression firstConstructor() {
       
   310         return null;
       
   311     }
       
   312 
       
   313     /**
       
   314      * Create a copy of the statement for method inlining
       
   315      */
       
   316     public Statement copyInline(Context ctx, boolean valNeeded) {
       
   317         return (Statement)clone();
       
   318     }
       
   319 
       
   320     public int costInline(int thresh, Environment env, Context ctx) {
       
   321         return thresh;
       
   322     }
       
   323 
       
   324 
       
   325     /**
       
   326      * Print
       
   327      */
       
   328     void printIndent(PrintStream out, int indent) {
       
   329         for (int i = 0 ; i < indent ; i++) {
       
   330             out.print("    ");
       
   331         }
       
   332     }
       
   333     public void print(PrintStream out, int indent) {
       
   334         if (labels != null) {
       
   335             for (int i = labels.length; --i >= 0; )
       
   336                 out.print(labels[i] + ": ");
       
   337         }
       
   338     }
       
   339     public void print(PrintStream out) {
       
   340         print(out, 0);
       
   341     }
       
   342 }