package net.sourceforge.phpdt.internal.compiler.flow;
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;
+
public long potentialInits;
+
public long extraDefiniteInits[];
+
public long extraPotentialInits[];
-
+
public int reachMode = REACHABLE; // by default
public int maxFieldCount;
-
+
// Constants
public static final int BitCacheSize = 64; // 64 bits in a long.
if (this == DEAD_END)
return this;
- UnconditionalFlowInfo otherInits = inits.unconditionalInits();
+ UnconditionalFlowInfo otherInits = inits.unconditionalInits();
if (otherInits == DEAD_END)
return this;
-
- // union of definitely assigned variables,
+
+ // 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);
+ // 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++];
} 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);
- }
+ } 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;
}
// unions of both sets of initialization - used for try/finally
public FlowInfo addPotentialInitializationsFrom(FlowInfo inits) {
-
- if (this == DEAD_END){
+
+ if (this == DEAD_END) {
return this;
}
UnconditionalFlowInfo otherInits = inits.unconditionalInits();
- if (otherInits == DEAD_END){
+ 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);
+ // 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++];
}
}
}
}
- } 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);
- }
+ } 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;
}
// 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
- }
- return false;
- }
-
+ // 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
+ // }
+ // 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);
- };
+ 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(){
-
+
+ public UnconditionalFlowInfo discardFieldInitializations() {
+
int limit = this.maxFieldCount;
-
+
if (limit < BitCacheSize) {
- long mask = (1L << limit)-1;
+ long mask = (1L << limit) - 1;
this.definiteInits &= ~mask;
this.potentialInits &= ~mask;
return this;
- }
+ }
this.definiteInits = 0;
this.potentialInits = 0;
this.extraDefiniteInits[i] = 0L;
this.extraPotentialInits[i] = 0L;
}
- long mask = (1L << (limit % BitCacheSize))-1;
+ long mask = (1L << (limit % BitCacheSize)) - 1;
this.extraDefiniteInits[vectorIndex] &= ~mask;
this.extraPotentialInits[vectorIndex] &= ~mask;
return this;
}
- public UnconditionalFlowInfo discardNonFieldInitializations(){
-
+ public UnconditionalFlowInfo discardNonFieldInitializations() {
+
int limit = this.maxFieldCount;
-
+
if (limit < BitCacheSize) {
- long mask = (1L << limit)-1;
+ 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
if ((vectorIndex = (limit / BitCacheSize) - 1) >= length) {
return this; // not enough room yet
}
- long mask = (1L << (limit % BitCacheSize))-1;
+ long mask = (1L << (limit % BitCacheSize)) - 1;
this.extraDefiniteInits[vectorIndex] &= mask;
this.extraPotentialInits[vectorIndex] &= mask;
- for (int i = vectorIndex+1; i < length; i++) {
+ for (int i = vectorIndex + 1; i < length; i++) {
this.extraDefiniteInits[i] = 0L;
this.extraPotentialInits[i] = 0L;
}
return this;
}
-
+
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.
+ * 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 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 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.reachMode & UNREACHABLE) != 0)
+ if ((this.reachMode & UNREACHABLE) != 0)
return true;
- return isDefinitelyAssigned(field.id);
+ 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.reachMode & UNREACHABLE) != 0)
if (local.isArgument) {
return true;
}
- // final constants are inlined, and thus considered as always initialized
+ // 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.
+ * 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 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 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);
+
+ 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
+ // 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.
+ * 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
} 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);
+ System
+ .arraycopy(
+ extraDefiniteInits,
+ 0,
+ (extraDefiniteInits = new long[vectorIndex + 1]),
+ 0, oldLength);
+ System
+ .arraycopy(
+ extraPotentialInits,
+ 0,
+ (extraPotentialInits = new long[vectorIndex + 1]),
+ 0, oldLength);
}
}
long mask;
}
}
}
-
+
/**
* Record a field got definitely assigned.
*/
if (this != DEAD_END)
markAsDefinitelyAssigned(field.id);
}
-
+
/**
* Record a local got definitely assigned.
*/
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.
+ * 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
// use extra vector
int vectorIndex = (position / BitCacheSize) - 1;
if (extraDefiniteInits == null) {
- return; // nothing to do, it was not yet set
+ 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
+ return; // nothing to do, it was not yet set
}
}
long mask;
}
}
}
-
+
/**
* 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,
+ * 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){
+
+ 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 {
return this;
}
}
-
+
// if one branch is not fake reachable, then the merged one is reachable
this.reachMode &= otherInits.reachMode;
-
- // intersection of definitely assigned variables,
+
+ // 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);
+ // 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 < length)
this.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);
- }
+ } 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){
-
+ static int numberOfEnclosingFields(ReferenceBinding type) {
+
int count = 0;
type = type.enclosingType();
- while(type != null) {
+ while (type != null) {
count += type.fieldCount();
type = type.enclosingType();
}
return count;
}
-
- public int reachMode(){
+
+ public int reachMode() {
return this.reachMode;
}
-
+
public FlowInfo setReachMode(int reachMode) {
-
- if (this == DEAD_END) return this; // cannot modify DEAD_END
-
+
+ if (this == DEAD_END)
+ return this; // cannot modify DEAD_END
+
// reset optional inits when becoming unreachable
- if ((this.reachMode & UNREACHABLE) == 0 && (reachMode & UNREACHABLE) != 0) {
+ 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++){
+ 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){
+ public String toString() {
+
+ if (this == DEAD_END) {
return "FlowInfo.DEAD_END"; //$NON-NLS-1$
}
- 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 "FlowInfo<def: " + this.definiteInits //$NON-NLS-1$
+ + ", pot: " + this.potentialInits //$NON-NLS-1$
+ + ", reachable:" + ((this.reachMode & UNREACHABLE) == 0) //$NON-NLS-1$
+ + ">"; //$NON-NLS-1$
}
-
+
public UnconditionalFlowInfo unconditionalInits() {
-
+
// also see conditional inits, where it requests them to merge
return this;
}