/java-1.7.0-openjdk/openjdk/jdk/src/share/classes/sun/tools/tree/Vset.java
Java | 518 lines | 296 code | 52 blank | 170 comment | 97 complexity | c5c1a1d05f6292cb37e33170ca502663 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause-No-Nuclear-License-2014, LGPL-3.0, LGPL-2.0
- /*
- * Copyright (c) 1996, 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.*;
- /**
- * 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.
- */
- public final
- class Vset implements Constants {
- long vset; // DA bits for first 64 variables
- long uset; // DU bits for first 64 variables
- // The extension array is interleaved, consisting of alternating
- // blocks of 64 DA bits followed by 64 DU bits followed by 64 DA
- // bits, and so on.
- long x[]; // extension array for more bits
- // An infinite vector of zeroes or an infinite vector of ones is
- // represented by a special value of the extension array.
- //
- // IMPORTANT: The condition 'this.x == fullX' is used as a marker for
- // unreachable code, i.e., for a dead-end. We maintain the invariant
- // that (this.x != fullX || (this.vset == -1 && this.uset == -1)).
- // A dead-end has the peculiar property that all variables are both
- // definitely assigned and definitely unassigned. We always force this
- // condition to hold, even when the normal bitvector operations performed
- // during DA/DU analysis would produce a different result. This supresses
- // reporting of DA/DU errors in unreachable code.
- static final long emptyX[] = new long[0]; // all zeroes
- static final long fullX[] = new long[0]; // all ones
- // For more thorough testing of long vset support, it is helpful to
- // temporarily redefine this value to a smaller number, such as 1 or 2.
- static final int VBITS = 64; // number of bits in vset (uset)
- /**
- * This is the Vset which reports all vars assigned and unassigned.
- * This impossibility is degenerately true exactly when
- * control flow cannot reach this point.
- */
- // We distinguish a canonical dead-end value generated initially for
- // statements that do not complete normally, making the next one unreachable.
- // Once an unreachable statement is reported, a non-canonical dead-end value
- // is used for subsequent statements in order to suppress redundant error
- // messages.
- static final Vset DEAD_END = new Vset(-1, -1, fullX);
- /**
- * Create an empty Vset.
- */
- public Vset() {
- this.x = emptyX;
- }
- private Vset(long vset, long uset, long x[]) {
- this.vset = vset;
- this.uset = uset;
- this.x = x;
- }
- /**
- * Create an copy of the given Vset.
- * (However, DEAD_END simply returns itself.)
- */
- public Vset copy() {
- if (this == DEAD_END) {
- return this;
- }
- Vset vs = new Vset(vset, uset, x);
- if (x.length > 0) {
- vs.growX(x.length); // recopy the extension vector
- }
- return vs;
- }
- private void growX(int length) {
- long newX[] = new long[length];
- long oldX[] = x;
- for (int i = 0; i < oldX.length; i++) {
- newX[i] = oldX[i];
- }
- x = newX;
- }
- /**
- * Ask if this is a vset for a dead end.
- * Answer true only for the canonical dead-end, DEAD_END.
- * A canonical dead-end is produced only as a result of
- * a statement that cannot complete normally, as specified
- * by the JLS. Due to the special-case rules for if-then
- * and if-then-else, this may fail to detect actual unreachable
- * code that could easily be identified.
- */
- public boolean isDeadEnd() {
- return (this == DEAD_END);
- }
- /**
- * Ask if this is a vset for a dead end.
- * Answer true for any dead-end.
- * Since 'clearDeadEnd' has no effect on this predicate,
- * if-then and if-then-else are handled in the more 'obvious'
- * and precise way. This predicate is to be preferred for
- * dead code elimination purposes.
- * (Presently used in workaround for bug 4173473 in MethodExpression.java)
- */
- public boolean isReallyDeadEnd() {
- return (x == fullX);
- }
- /**
- * Replace canonical DEAD_END with a distinct but
- * equivalent Vset. The bits are unaltered, but
- * the result does not answer true to 'isDeadEnd'.
- * <p>
- * Used mostly for error recovery, but see
- * 'IfStatement.check', where it is used to
- * implement the special-case treatment of
- * statement reachability for such statements.
- */
- public Vset clearDeadEnd() {
- if (this == DEAD_END) {
- return new Vset(-1, -1, fullX);
- }
- return this;
- }
- /**
- * Ask if a var is definitely assigned.
- */
- public boolean testVar(int varNumber) {
- long bit = (1L << varNumber);
- if (varNumber >= VBITS) {
- int i = (varNumber / VBITS - 1) * 2;
- if (i >= x.length) {
- return (x == fullX);
- }
- return (x[i] & bit) != 0;
- } else {
- return (vset & bit) != 0;
- }
- }
- /**
- * Ask if a var is definitely un-assigned.
- * (This is not just the negation of testVar:
- * It's possible for neither to be true.)
- */
- public boolean testVarUnassigned(int varNumber) {
- long bit = (1L << varNumber);
- if (varNumber >= VBITS) {
- // index "uset" extension
- int i = ((varNumber / VBITS - 1) * 2) + 1;
- if (i >= x.length) {
- return (x == fullX);
- }
- return (x[i] & bit) != 0;
- } else {
- return (uset & bit) != 0;
- }
- }
- /**
- * Note that a var is definitely assigned.
- * (Side-effecting.)
- */
- public Vset addVar(int varNumber) {
- if (x == fullX) {
- return this;
- }
- // gen DA, kill DU
- long bit = (1L << varNumber);
- if (varNumber >= VBITS) {
- int i = (varNumber / VBITS - 1) * 2;
- if (i >= x.length) {
- growX(i+1);
- }
- x[i] |= bit;
- if (i+1 < x.length) {
- x[i+1] &=~ bit;
- }
- } else {
- vset |= bit;
- uset &=~ bit;
- }
- return this;
- }
- /**
- * Note that a var is definitely un-assigned.
- * (Side-effecting.)
- */
- public Vset addVarUnassigned(int varNumber) {
- if (x == fullX) {
- return this;
- }
- // gen DU, kill DA
- long bit = (1L << varNumber);
- if (varNumber >= VBITS) {
- // index "uset" extension
- int i = ((varNumber / VBITS - 1) * 2) + 1;
- if (i >= x.length) {
- growX(i+1);
- }
- x[i] |= bit;
- x[i-1] &=~ bit;
- } else {
- uset |= bit;
- vset &=~ bit;
- }
- return this;
- }
- /**
- * Retract any assertion about the var.
- * This operation is ineffective on a dead-end.
- * (Side-effecting.)
- */
- public Vset clearVar(int varNumber) {
- if (x == fullX) {
- return this;
- }
- long bit = (1L << varNumber);
- if (varNumber >= VBITS) {
- int i = (varNumber / VBITS - 1) * 2;
- if (i >= x.length) {
- return this;
- }
- x[i] &=~ bit;
- if (i+1 < x.length) {
- x[i+1] &=~ bit;
- }
- } else {
- vset &=~ bit;
- uset &=~ bit;
- }
- return this;
- }
- /**
- * Join with another vset. This is set intersection.
- * (Side-effecting.)
- */
- public Vset join(Vset other) {
- // Return a dead-end if both vsets are dead-ends.
- // Return the canonical DEAD_END only if both vsets
- // are the canonical DEAD_END. Otherwise, an incoming
- // dead-end vset has already produced an error message,
- // and is now assumed to be reachable.
- if (this == DEAD_END) {
- return other.copy();
- }
- if (other == DEAD_END) {
- return this;
- }
- if (x == fullX) {
- return other.copy();
- }
- if (other.x == fullX) {
- return this;
- }
- // DA = DA intersection DA
- // DU = DU intersection DU
- vset &= other.vset;
- uset &= other.uset;
- if (other.x == emptyX) {
- x = emptyX;
- } else {
- // ASSERT(otherX.length > 0);
- long otherX[] = other.x;
- int selfLength = x.length;
- int limit = (otherX.length < selfLength) ? otherX.length : selfLength;
- for (int i = 0; i < limit; i++) {
- x[i] &= otherX[i];
- }
- // If self is longer than other, all remaining
- // bits are implicitly 0. In the result, then,
- // the remaining DA and DU bits are cleared.
- for (int i = limit; i < selfLength; i++) {
- x[i] = 0;
- }
- }
- return this;
- }
- /**
- * Add in the definite assignment bits of another vset,
- * but join the definite unassignment bits. This unusual
- * operation is used only for 'finally' blocks. The
- * original vset 'this' is destroyed by this operation.
- * (Part of fix for 4068688.)
- */
- public Vset addDAandJoinDU(Vset other) {
- // Return a dead-end if either vset is a dead end.
- // If either vset is the canonical DEAD_END, the
- // result is also the canonical DEAD_END.
- if (this == DEAD_END) {
- return this;
- }
- if (other == DEAD_END) {
- return other;
- }
- if (x == fullX) {
- return this;
- }
- if (other.x == fullX) {
- return other.copy();
- }
- // DA = DA union DA'
- // DU = (DU intersection DU') - DA'
- vset = vset | other.vset;
- uset = (uset & other.uset) & ~other.vset;
- int selfLength = x.length;
- long otherX[] = other.x;
- int otherLength = otherX.length;
- if (otherX != emptyX) {
- // ASSERT(otherX.length > 0);
- if (otherLength > selfLength) {
- growX(otherLength);
- }
- int i = 0;
- while (i < otherLength) {
- x[i] |= otherX[i];
- i++;
- if (i == otherLength) break;
- x[i] = ((x[i] & otherX[i]) & ~otherX[i-1]);
- i++;
- }
- }
- // If self is longer than other, all remaining
- // bits are implicitly 0. In the result, then,
- // the remaining DA bits are left unchanged, and
- // the DU bits are all cleared. First, align
- // index to the next block of DU bits (odd index).
- for (int i = (otherLength | 1); i < selfLength; i += 2) {
- x[i] = 0;
- }
- return this;
- }
- /**
- * Construct a vset consisting of the DA bits of the first argument
- * and the DU bits of the second argument. This is a higly unusual
- * operation, as it implies a case where the flowgraph for DA analysis
- * differs from that for DU analysis. It is only needed for analysing
- * 'try' blocks. The result is a dead-end iff the first argument is
- * dead-end. (Part of fix for 4068688.)
- */
- public static Vset firstDAandSecondDU(Vset sourceDA, Vset sourceDU) {
- // Note that reachability status is received via 'sourceDA' only!
- // This is a consequence of the fact that reachability and DA
- // analysis are performed on an identical flow graph, whereas the
- // flowgraph for DU analysis differs in the case of a 'try' statement.
- if (sourceDA.x == fullX) {
- return sourceDA.copy();
- }
- long sourceDAx[] = sourceDA.x;
- int lenDA = sourceDAx.length;
- long sourceDUx[] = sourceDU.x;
- int lenDU = sourceDUx.length;
- int limit = (lenDA > lenDU) ? lenDA : lenDU;
- long x[] = emptyX;
- if (limit > 0) {
- x = new long[limit];
- for (int i = 0; i < lenDA; i += 2) {
- x[i] = sourceDAx[i];
- }
- for (int i = 1; i < lenDU; i += 2) {
- x[i] = sourceDUx[i];
- }
- }
- return new Vset(sourceDA.vset, sourceDU.uset, x);
- }
- /**
- * Remove variables from the vset that are no longer part of
- * a context. Zeroes are stored past varNumber.
- * (Side-effecting.)<p>
- * However, if this is a dead end, keep it so.
- * That is, leave an infinite tail of bits set.
- */
- public Vset removeAdditionalVars(int varNumber) {
- if (x == fullX) {
- return this;
- }
- long bit = (1L << varNumber);
- if (varNumber >= VBITS) {
- int i = (varNumber / VBITS - 1) * 2;
- if (i < x.length) {
- x[i] &= (bit - 1);
- if (++i < x.length) {
- x[i] &= (bit - 1); // do the "uset" extension also
- }
- while (++i < x.length) {
- x[i] = 0;
- }
- }
- } else {
- if (x.length > 0) {
- x = emptyX;
- }
- vset &= (bit - 1);
- uset &= (bit - 1);
- }
- return this;
- }
- /**
- * Return one larger than the highest bit set.
- */
- public int varLimit() {
- long vset;
- int result;
- scan: {
- for (int i = (x.length / 2) * 2; i >= 0; i -= 2) {
- if (i == x.length) continue; // oops
- vset = x[i];
- if (i+1 < x.length) {
- vset |= x[i+1]; // check the "uset" also
- }
- if (vset != 0) {
- result = (i/2 + 1) * VBITS;
- break scan;
- }
- }
- vset = this.vset;
- vset |= this.uset; // check the "uset" also
- if (vset != 0) {
- result = 0;
- break scan;
- } else {
- return 0;
- }
- }
- while (vset != 0) {
- result += 1;
- vset >>>= 1;
- }
- return result;
- }
- public String toString() {
- if (this == DEAD_END)
- return "{DEAD_END}";
- StringBuffer sb = new StringBuffer("{");
- int maxVar = VBITS * (1 + (x.length+1)/2);
- for (int i = 0; i < maxVar; i++) {
- if (!testVarUnassigned(i)) {
- if (sb.length() > 1) {
- sb.append(' ');
- }
- sb.append(i);
- if (!testVar(i)) {
- sb.append('?'); // not definitely unassigned
- }
- }
- }
- if (x == fullX) {
- sb.append("...DEAD_END");
- }
- sb.append('}');
- return sb.toString();
- }
- }