/*******************************************************************************
- * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Common Public License v0.5
+ * are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v05.html
+ * http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
- ******************************************************************************/
+ *******************************************************************************/
package net.sourceforge.phpdt.internal.compiler.flow;
-import net.sourceforge.phpdt.internal.compiler.ast.AstNode;
-import net.sourceforge.phpdt.internal.compiler.ast.Statement;
+import net.sourceforge.phpdt.internal.compiler.impl.Constant;
import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope;
import net.sourceforge.phpdt.internal.compiler.lookup.FieldBinding;
import net.sourceforge.phpdt.internal.compiler.lookup.LocalVariableBinding;
import net.sourceforge.phpdt.internal.compiler.lookup.ReferenceBinding;
+import net.sourceforge.phpeclipse.internal.compiler.ast.ASTNode;
+import net.sourceforge.phpeclipse.internal.compiler.ast.Statement;
/**
* Record initialization status during definite assignment analysis
* No caching of pre-allocated instances.
*/
public class UnconditionalFlowInfo extends FlowInfo {
+
+
public long definiteInits;
- long potentialInits;
+ public long potentialInits;
public long extraDefiniteInits[];
- long extraPotentialInits[];
- public boolean isFakeReachable;
+ public long extraPotentialInits[];
+
+ public int reachMode = REACHABLE; // by default
+
public int maxFieldCount;
// Constants
public static final int BitCacheSize = 64; // 64 bits in a long.
-UnconditionalFlowInfo() {
-}
-public UnconditionalFlowInfo addInitializationsFrom(UnconditionalFlowInfo otherInits) {
+
+ UnconditionalFlowInfo() {
+ }
// unions of both sets of initialization - used for try/finally
- if (this == DeadEnd)
- return this;
- if (otherInits == DeadEnd)
- return this;
-
- // union of definitely assigned variables,
- definiteInits |= otherInits.definiteInits;
- // union of potentially set ones
- potentialInits |= otherInits.potentialInits;
+ public FlowInfo addInitializationsFrom(FlowInfo inits) {
- // treating extra storage
- if (extraDefiniteInits != null) {
- if (otherInits.extraDefiniteInits != null) {
- // both sides have extra storage
- int i = 0, length, otherLength;
- if ((length = extraDefiniteInits.length) < (otherLength = otherInits.extraDefiniteInits.length)) {
- // current storage is shorter -> grow current (could maybe reuse otherInits extra storage?)
- System.arraycopy(extraDefiniteInits, 0, (extraDefiniteInits = new long[otherLength]), 0, length);
- System.arraycopy(extraPotentialInits, 0, (extraPotentialInits = new long[otherLength]), 0, length);
- while (i < length) {
- extraDefiniteInits[i] |= otherInits.extraDefiniteInits[i];
- extraPotentialInits[i] |= otherInits.extraPotentialInits[i++];
- }
- while (i < otherLength) {
- extraPotentialInits[i] = otherInits.extraPotentialInits[i++];
+ if (this == DEAD_END)
+ return this;
+
+ UnconditionalFlowInfo otherInits = inits.unconditionalInits();
+ if (otherInits == DEAD_END)
+ return this;
+
+ // union of definitely assigned variables,
+ definiteInits |= otherInits.definiteInits;
+ // union of potentially set ones
+ potentialInits |= otherInits.potentialInits;
+
+ // treating extra storage
+ if (extraDefiniteInits != null) {
+ if (otherInits.extraDefiniteInits != null) {
+ // both sides have extra storage
+ int i = 0, length, otherLength;
+ if ((length = extraDefiniteInits.length) < (otherLength = otherInits.extraDefiniteInits.length)) {
+ // current storage is shorter -> grow current (could maybe reuse otherInits extra storage?)
+ System.arraycopy(extraDefiniteInits, 0, (extraDefiniteInits = new long[otherLength]), 0, length);
+ System.arraycopy(extraPotentialInits, 0, (extraPotentialInits = new long[otherLength]), 0, length);
+ while (i < length) {
+ extraDefiniteInits[i] |= otherInits.extraDefiniteInits[i];
+ extraPotentialInits[i] |= otherInits.extraPotentialInits[i++];
+ }
+ while (i < otherLength) {
+ extraPotentialInits[i] = otherInits.extraPotentialInits[i++];
+ }
+ } else {
+ // current storage is longer
+ while (i < otherLength) {
+ extraDefiniteInits[i] |= otherInits.extraDefiniteInits[i];
+ extraPotentialInits[i] |= otherInits.extraPotentialInits[i++];
+ }
+ while (i < length)
+ extraDefiniteInits[i++] = 0;
}
} else {
- // current storage is longer
- while (i < otherLength) {
- extraDefiniteInits[i] |= otherInits.extraDefiniteInits[i];
- extraPotentialInits[i] |= otherInits.extraPotentialInits[i++];
- }
- while (i < length)
- extraDefiniteInits[i++] = 0;
+ // no extra storage on otherInits
+ }
+ } else
+ if (otherInits.extraDefiniteInits != null) {
+ // no storage here, but other has extra storage.
+ int otherLength;
+ System.arraycopy(otherInits.extraDefiniteInits, 0, (extraDefiniteInits = new long[otherLength = otherInits.extraDefiniteInits.length]), 0, otherLength);
+ System.arraycopy(otherInits.extraPotentialInits, 0, (extraPotentialInits = new long[otherLength]), 0, otherLength);
}
- } else {
- // no extra storage on otherInits
- }
- } else
- if (otherInits.extraDefiniteInits != null) {
- // no storage here, but other has extra storage.
- int otherLength;
- System.arraycopy(otherInits.extraDefiniteInits, 0, (extraDefiniteInits = new long[otherLength = otherInits.extraDefiniteInits.length]), 0, otherLength);
- System.arraycopy(otherInits.extraPotentialInits, 0, (extraPotentialInits = new long[otherLength]), 0, otherLength);
- }
- return this;
-}
-public UnconditionalFlowInfo addPotentialInitializationsFrom(UnconditionalFlowInfo otherInits) {
-
- // unions of both sets of initialization - used for try/finally
- if (this == DeadEnd){
return this;
}
- if (otherInits == DeadEnd){
+
+ // unions of both sets of initialization - used for try/finally
+ public FlowInfo addPotentialInitializationsFrom(FlowInfo inits) {
+
+ if (this == DEAD_END){
+ return this;
+ }
+
+ UnconditionalFlowInfo otherInits = inits.unconditionalInits();
+ if (otherInits == DEAD_END){
+ return this;
+ }
+ // union of potentially set ones
+ potentialInits |= otherInits.potentialInits;
+
+ // treating extra storage
+ if (extraDefiniteInits != null) {
+ if (otherInits.extraDefiniteInits != null) {
+ // both sides have extra storage
+ int i = 0, length, otherLength;
+ if ((length = extraDefiniteInits.length) < (otherLength = otherInits.extraDefiniteInits.length)) {
+ // current storage is shorter -> grow current (could maybe reuse otherInits extra storage?)
+ System.arraycopy(extraDefiniteInits, 0, (extraDefiniteInits = new long[otherLength]), 0, length);
+ System.arraycopy(extraPotentialInits, 0, (extraPotentialInits = new long[otherLength]), 0, length);
+ while (i < length) {
+ extraPotentialInits[i] |= otherInits.extraPotentialInits[i++];
+ }
+ while (i < otherLength) {
+ extraPotentialInits[i] = otherInits.extraPotentialInits[i++];
+ }
+ } else {
+ // current storage is longer
+ while (i < otherLength) {
+ extraPotentialInits[i] |= otherInits.extraPotentialInits[i++];
+ }
+ }
+ }
+ } else
+ if (otherInits.extraDefiniteInits != null) {
+ // no storage here, but other has extra storage.
+ int otherLength;
+ extraDefiniteInits = new long[otherLength = otherInits.extraDefiniteInits.length];
+ System.arraycopy(otherInits.extraPotentialInits, 0, (extraPotentialInits = new long[otherLength]), 0, otherLength);
+ }
return this;
}
- // union of potentially set ones
- potentialInits |= otherInits.potentialInits;
- // treating extra storage
- if (extraDefiniteInits != null) {
- if (otherInits.extraDefiniteInits != null) {
- // both sides have extra storage
- int i = 0, length, otherLength;
- if ((length = extraDefiniteInits.length) < (otherLength = otherInits.extraDefiniteInits.length)) {
- // current storage is shorter -> grow current (could maybe reuse otherInits extra storage?)
- System.arraycopy(extraDefiniteInits, 0, (extraDefiniteInits = new long[otherLength]), 0, length);
- System.arraycopy(extraPotentialInits, 0, (extraPotentialInits = new long[otherLength]), 0, length);
- while (i < length) {
- extraPotentialInits[i] |= otherInits.extraPotentialInits[i++];
- }
- while (i < otherLength) {
- extraPotentialInits[i] = otherInits.extraPotentialInits[i++];
- }
- } else {
- // current storage is longer
- while (i < otherLength) {
- extraPotentialInits[i] |= otherInits.extraPotentialInits[i++];
- }
+ // Report an error if necessary
+ public boolean complainIfUnreachable(Statement statement, BlockScope scope, boolean didAlreadyComplain) {
+
+ if ((this.reachMode & UNREACHABLE) != 0) {
+ statement.bits &= ~ASTNode.IsReachableMASK;
+ boolean reported = this == DEAD_END;
+ if (!didAlreadyComplain && reported) {
+ scope.problemReporter().unreachableCode(statement);
}
+ return reported; // keep going for fake reachable
}
- } else
- if (otherInits.extraDefiniteInits != null) {
- // no storage here, but other has extra storage.
- int otherLength;
- extraDefiniteInits = new long[otherLength = otherInits.extraDefiniteInits.length];
- System.arraycopy(otherInits.extraPotentialInits, 0, (extraPotentialInits = new long[otherLength]), 0, otherLength);
+ return false;
+ }
+
+ /**
+ * Answers a copy of the current instance
+ */
+ public FlowInfo copy() {
+
+ // do not clone the DeadEnd
+ if (this == DEAD_END)
+ return this;
+
+ // look for an unused preallocated object
+ UnconditionalFlowInfo copy = new UnconditionalFlowInfo();
+
+ // copy slots
+ copy.definiteInits = this.definiteInits;
+ copy.potentialInits = this.potentialInits;
+ copy.reachMode = this.reachMode;
+ copy.maxFieldCount = this.maxFieldCount;
+
+ if (this.extraDefiniteInits != null) {
+ int length;
+ System.arraycopy(this.extraDefiniteInits, 0, (copy.extraDefiniteInits = new long[ (length = extraDefiniteInits.length)]), 0, length);
+ System.arraycopy(this.extraPotentialInits, 0, (copy.extraPotentialInits = new long[length]), 0, length);
+ };
+ return copy;
+ }
+
+ public UnconditionalFlowInfo discardFieldInitializations(){
+
+ int limit = this.maxFieldCount;
+
+ if (limit < BitCacheSize) {
+ long mask = (1L << limit)-1;
+ this.definiteInits &= ~mask;
+ this.potentialInits &= ~mask;
+ return this;
+ }
+
+ this.definiteInits = 0;
+ this.potentialInits = 0;
+
+ // use extra vector
+ if (extraDefiniteInits == null) {
+ return this; // if vector not yet allocated, then not initialized
}
- return this;
-}
-public boolean complainIfUnreachable(Statement statement, BlockScope scope) {
- // Report an error if necessary
+ int vectorIndex, length = this.extraDefiniteInits.length;
+ if ((vectorIndex = (limit / BitCacheSize) - 1) >= length) {
+ return this; // not enough room yet
+ }
+ for (int i = 0; i < vectorIndex; i++) {
+ this.extraDefiniteInits[i] = 0L;
+ this.extraPotentialInits[i] = 0L;
+ }
+ long mask = (1L << (limit % BitCacheSize))-1;
+ this.extraDefiniteInits[vectorIndex] &= ~mask;
+ this.extraPotentialInits[vectorIndex] &= ~mask;
+ return this;
+ }
- boolean isDeadEnd;
- if ((isDeadEnd = (this == DeadEnd)) || isFakeReachable) {
- statement.bits &= ~AstNode.IsReachableMASK;
- /* EXTRA REFERENCE RECORDING
- statement.recordUnreachableReferences(scope.referenceType()); // scopes cannot have an enclosingMethod slot since there are class scopes
- */
- if (isDeadEnd)
- scope.problemReporter().unreachableCode(statement);
- return isDeadEnd;
+ public UnconditionalFlowInfo discardNonFieldInitializations(){
+
+ int limit = this.maxFieldCount;
+
+ if (limit < BitCacheSize) {
+ long mask = (1L << limit)-1;
+ this.definiteInits &= mask;
+ this.potentialInits &= mask;
+ return this;
+ }
+ // use extra vector
+ if (extraDefiniteInits == null) {
+ return this; // if vector not yet allocated, then not initialized
+ }
+ int vectorIndex, length = this.extraDefiniteInits.length;
+ if ((vectorIndex = (limit / BitCacheSize) - 1) >= length) {
+ return this; // not enough room yet
+ }
+ long mask = (1L << (limit % BitCacheSize))-1;
+ this.extraDefiniteInits[vectorIndex] &= mask;
+ this.extraPotentialInits[vectorIndex] &= mask;
+ for (int i = vectorIndex+1; i < length; i++) {
+ this.extraDefiniteInits[i] = 0L;
+ this.extraPotentialInits[i] = 0L;
+ }
+ return this;
}
- return false;
-}
-/**
- * Answers a copy of the current instance
- */
-public FlowInfo copy() {
- // do not clone the DeadEnd
- if (this == DeadEnd)
+
+ public FlowInfo initsWhenFalse() {
+
return this;
-
- // look for an unused preallocated object
- UnconditionalFlowInfo copy = new UnconditionalFlowInfo();
-
- // copy slots
- copy.definiteInits = definiteInits;
- copy.potentialInits = potentialInits;
- copy.isFakeReachable = isFakeReachable;
- copy.maxFieldCount = maxFieldCount;
-
- if (extraDefiniteInits != null) {
- int length;
- System.arraycopy(extraDefiniteInits, 0, (copy.extraDefiniteInits = new long[ (length = extraDefiniteInits.length)]), 0, length);
- System.arraycopy(extraPotentialInits, 0, (copy.extraPotentialInits = new long[length]), 0, length);
- };
- return copy;
-}
-public FlowInfo initsWhenFalse() {
- return this;
-}
-public FlowInfo initsWhenTrue() {
- return this;
-}
-/**
- * Check status of definite assignment at a given position.
- * It deals with the dual representation of the InitializationInfo2:
- * bits for the first 64 entries, then an array of booleans.
- */
-final private boolean isDefinitelyAssigned(int position) {
- // Dependant of CodeStream.isDefinitelyAssigned(..)
- // id is zero-based
- if (position < BitCacheSize) {
- return (definiteInits & (1L << position)) != 0; // use bits
}
- // use extra vector
- if (extraDefiniteInits == null)
- return false; // if vector not yet allocated, then not initialized
- int vectorIndex;
- if ((vectorIndex = (position / BitCacheSize) - 1) >= extraDefiniteInits.length)
- return false; // if not enough room in vector, then not initialized
- return ((extraDefiniteInits[vectorIndex]) & (1L << (position % BitCacheSize))) != 0;
-}
-/**
- * Check status of definite assignment for a field.
- */
-final public boolean isDefinitelyAssigned(FieldBinding field) {
- // Dependant of CodeStream.isDefinitelyAssigned(..)
- // We do not want to complain in unreachable code
- if ((this == DeadEnd) || (this.isFakeReachable))
- return true;
- return isDefinitelyAssigned(field.id);
-}
-/**
- * Check status of definite assignment for a local.
- */
-final public boolean isDefinitelyAssigned(LocalVariableBinding local) {
- // Dependant of CodeStream.isDefinitelyAssigned(..)
- // We do not want to complain in unreachable code
- if ((this == DeadEnd) || (this.isFakeReachable))
- return true;
- if (local.isArgument) {
- return true;
+
+ public FlowInfo initsWhenTrue() {
+
+ return this;
}
- return isDefinitelyAssigned(local.id + maxFieldCount);
-}
-public boolean isFakeReachable() {
- return isFakeReachable;
-}
-/**
- * Check status of potential assignment at a given position.
- * It deals with the dual representation of the InitializationInfo3:
- * bits for the first 64 entries, then an array of booleans.
- */
-final private boolean isPotentiallyAssigned(int position) {
- // id is zero-based
- if (position < BitCacheSize) {
- // use bits
- return (potentialInits & (1L << position)) != 0;
+
+ /**
+ * Check status of definite assignment at a given position.
+ * It deals with the dual representation of the InitializationInfo2:
+ * bits for the first 64 entries, then an array of booleans.
+ */
+ final private boolean isDefinitelyAssigned(int position) {
+
+ // Dependant of CodeStream.isDefinitelyAssigned(..)
+ // id is zero-based
+ if (position < BitCacheSize) {
+ return (definiteInits & (1L << position)) != 0; // use bits
+ }
+ // use extra vector
+ if (extraDefiniteInits == null)
+ return false; // if vector not yet allocated, then not initialized
+ int vectorIndex;
+ if ((vectorIndex = (position / BitCacheSize) - 1) >= extraDefiniteInits.length)
+ return false; // if not enough room in vector, then not initialized
+ return ((extraDefiniteInits[vectorIndex]) & (1L << (position % BitCacheSize))) != 0;
}
- // use extra vector
- if (extraPotentialInits == null)
- return false; // if vector not yet allocated, then not initialized
- int vectorIndex;
- if ((vectorIndex = (position / BitCacheSize) - 1) >= extraPotentialInits.length)
- return false; // if not enough room in vector, then not initialized
- return ((extraPotentialInits[vectorIndex]) & (1L << (position % BitCacheSize))) != 0;
-}
-/**
- * Check status of definite assignment for a field.
- */
-final public boolean isPotentiallyAssigned(FieldBinding field) {
- // We do not want to complain in unreachable code
- if ((this == DeadEnd) || (this.isFakeReachable))
- return false;
- return isPotentiallyAssigned(field.id);
-}
-/**
- * Check status of potential assignment for a local.
- */
-final public boolean isPotentiallyAssigned(LocalVariableBinding local) {
- // We do not want to complain in unreachable code
- if ((this == DeadEnd) || (this.isFakeReachable))
- return false;
- if (local.isArgument) {
- return true;
+
+ /**
+ * Check status of definite assignment for a field.
+ */
+ final public boolean isDefinitelyAssigned(FieldBinding field) {
+
+ // Dependant of CodeStream.isDefinitelyAssigned(..)
+ // We do not want to complain in unreachable code
+ if ((this.reachMode & UNREACHABLE) != 0)
+ return true;
+ return isDefinitelyAssigned(field.id);
}
- return isPotentiallyAssigned(local.id + maxFieldCount);
-}
-/**
- * Record a definite assignment at a given position.
- * It deals with the dual representation of the InitializationInfo2:
- * bits for the first 64 entries, then an array of booleans.
- */
-final private void markAsDefinitelyAssigned(int position) {
- if (this != DeadEnd) {
-
- // position is zero-based
+
+ /**
+ * Check status of definite assignment for a local.
+ */
+ final public boolean isDefinitelyAssigned(LocalVariableBinding local) {
+
+ // Dependant of CodeStream.isDefinitelyAssigned(..)
+ // We do not want to complain in unreachable code
+ if ((this.reachMode & UNREACHABLE) != 0)
+ return true;
+ if (local.isArgument) {
+ return true;
+ }
+ // final constants are inlined, and thus considered as always initialized
+ if (local.constant != Constant.NotAConstant) {
+ return true;
+ }
+ return isDefinitelyAssigned(local.id + maxFieldCount);
+ }
+
+ public boolean isReachable() {
+
+ return this.reachMode == REACHABLE;
+ }
+
+ /**
+ * Check status of potential assignment at a given position.
+ * It deals with the dual representation of the InitializationInfo3:
+ * bits for the first 64 entries, then an array of booleans.
+ */
+ final private boolean isPotentiallyAssigned(int position) {
+
+ // id is zero-based
if (position < BitCacheSize) {
// use bits
- long mask;
- definiteInits |= (mask = 1L << position);
- potentialInits |= mask;
- } else {
- // use extra vector
- int vectorIndex = (position / BitCacheSize) - 1;
- if (extraDefiniteInits == null) {
- int length;
- extraDefiniteInits = new long[length = vectorIndex + 1];
- extraPotentialInits = new long[length];
+ return (potentialInits & (1L << position)) != 0;
+ }
+ // use extra vector
+ if (extraPotentialInits == null)
+ return false; // if vector not yet allocated, then not initialized
+ int vectorIndex;
+ if ((vectorIndex = (position / BitCacheSize) - 1) >= extraPotentialInits.length)
+ return false; // if not enough room in vector, then not initialized
+ return ((extraPotentialInits[vectorIndex]) & (1L << (position % BitCacheSize))) != 0;
+ }
+
+ /**
+ * Check status of definite assignment for a field.
+ */
+ final public boolean isPotentiallyAssigned(FieldBinding field) {
+
+ return isPotentiallyAssigned(field.id);
+ }
+
+ /**
+ * Check status of potential assignment for a local.
+ */
+ final public boolean isPotentiallyAssigned(LocalVariableBinding local) {
+
+ if (local.isArgument) {
+ return true;
+ }
+ // final constants are inlined, and thus considered as always initialized
+ if (local.constant != Constant.NotAConstant) {
+ return true;
+ }
+ return isPotentiallyAssigned(local.id + maxFieldCount);
+ }
+
+ /**
+ * Record a definite assignment at a given position.
+ * It deals with the dual representation of the InitializationInfo2:
+ * bits for the first 64 entries, then an array of booleans.
+ */
+ final private void markAsDefinitelyAssigned(int position) {
+
+ if (this != DEAD_END) {
+
+ // position is zero-based
+ if (position < BitCacheSize) {
+ // use bits
+ long mask;
+ definiteInits |= (mask = 1L << position);
+ potentialInits |= mask;
} else {
- int oldLength; // might need to grow the arrays
- if (vectorIndex >= (oldLength = extraDefiniteInits.length)) {
- System.arraycopy(extraDefiniteInits, 0, (extraDefiniteInits = new long[vectorIndex + 1]), 0, oldLength);
- System.arraycopy(extraPotentialInits, 0, (extraPotentialInits = new long[vectorIndex + 1]), 0, oldLength);
+ // use extra vector
+ int vectorIndex = (position / BitCacheSize) - 1;
+ if (extraDefiniteInits == null) {
+ int length;
+ extraDefiniteInits = new long[length = vectorIndex + 1];
+ extraPotentialInits = new long[length];
+ } else {
+ int oldLength; // might need to grow the arrays
+ if (vectorIndex >= (oldLength = extraDefiniteInits.length)) {
+ System.arraycopy(extraDefiniteInits, 0, (extraDefiniteInits = new long[vectorIndex + 1]), 0, oldLength);
+ System.arraycopy(extraPotentialInits, 0, (extraPotentialInits = new long[vectorIndex + 1]), 0, oldLength);
+ }
}
+ long mask;
+ extraDefiniteInits[vectorIndex] |= (mask = 1L << (position % BitCacheSize));
+ extraPotentialInits[vectorIndex] |= mask;
}
- long mask;
- extraDefiniteInits[vectorIndex] |= (mask = 1L << (position % BitCacheSize));
- extraPotentialInits[vectorIndex] |= mask;
}
}
-}
-/**
- * Record a field got definitely assigned.
- */
-public void markAsDefinitelyAssigned(FieldBinding field) {
- if (this != DeadEnd)
- markAsDefinitelyAssigned(field.id);
-}
-/**
- * Record a local got definitely assigned.
- */
-public void markAsDefinitelyAssigned(LocalVariableBinding local) {
- if (this != DeadEnd)
- markAsDefinitelyAssigned(local.id + maxFieldCount);
-}
-/**
- * Clear initialization information at a given position.
- * It deals with the dual representation of the InitializationInfo2:
- * bits for the first 64 entries, then an array of booleans.
- */
-final private void markAsDefinitelyNotAssigned(int position) {
- if (this != DeadEnd) {
-
- // position is zero-based
- if (position < BitCacheSize) {
- // use bits
- long mask;
- definiteInits &= ~(mask = 1L << position);
- potentialInits &= ~mask;
- } else {
- // use extra vector
- int vectorIndex = (position / BitCacheSize) - 1;
- if (extraDefiniteInits == null) {
- return; // nothing to do, it was not yet set
+
+ /**
+ * Record a field got definitely assigned.
+ */
+ public void markAsDefinitelyAssigned(FieldBinding field) {
+ if (this != DEAD_END)
+ markAsDefinitelyAssigned(field.id);
+ }
+
+ /**
+ * Record a local got definitely assigned.
+ */
+ public void markAsDefinitelyAssigned(LocalVariableBinding local) {
+ if (this != DEAD_END)
+ markAsDefinitelyAssigned(local.id + maxFieldCount);
+ }
+
+ /**
+ * Clear initialization information at a given position.
+ * It deals with the dual representation of the InitializationInfo2:
+ * bits for the first 64 entries, then an array of booleans.
+ */
+ final private void markAsDefinitelyNotAssigned(int position) {
+ if (this != DEAD_END) {
+
+ // position is zero-based
+ if (position < BitCacheSize) {
+ // use bits
+ long mask;
+ definiteInits &= ~(mask = 1L << position);
+ potentialInits &= ~mask;
} else {
- // might need to grow the arrays
- if (vectorIndex >= extraDefiniteInits.length) {
+ // use extra vector
+ int vectorIndex = (position / BitCacheSize) - 1;
+ if (extraDefiniteInits == null) {
return; // nothing to do, it was not yet set
+ } else {
+ // might need to grow the arrays
+ if (vectorIndex >= extraDefiniteInits.length) {
+ return; // nothing to do, it was not yet set
+ }
}
+ long mask;
+ extraDefiniteInits[vectorIndex] &= ~(mask = 1L << (position % BitCacheSize));
+ extraPotentialInits[vectorIndex] &= ~mask;
}
- long mask;
- extraDefiniteInits[vectorIndex] &= ~(mask = 1L << (position % BitCacheSize));
- extraPotentialInits[vectorIndex] &= ~mask;
}
}
-}
-/**
- * Clear the initialization info for a field
- */
-public void markAsDefinitelyNotAssigned(FieldBinding field) {
- if (this != DeadEnd)
- markAsDefinitelyNotAssigned(field.id);
-}
-/**
- * Clear the initialization info for a local variable
- */
-
-public void markAsDefinitelyNotAssigned(LocalVariableBinding local) {
- if (this != DeadEnd)
- markAsDefinitelyNotAssigned(local.id + maxFieldCount);
-}
-public FlowInfo markAsFakeReachable(boolean isFakeReachable) {
- this.isFakeReachable = isFakeReachable;
- return this;
-}
-public UnconditionalFlowInfo mergedWith(UnconditionalFlowInfo otherInits) {
- // updates the receiver with:
- // - intersection of definitely assigned variables,
- // - union of potentially set ones
-
- if (this == DeadEnd)
- return otherInits;
- if (otherInits == DeadEnd)
- return this;
-
- // if one branch is not fake reachable, then the merged one is reachable
- if (!otherInits.isFakeReachable())
- markAsFakeReachable(false);
-
- // intersection of definitely assigned variables,
- definiteInits &= otherInits.definiteInits;
- // union of potentially set ones
- potentialInits |= otherInits.potentialInits;
-
- // treating extra storage
- if (extraDefiniteInits != null) {
- if (otherInits.extraDefiniteInits != null) {
- // both sides have extra storage
- int i = 0, length, otherLength;
- if ((length = extraDefiniteInits.length) < (otherLength = otherInits.extraDefiniteInits.length)) {
- // current storage is shorter -> grow current (could maybe reuse otherInits extra storage?)
- System.arraycopy(extraDefiniteInits, 0, (extraDefiniteInits = new long[otherLength]), 0, length);
- System.arraycopy(extraPotentialInits, 0, (extraPotentialInits = new long[otherLength]), 0, length);
- while (i < length) {
- extraDefiniteInits[i] &= otherInits.extraDefiniteInits[i];
- extraPotentialInits[i] |= otherInits.extraPotentialInits[i++];
- }
- while (i < otherLength) {
- extraPotentialInits[i] = otherInits.extraPotentialInits[i++];
- }
+
+ /**
+ * Clear the initialization info for a field
+ */
+ public void markAsDefinitelyNotAssigned(FieldBinding field) {
+
+ if (this != DEAD_END)
+ markAsDefinitelyNotAssigned(field.id);
+ }
+
+ /**
+ * Clear the initialization info for a local variable
+ */
+
+ public void markAsDefinitelyNotAssigned(LocalVariableBinding local) {
+
+ if (this != DEAD_END)
+ markAsDefinitelyNotAssigned(local.id + maxFieldCount);
+ }
+
+ /**
+ * Returns the receiver updated in the following way: <ul>
+ * <li> intersection of definitely assigned variables,
+ * <li> union of potentially assigned variables.
+ * </ul>
+ */
+ public UnconditionalFlowInfo mergedWith(UnconditionalFlowInfo otherInits) {
+
+ if (this == DEAD_END) return otherInits;
+ if (otherInits == DEAD_END) return this;
+
+ if ((this.reachMode & UNREACHABLE) != (otherInits.reachMode & UNREACHABLE)){
+ if ((this.reachMode & UNREACHABLE) != 0){
+ return otherInits;
} else {
- // current storage is longer
- while (i < otherLength) {
- extraDefiniteInits[i] &= otherInits.extraDefiniteInits[i];
- extraPotentialInits[i] |= otherInits.extraPotentialInits[i++];
+ return this;
+ }
+ }
+
+ // if one branch is not fake reachable, then the merged one is reachable
+ this.reachMode &= otherInits.reachMode;
+
+ // intersection of definitely assigned variables,
+ this.definiteInits &= otherInits.definiteInits;
+ // union of potentially set ones
+ this.potentialInits |= otherInits.potentialInits;
+
+ // treating extra storage
+ if (this.extraDefiniteInits != null) {
+ if (otherInits.extraDefiniteInits != null) {
+ // both sides have extra storage
+ int i = 0, length, otherLength;
+ if ((length = this.extraDefiniteInits.length) < (otherLength = otherInits.extraDefiniteInits.length)) {
+ // current storage is shorter -> grow current (could maybe reuse otherInits extra storage?)
+ System.arraycopy(this.extraDefiniteInits, 0, (this.extraDefiniteInits = new long[otherLength]), 0, length);
+ System.arraycopy(this.extraPotentialInits, 0, (this.extraPotentialInits = new long[otherLength]), 0, length);
+ while (i < length) {
+ this.extraDefiniteInits[i] &= otherInits.extraDefiniteInits[i];
+ this.extraPotentialInits[i] |= otherInits.extraPotentialInits[i++];
+ }
+ while (i < otherLength) {
+ this.extraPotentialInits[i] = otherInits.extraPotentialInits[i++];
+ }
+ } else {
+ // current storage is longer
+ while (i < otherLength) {
+ this.extraDefiniteInits[i] &= otherInits.extraDefiniteInits[i];
+ this.extraPotentialInits[i] |= otherInits.extraPotentialInits[i++];
+ }
+ while (i < length)
+ this.extraDefiniteInits[i++] = 0;
}
+ } else {
+ // no extra storage on otherInits
+ int i = 0, length = this.extraDefiniteInits.length;
while (i < length)
- extraDefiniteInits[i++] = 0;
+ this.extraDefiniteInits[i++] = 0;
}
- } else {
- // no extra storage on otherInits
- int i = 0, length = extraDefiniteInits.length;
- while (i < length)
- extraDefiniteInits[i++] = 0;
+ } else
+ if (otherInits.extraDefiniteInits != null) {
+ // no storage here, but other has extra storage.
+ int otherLength;
+ this.extraDefiniteInits = new long[otherLength = otherInits.extraDefiniteInits.length];
+ System.arraycopy(otherInits.extraPotentialInits, 0, (this.extraPotentialInits = new long[otherLength]), 0, otherLength);
+ }
+ return this;
+ }
+
+ /*
+ * Answer the total number of fields in enclosing types of a given type
+ */
+ static int numberOfEnclosingFields(ReferenceBinding type){
+
+ int count = 0;
+ type = type.enclosingType();
+ while(type != null) {
+ count += type.fieldCount();
+ type = type.enclosingType();
}
- } else
- if (otherInits.extraDefiniteInits != null) {
- // no storage here, but other has extra storage.
- int otherLength;
- extraDefiniteInits = new long[otherLength = otherInits.extraDefiniteInits.length];
- System.arraycopy(otherInits.extraPotentialInits, 0, (extraPotentialInits = new long[otherLength]), 0, otherLength);
+ return count;
+ }
+
+ public int reachMode(){
+ return this.reachMode;
+ }
+
+ public FlowInfo setReachMode(int reachMode) {
+
+ if (this == DEAD_END) return this; // cannot modify DEAD_END
+
+ // reset optional inits when becoming unreachable
+ if ((this.reachMode & UNREACHABLE) == 0 && (reachMode & UNREACHABLE) != 0) {
+ this.potentialInits = 0;
+ if (this.extraPotentialInits != null){
+ for (int i = 0, length = this.extraPotentialInits.length; i < length; i++){
+ this.extraPotentialInits[i] = 0;
+ }
+ }
+ }
+ this.reachMode = reachMode;
+
+ return this;
+ }
+
+ public String toString(){
+
+ if (this == DEAD_END){
+ return "FlowInfo.DEAD_END"; //$NON-NLS-1$
}
- return this;
-}
-/*
- * Answer the total number of fields in enclosing types of a given type
- */
-static int numberOfEnclosingFields(ReferenceBinding type){
- int count = 0;
- type = type.enclosingType();
- while(type != null) {
- count += type.fieldCount();
- type = type.enclosingType();
+ return "FlowInfo<def: "+ this.definiteInits //$NON-NLS-1$
+ +", pot: " + this.potentialInits //$NON-NLS-1$
+ + ", reachable:" + ((this.reachMode & UNREACHABLE) == 0) //$NON-NLS-1$
+ +">"; //$NON-NLS-1$
}
- return count;
-}
-public String toString(){
- if (this == DeadEnd){
- return "FlowInfo.DeadEnd"; //$NON-NLS-1$
+
+ public UnconditionalFlowInfo unconditionalInits() {
+
+ // also see conditional inits, where it requests them to merge
+ return this;
}
- return "FlowInfo<def: "+ definiteInits +", pot: " + potentialInits + ">"; //$NON-NLS-1$ //$NON-NLS-3$ //$NON-NLS-2$
-}
-public UnconditionalFlowInfo unconditionalInits() {
- // also see conditional inits, where it requests them to merge
- return this;
-}
}