X-Git-Url: http://git.phpeclipse.com diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/flow/UnconditionalFlowInfo.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/flow/UnconditionalFlowInfo.java index 045e723..685d8cb 100644 --- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/flow/UnconditionalFlowInfo.java +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/flow/UnconditionalFlowInfo.java @@ -1,21 +1,22 @@ /******************************************************************************* - * 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 @@ -23,417 +24,554 @@ import net.sourceforge.phpdt.internal.compiler.lookup.ReferenceBinding; * 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: + */ + 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"; //$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"; //$NON-NLS-1$ //$NON-NLS-3$ //$NON-NLS-2$ -} -public UnconditionalFlowInfo unconditionalInits() { - // also see conditional inits, where it requests them to merge - return this; -} }