0N/A/*
2362N/A * Copyright (c) 1996, 2003, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
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
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
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 *
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 *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage sun.tools.tree;
0N/A
0N/Aimport sun.tools.java.*;
0N/A
0N/A/**
0N/A * WARNING: The contents of this source file are not part of any
0N/A * supported API. Code that depends on them does so at its own risk:
0N/A * they are subject to change or removal without notice.
0N/A */
0N/Apublic final
0N/Aclass Vset implements Constants {
0N/A long vset; // DA bits for first 64 variables
0N/A long uset; // DU bits for first 64 variables
0N/A
0N/A // The extension array is interleaved, consisting of alternating
0N/A // blocks of 64 DA bits followed by 64 DU bits followed by 64 DA
0N/A // bits, and so on.
0N/A
0N/A long x[]; // extension array for more bits
0N/A
0N/A // An infinite vector of zeroes or an infinite vector of ones is
0N/A // represented by a special value of the extension array.
0N/A //
0N/A // IMPORTANT: The condition 'this.x == fullX' is used as a marker for
0N/A // unreachable code, i.e., for a dead-end. We maintain the invariant
0N/A // that (this.x != fullX || (this.vset == -1 && this.uset == -1)).
0N/A // A dead-end has the peculiar property that all variables are both
0N/A // definitely assigned and definitely unassigned. We always force this
0N/A // condition to hold, even when the normal bitvector operations performed
0N/A // during DA/DU analysis would produce a different result. This supresses
0N/A // reporting of DA/DU errors in unreachable code.
0N/A
0N/A static final long emptyX[] = new long[0]; // all zeroes
0N/A static final long fullX[] = new long[0]; // all ones
0N/A
0N/A // For more thorough testing of long vset support, it is helpful to
0N/A // temporarily redefine this value to a smaller number, such as 1 or 2.
0N/A
0N/A static final int VBITS = 64; // number of bits in vset (uset)
0N/A
0N/A /**
0N/A * This is the Vset which reports all vars assigned and unassigned.
0N/A * This impossibility is degenerately true exactly when
0N/A * control flow cannot reach this point.
0N/A */
0N/A
0N/A // We distinguish a canonical dead-end value generated initially for
0N/A // statements that do not complete normally, making the next one unreachable.
0N/A // Once an unreachable statement is reported, a non-canonical dead-end value
0N/A // is used for subsequent statements in order to suppress redundant error
0N/A // messages.
0N/A
0N/A static final Vset DEAD_END = new Vset(-1, -1, fullX);
0N/A
0N/A /**
0N/A * Create an empty Vset.
0N/A */
0N/A public Vset() {
0N/A this.x = emptyX;
0N/A }
0N/A
0N/A private Vset(long vset, long uset, long x[]) {
0N/A this.vset = vset;
0N/A this.uset = uset;
0N/A this.x = x;
0N/A }
0N/A
0N/A /**
0N/A * Create an copy of the given Vset.
0N/A * (However, DEAD_END simply returns itself.)
0N/A */
0N/A public Vset copy() {
0N/A if (this == DEAD_END) {
0N/A return this;
0N/A }
0N/A Vset vs = new Vset(vset, uset, x);
0N/A if (x.length > 0) {
0N/A vs.growX(x.length); // recopy the extension vector
0N/A }
0N/A return vs;
0N/A }
0N/A
0N/A private void growX(int length) {
0N/A long newX[] = new long[length];
0N/A long oldX[] = x;
0N/A for (int i = 0; i < oldX.length; i++) {
0N/A newX[i] = oldX[i];
0N/A }
0N/A x = newX;
0N/A }
0N/A
0N/A /**
0N/A * Ask if this is a vset for a dead end.
0N/A * Answer true only for the canonical dead-end, DEAD_END.
0N/A * A canonical dead-end is produced only as a result of
0N/A * a statement that cannot complete normally, as specified
0N/A * by the JLS. Due to the special-case rules for if-then
0N/A * and if-then-else, this may fail to detect actual unreachable
0N/A * code that could easily be identified.
0N/A */
0N/A
0N/A public boolean isDeadEnd() {
0N/A return (this == DEAD_END);
0N/A }
0N/A
0N/A /**
0N/A * Ask if this is a vset for a dead end.
0N/A * Answer true for any dead-end.
0N/A * Since 'clearDeadEnd' has no effect on this predicate,
0N/A * if-then and if-then-else are handled in the more 'obvious'
0N/A * and precise way. This predicate is to be preferred for
0N/A * dead code elimination purposes.
0N/A * (Presently used in workaround for bug 4173473 in MethodExpression.java)
0N/A */
0N/A public boolean isReallyDeadEnd() {
0N/A return (x == fullX);
0N/A }
0N/A
0N/A /**
0N/A * Replace canonical DEAD_END with a distinct but
0N/A * equivalent Vset. The bits are unaltered, but
0N/A * the result does not answer true to 'isDeadEnd'.
0N/A * <p>
0N/A * Used mostly for error recovery, but see
0N/A * 'IfStatement.check', where it is used to
0N/A * implement the special-case treatment of
0N/A * statement reachability for such statements.
0N/A */
0N/A public Vset clearDeadEnd() {
0N/A if (this == DEAD_END) {
0N/A return new Vset(-1, -1, fullX);
0N/A }
0N/A return this;
0N/A }
0N/A
0N/A /**
0N/A * Ask if a var is definitely assigned.
0N/A */
0N/A public boolean testVar(int varNumber) {
0N/A long bit = (1L << varNumber);
0N/A if (varNumber >= VBITS) {
0N/A int i = (varNumber / VBITS - 1) * 2;
0N/A if (i >= x.length) {
0N/A return (x == fullX);
0N/A }
0N/A return (x[i] & bit) != 0;
0N/A } else {
0N/A return (vset & bit) != 0;
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Ask if a var is definitely un-assigned.
0N/A * (This is not just the negation of testVar:
0N/A * It's possible for neither to be true.)
0N/A */
0N/A public boolean testVarUnassigned(int varNumber) {
0N/A long bit = (1L << varNumber);
0N/A if (varNumber >= VBITS) {
0N/A // index "uset" extension
0N/A int i = ((varNumber / VBITS - 1) * 2) + 1;
0N/A if (i >= x.length) {
0N/A return (x == fullX);
0N/A }
0N/A return (x[i] & bit) != 0;
0N/A } else {
0N/A return (uset & bit) != 0;
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Note that a var is definitely assigned.
0N/A * (Side-effecting.)
0N/A */
0N/A public Vset addVar(int varNumber) {
0N/A if (x == fullX) {
0N/A return this;
0N/A }
0N/A
0N/A // gen DA, kill DU
0N/A
0N/A long bit = (1L << varNumber);
0N/A if (varNumber >= VBITS) {
0N/A int i = (varNumber / VBITS - 1) * 2;
0N/A if (i >= x.length) {
0N/A growX(i+1);
0N/A }
0N/A x[i] |= bit;
0N/A if (i+1 < x.length) {
0N/A x[i+1] &=~ bit;
0N/A }
0N/A } else {
0N/A vset |= bit;
0N/A uset &=~ bit;
0N/A }
0N/A return this;
0N/A }
0N/A
0N/A /**
0N/A * Note that a var is definitely un-assigned.
0N/A * (Side-effecting.)
0N/A */
0N/A public Vset addVarUnassigned(int varNumber) {
0N/A if (x == fullX) {
0N/A return this;
0N/A }
0N/A
0N/A // gen DU, kill DA
0N/A
0N/A long bit = (1L << varNumber);
0N/A if (varNumber >= VBITS) {
0N/A // index "uset" extension
0N/A int i = ((varNumber / VBITS - 1) * 2) + 1;
0N/A if (i >= x.length) {
0N/A growX(i+1);
0N/A }
0N/A x[i] |= bit;
0N/A x[i-1] &=~ bit;
0N/A } else {
0N/A uset |= bit;
0N/A vset &=~ bit;
0N/A }
0N/A return this;
0N/A }
0N/A
0N/A /**
0N/A * Retract any assertion about the var.
0N/A * This operation is ineffective on a dead-end.
0N/A * (Side-effecting.)
0N/A */
0N/A public Vset clearVar(int varNumber) {
0N/A if (x == fullX) {
0N/A return this;
0N/A }
0N/A long bit = (1L << varNumber);
0N/A if (varNumber >= VBITS) {
0N/A int i = (varNumber / VBITS - 1) * 2;
0N/A if (i >= x.length) {
0N/A return this;
0N/A }
0N/A x[i] &=~ bit;
0N/A if (i+1 < x.length) {
0N/A x[i+1] &=~ bit;
0N/A }
0N/A } else {
0N/A vset &=~ bit;
0N/A uset &=~ bit;
0N/A }
0N/A return this;
0N/A }
0N/A
0N/A /**
0N/A * Join with another vset. This is set intersection.
0N/A * (Side-effecting.)
0N/A */
0N/A public Vset join(Vset other) {
0N/A
0N/A // Return a dead-end if both vsets are dead-ends.
0N/A // Return the canonical DEAD_END only if both vsets
0N/A // are the canonical DEAD_END. Otherwise, an incoming
0N/A // dead-end vset has already produced an error message,
0N/A // and is now assumed to be reachable.
0N/A if (this == DEAD_END) {
0N/A return other.copy();
0N/A }
0N/A if (other == DEAD_END) {
0N/A return this;
0N/A }
0N/A if (x == fullX) {
0N/A return other.copy();
0N/A }
0N/A if (other.x == fullX) {
0N/A return this;
0N/A }
0N/A
0N/A // DA = DA intersection DA
0N/A // DU = DU intersection DU
0N/A
0N/A vset &= other.vset;
0N/A uset &= other.uset;
0N/A
0N/A if (other.x == emptyX) {
0N/A x = emptyX;
0N/A } else {
0N/A // ASSERT(otherX.length > 0);
0N/A long otherX[] = other.x;
0N/A int selfLength = x.length;
0N/A int limit = (otherX.length < selfLength) ? otherX.length : selfLength;
0N/A for (int i = 0; i < limit; i++) {
0N/A x[i] &= otherX[i];
0N/A }
0N/A // If self is longer than other, all remaining
0N/A // bits are implicitly 0. In the result, then,
0N/A // the remaining DA and DU bits are cleared.
0N/A for (int i = limit; i < selfLength; i++) {
0N/A x[i] = 0;
0N/A }
0N/A }
0N/A return this;
0N/A }
0N/A
0N/A /**
0N/A * Add in the definite assignment bits of another vset,
0N/A * but join the definite unassignment bits. This unusual
0N/A * operation is used only for 'finally' blocks. The
0N/A * original vset 'this' is destroyed by this operation.
0N/A * (Part of fix for 4068688.)
0N/A */
0N/A
0N/A public Vset addDAandJoinDU(Vset other) {
0N/A
0N/A // Return a dead-end if either vset is a dead end.
0N/A // If either vset is the canonical DEAD_END, the
0N/A // result is also the canonical DEAD_END.
0N/A if (this == DEAD_END) {
0N/A return this;
0N/A }
0N/A if (other == DEAD_END) {
0N/A return other;
0N/A }
0N/A if (x == fullX) {
0N/A return this;
0N/A }
0N/A if (other.x == fullX) {
0N/A return other.copy();
0N/A }
0N/A
0N/A // DA = DA union DA'
0N/A // DU = (DU intersection DU') - DA'
0N/A
0N/A vset = vset | other.vset;
0N/A uset = (uset & other.uset) & ~other.vset;
0N/A
0N/A int selfLength = x.length;
0N/A long otherX[] = other.x;
0N/A int otherLength = otherX.length;
0N/A
0N/A if (otherX != emptyX) {
0N/A // ASSERT(otherX.length > 0);
0N/A if (otherLength > selfLength) {
0N/A growX(otherLength);
0N/A }
0N/A int i = 0;
0N/A while (i < otherLength) {
0N/A x[i] |= otherX[i];
0N/A i++;
0N/A if (i == otherLength) break;
0N/A x[i] = ((x[i] & otherX[i]) & ~otherX[i-1]);
0N/A i++;
0N/A }
0N/A }
0N/A // If self is longer than other, all remaining
0N/A // bits are implicitly 0. In the result, then,
0N/A // the remaining DA bits are left unchanged, and
0N/A // the DU bits are all cleared. First, align
0N/A // index to the next block of DU bits (odd index).
0N/A for (int i = (otherLength | 1); i < selfLength; i += 2) {
0N/A x[i] = 0;
0N/A }
0N/A return this;
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Construct a vset consisting of the DA bits of the first argument
0N/A * and the DU bits of the second argument. This is a higly unusual
0N/A * operation, as it implies a case where the flowgraph for DA analysis
0N/A * differs from that for DU analysis. It is only needed for analysing
0N/A * 'try' blocks. The result is a dead-end iff the first argument is
0N/A * dead-end. (Part of fix for 4068688.)
0N/A */
0N/A
0N/A public static Vset firstDAandSecondDU(Vset sourceDA, Vset sourceDU) {
0N/A
0N/A // Note that reachability status is received via 'sourceDA' only!
0N/A // This is a consequence of the fact that reachability and DA
0N/A // analysis are performed on an identical flow graph, whereas the
0N/A // flowgraph for DU analysis differs in the case of a 'try' statement.
0N/A if (sourceDA.x == fullX) {
0N/A return sourceDA.copy();
0N/A }
0N/A
0N/A long sourceDAx[] = sourceDA.x;
0N/A int lenDA = sourceDAx.length;
0N/A long sourceDUx[] = sourceDU.x;
0N/A int lenDU = sourceDUx.length;
0N/A int limit = (lenDA > lenDU) ? lenDA : lenDU;
0N/A long x[] = emptyX;
0N/A
0N/A if (limit > 0) {
0N/A x = new long[limit];
0N/A for (int i = 0; i < lenDA; i += 2) {
0N/A x[i] = sourceDAx[i];
0N/A }
0N/A for (int i = 1; i < lenDU; i += 2) {
0N/A x[i] = sourceDUx[i];
0N/A }
0N/A }
0N/A
0N/A return new Vset(sourceDA.vset, sourceDU.uset, x);
0N/A }
0N/A
0N/A /**
0N/A * Remove variables from the vset that are no longer part of
0N/A * a context. Zeroes are stored past varNumber.
0N/A * (Side-effecting.)<p>
0N/A * However, if this is a dead end, keep it so.
0N/A * That is, leave an infinite tail of bits set.
0N/A */
0N/A public Vset removeAdditionalVars(int varNumber) {
0N/A if (x == fullX) {
0N/A return this;
0N/A }
0N/A long bit = (1L << varNumber);
0N/A if (varNumber >= VBITS) {
0N/A int i = (varNumber / VBITS - 1) * 2;
0N/A if (i < x.length) {
0N/A x[i] &= (bit - 1);
0N/A if (++i < x.length) {
0N/A x[i] &= (bit - 1); // do the "uset" extension also
0N/A }
0N/A while (++i < x.length) {
0N/A x[i] = 0;
0N/A }
0N/A }
0N/A } else {
0N/A if (x.length > 0) {
0N/A x = emptyX;
0N/A }
0N/A vset &= (bit - 1);
0N/A uset &= (bit - 1);
0N/A }
0N/A return this;
0N/A }
0N/A
0N/A /**
0N/A * Return one larger than the highest bit set.
0N/A */
0N/A public int varLimit() {
0N/A long vset;
0N/A int result;
0N/A scan: {
0N/A for (int i = (x.length / 2) * 2; i >= 0; i -= 2) {
0N/A if (i == x.length) continue; // oops
0N/A vset = x[i];
0N/A if (i+1 < x.length) {
0N/A vset |= x[i+1]; // check the "uset" also
0N/A }
0N/A if (vset != 0) {
0N/A result = (i/2 + 1) * VBITS;
0N/A break scan;
0N/A }
0N/A }
0N/A vset = this.vset;
0N/A vset |= this.uset; // check the "uset" also
0N/A if (vset != 0) {
0N/A result = 0;
0N/A break scan;
0N/A } else {
0N/A return 0;
0N/A }
0N/A }
0N/A while (vset != 0) {
0N/A result += 1;
0N/A vset >>>= 1;
0N/A }
0N/A return result;
0N/A }
0N/A
0N/A public String toString() {
0N/A if (this == DEAD_END)
0N/A return "{DEAD_END}";
0N/A StringBuffer sb = new StringBuffer("{");
0N/A int maxVar = VBITS * (1 + (x.length+1)/2);
0N/A for (int i = 0; i < maxVar; i++) {
0N/A if (!testVarUnassigned(i)) {
0N/A if (sb.length() > 1) {
0N/A sb.append(' ');
0N/A }
0N/A sb.append(i);
0N/A if (!testVar(i)) {
0N/A sb.append('?'); // not definitely unassigned
0N/A }
0N/A }
0N/A }
0N/A if (x == fullX) {
0N/A sb.append("...DEAD_END");
0N/A }
0N/A sb.append('}');
0N/A return sb.toString();
0N/A }
0N/A
0N/A}