Flow.java revision 116
116N/A * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. 0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 0N/A * This code is free software; you can redistribute it and/or modify it 0N/A * under the terms of the GNU General Public License version 2 only, as 0N/A * published by the Free Software Foundation. Sun designates this 0N/A * particular file as subject to the "Classpath" exception as provided 0N/A * by Sun in the LICENSE file that accompanied this code. 0N/A * This code is distributed in the hope that it will be useful, but WITHOUT 0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 0N/A * version 2 for more details (a copy is included in the LICENSE file that 0N/A * accompanied this code). 0N/A * You should have received a copy of the GNU General Public License version 0N/A * 2 along with this work; if not, write to the Free Software Foundation, 0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 0N/A * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 0N/A * CA 95054 USA or visit www.sun.com if you need additional information or 0N/A * have any questions. 0N/A//todo: one might eliminate uninits.andSets when monotonic 0N/A/** This pass implements dataflow analysis for Java programs. 0N/A * Liveness analysis checks that every statement is reachable. 0N/A * Exception analysis ensures that every checked exception that is 0N/A * thrown is declared or caught. Definite assignment analysis 0N/A * ensures that each variable is assigned when used. Definite 0N/A * unassignment analysis ensures that no final variable is assigned 0N/A * <p>The second edition of the JLS has a number of problems in the 0N/A * specification of these flow analysis problems. This implementation 0N/A * attempts to address those issues. 0N/A * <p>First, there is no accommodation for a finally clause that cannot 0N/A * complete normally. For liveness analysis, an intervening finally 0N/A * clause can cause a break, continue, or return not to reach its 0N/A * target. For exception analysis, an intervening finally clause can 0N/A * cause any exception to be "caught". For DA/DU analysis, the finally 0N/A * clause can prevent a transfer of control from propagating DA/DU 0N/A * state to the target. In addition, code in the finally clause can 0N/A * affect the DA/DU status of variables. 0N/A * <p>For try statements, we introduce the idea of a variable being 0N/A * definitely unassigned "everywhere" in a block. A variable V is 0N/A * "unassigned everywhere" in a block iff it is unassigned at the 0N/A * beginning of the block and there is no reachable assignment to V 0N/A * in the block. An assignment V=e is reachable iff V is not DA 0N/A * after e. Then we can say that V is DU at the beginning of the 0N/A * catch block iff V is DU everywhere in the try block. Similarly, V 0N/A * is DU at the beginning of the finally block iff V is DU everywhere 0N/A * in the try block and in every catch block. Specifically, the 0N/A * following bullet is added to 16.2.2 0N/A * V is <em>unassigned everywhere</em> in a block if it is 0N/A * unassigned before the block and there is no reachable 0N/A * assignment to V within the block. 0N/A * <p>In 16.2.15, the third bullet (and all of its sub-bullets) for all 0N/A * try blocks is changed to 0N/A * V is definitely unassigned before a catch block iff V is 0N/A * definitely unassigned everywhere in the try block. 0N/A * <p>The last bullet (and all of its sub-bullets) for try blocks that 0N/A * have a finally block is changed to 0N/A * V is definitely unassigned before the finally block iff 0N/A * V is definitely unassigned everywhere in the try block 0N/A * and everywhere in each catch block of the try statement. 0N/A * V is definitely assigned at the end of a constructor iff 0N/A * V is definitely assigned after the block that is the body 0N/A * of the constructor and V is definitely assigned at every 0N/A * return that can return from the constructor. 0N/A * <p>In addition, each continue statement with the loop as its target 0N/A * is treated as a jump to the end of the loop body, and "intervening" 0N/A * finally clauses are treated as follows: V is DA "due to the 0N/A * continue" iff V is DA before the continue statement or V is DA at 0N/A * the end of any intervening finally block. V is DU "due to the 0N/A * continue" iff any intervening finally cannot complete normally or V 0N/A * is DU at the end of every intervening finally block. This "due to 0N/A * the continue" concept is then used in the spec for the loops. 0N/A * <p>Similarly, break statements must consider intervening finally 0N/A * blocks. For liveness analysis, a break statement for which any 0N/A * intervening finally cannot complete normally is not considered to 0N/A * cause the target statement to be able to complete normally. Then 0N/A * we say V is DA "due to the break" iff V is DA before the break or 0N/A * V is DA at the end of any intervening finally block. V is DU "due 0N/A * to the break" iff any intervening finally cannot complete normally 0N/A * or V is DU at the break and at the end of every intervening 0N/A * finally block. (I suspect this latter condition can be 0N/A * simplified.) This "due to the break" is then used in the spec for 0N/A * all statements that can be "broken". 0N/A * <p>The return statement is treated similarly. V is DA "due to a 0N/A * return statement" iff V is DA before the return statement or V is 0N/A * DA at the end of any intervening finally block. Note that we 0N/A * don't have to worry about the return expression because this 0N/A * concept is only used for construcrors. 0N/A * <p>There is no spec in JLS2 for when a variable is definitely 0N/A * assigned at the end of a constructor, which is needed for final 0N/A * fields (8.3.1.2). We implement the rule that V is DA at the end 0N/A * of the constructor iff it is DA and the end of the body of the 0N/A * constructor and V is DA "due to" every return of the constructor. 0N/A * <p>Intervening finally blocks similarly affect exception analysis. An 0N/A * intervening finally that cannot complete normally allows us to ignore 0N/A * an otherwise uncaught exception. 0N/A * <p>To implement the semantics of intervening finally clauses, all 0N/A * nonlocal transfers (break, continue, return, throw, method call that 0N/A * can throw a checked exception, and a constructor invocation that can 0N/A * thrown a checked exception) are recorded in a queue, and removed 0N/A * from the queue when we complete processing the target of the 0N/A * nonlocal transfer. This allows us to modify the queue in accordance 0N/A * with the above rules when we encounter a finally clause. The only 0N/A * exception to this [no pun intended] is that checked exceptions that 0N/A * are known to be caught or declared to be caught in the enclosing 0N/A * method are not recorded in the queue, but instead are recorded in a 0N/A * global variable "Set<Type> thrown" that records the type of all 0N/A * exceptions that can be thrown. 0N/A * <p>Other minor issues the treatment of members of other classes 0N/A * (always considered DA except that within an anonymous class 0N/A * constructor, where DA status from the enclosing scope is 0N/A * preserved), treatment of the case expression (V is DA before the 0N/A * case expression iff V is DA after the switch expression), 0N/A * treatment of variables declared in a switch block (the implied 0N/A * DA/DU status after the switch expression is DU and not DA for 0N/A * variables defined in a switch block), the treatment of boolean ?: 0N/A * expressions (The JLS rules only handle b and c non-boolean; the 0N/A * new rule is that if b and c are boolean valued, then V is 0N/A * (un)assigned after a?b:c when true/false iff V is (un)assigned 0N/A * after b when true/false and V is (un)assigned after c when 0N/A * <p>There is the remaining question of what syntactic forms constitute a 0N/A * reference to a variable. It is conventional to allow this.x on the 0N/A * left-hand-side to initialize a final instance field named x, yet 0N/A * this.x isn't considered a "use" when appearing on a right-hand-side 0N/A * in most implementations. Should parentheses affect what is 0N/A * considered a variable reference? The simplest rule would be to 0N/A * allow unqualified forms only, parentheses optional, and phase out 0N/A * support for assigning to a final field via this.x. 0N/A * <p><b>This is NOT part of any API supported by Sun Microsystems. If 0N/A * you write code that depends on this, you do so at your own risk. 0N/A * This code and its internal interfaces are subject to change or 0N/A * deletion without notice.</b> 0N/A /** A flag that indicates whether the last statement could 0N/A * complete normally. 0N/A /** The set of definitely assigned variables. 0N/A /** The set of definitely unassigned variables. 0N/A /** The set of variables that are definitely unassigned everywhere 0N/A * in current try block. This variable is maintained lazily; it is 0N/A * updated only when something gets removed from uninits, 0N/A * typically by being assigned in reachable code. To obtain the 0N/A * correct set of variables which are definitely unassigned 0N/A * anywhere in current try block, intersect uninitsTry and 0N/A /** When analyzing a condition, inits and uninits are null. 0N/A /** A mapping from addresses to variable symbols. 0N/A /** The current class being defined. 0N/A /** The first variable sequence number in this class definition. 0N/A /** The next available variable sequence number. 0N/A /** The list of possibly thrown declarable exceptions. 0N/A /** The list of exceptions that are either caught or declared to be 0N/A /** Set when processing a loop body the second time for DU analysis. */ 0N/A /*-------------------- Environments ----------------------*/ 0N/A /** A pending exit. These are the statements return, break, and 0N/A * continue. In addition, exception-throwing expressions or 0N/A * statements are put here when not known to be caught. This 0N/A * will typically result in an error unless it is within a 0N/A * try-finally whose finally block cannot complete normally. 0N/A /** The currently pending exits that go from current inner blocks 0N/A * to an enclosing block, in source order. 0N/A /*-------------------- Exceptions ----------------------*/ 0N/A /** Complain that pending exceptions are not caught. 0N/A ?
"unreported.exception.default.constructor" 0N/A :
"unreported.exception.need.to.catch.or.throw",
0N/A /** Record that exception is potentially thrown and check that it 0N/A /*-------------- Processing variables ----------------------*/ 0N/A * I.e. is symbol either a local or a blank final variable? 0N/A /** Initialize new trackable variable by setting its address field 0N/A * to the next available sequence number and entering it under that 0N/A * index into the vars array. 0N/A /** Record an initialization of a trackable variable. 0N/A ?
"var.might.be.assigned.in.loop" 0N/A :
"var.might.already.be.assigned",
0N/A // reachable assignment 0N/A //log.rawWarning(pos, "unreachable assignment");//DEBUG 0N/A /** If tree is either a simple name or of the form this.name or 0N/A * C.this.name, and tree represents a trackable variable, 0N/A * record an initialization of the variable. 0N/A /** Check that trackable variable is initialized. 0N/A /*-------------------- Handling jumps ----------------------*/ 0N/A /** Record an outward transfer of control. */ 0N/A /** Resolve all breaks of this statement. */ 0N/A /** Resolve all continues of this statement. */ 0N/A /** Record that statement is unreachable. 0N/A/* ************************************************************************ 0N/A * Visitor methods for statements and definitions 0N/A *************************************************************************/ 0N/A /** Analyze a definition. 0N/A "initializer.must.be.able.to.complete.normally");
0N/A /** Analyze a statement. Check that statement is reachable. 0N/A /** Analyze list of statements. 0N/A /** Analyze an expression. Make sure to set (un)inits rather than 0N/A * (un)initsWhenTrue(WhenFalse) on exit. 0N/A /** Analyze a list of expressions. 0N/A /** Analyze a condition. Make sure to set (un)initsWhenTrue(WhenFalse) 0N/A * rather than (un)inits on exit. 0N/A /* ------------ Visitor methods for various sorts of trees -------------*/ 0N/A // define all the static fields 0N/A // process all the static initializers 0N/A // add intersection of all thrown clauses of initial constructors 0N/A // to set of caught exceptions, unless class is anonymous. 0N/A // define all the instance fields 0N/A // process all the instance initializers 0N/A // in an anonymous class, add the set of thrown exceptions to 0N/A // the throws clause of the synthetic constructor and propagate 0N/A // process all the methods 0N/A // else we are in an instance initializer block; 0N/A // leave caught unchanged. 0N/A // uncaught throws will be reported later 0N/A // Warn about fall-through if lint switch fallthrough enabled. 0N/A "possible.fall-through.into.case");
0N/A /** Add any variables defined in stats to inits and uninits. */ 0N/A "except.already.caught",
exc);
0N/A "except.never.thrown.in.try",
exc);
0N/A // discard exits and exceptions from try and finally 0N/A "finally.cannot.complete");
0N/A // FIX: this doesn't preserve source order of exits in catch 0N/A // if b and c are boolean valued, then 0N/A // v is (un)assigned after a?b:c when true iff 0N/A // v is (un)assigned after b when true and 0N/A // v is (un)assigned after c when true 0N/A // if not initial constructor, should markDead instead of recordExit 0N/A // Do nothing for TopLevel since each class is visited individually 0N/A/************************************************************************** 0N/A *************************************************************************/ 0N/A // note that recursive invocations of this method fail hard