diff options
Diffstat (limited to 'org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/NullInfoRegistry.java')
-rw-r--r-- | org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/NullInfoRegistry.java | 549 |
1 files changed, 0 insertions, 549 deletions
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/NullInfoRegistry.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/NullInfoRegistry.java deleted file mode 100644 index 4005f54c8b..0000000000 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/NullInfoRegistry.java +++ /dev/null @@ -1,549 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2006, 2012 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann <stephan@cs.tu-berlin.de> - Contribution for bug 320170 - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.flow; - -import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; - -/** - * A degenerate form of UnconditionalFlowInfo explicitly meant to capture - * the effects of null related operations within try blocks. Given the fact - * that a try block might exit at any time, a null related operation that - * occurs within such a block mitigates whatever we know about the previous - * null status of involved variables. NullInfoRegistry handles that - * by negating upstream definite information that clashes with what a given - * statement contends about the same variable. It also implements - * {@link #mitigateNullInfoOf(FlowInfo) mitigateNullInfo} so as to elaborate the - * flow info presented in input of finally blocks. - */ -public class NullInfoRegistry extends UnconditionalFlowInfo { - // significant states at this level: - // def. non null, def. null, def. unknown, prot. non null - -// PREMATURE implement coverage and low level tests - -/** - * Make a new null info registry, using an upstream flow info. All definite - * assignments of the upstream are carried forward, since a try block may - * exit before its first statement. - * @param upstream - UnconditionalFlowInfo: the flow info before we enter the - * try block; only definite assignments are considered; this parameter is - * not modified by this constructor - */ -public NullInfoRegistry(UnconditionalFlowInfo upstream) { - this.maxFieldCount = upstream.maxFieldCount; - if ((upstream.tagBits & NULL_FLAG_MASK) != 0) { - long u1, u2, u3, u4, nu2, nu3, nu4; - this.nullBit2 = (u1 = upstream.nullBit1) - & (u2 = upstream.nullBit2) - & (nu3 = ~(u3 = upstream.nullBit3)) - & (nu4 = ~(u4 = upstream.nullBit4)); - this.nullBit3 = u1 & (nu2 = ~u2) & u3 & nu4; - this.nullBit4 = u1 & nu2 &nu3 & u4; - if ((this.nullBit2 | this.nullBit3 | this.nullBit4) != 0) { - this.tagBits |= NULL_FLAG_MASK; - } - if (upstream.extra != null) { - this.extra = new long[extraLength][]; - int length = upstream.extra[2].length; - for (int i = 2; i < extraLength; i++) { - this.extra[i] = new long[length]; - } - for (int i = 0; i < length; i++) { - this.extra[2 + 1][i] = (u1 = upstream.extra[1 + 1][i]) - & (u2 = upstream.extra[2 + 1][i]) - & (nu3 = ~(u3 = upstream.extra[3 + 1][i])) - & (nu4 = ~(u4 = upstream.extra[4 + 1][i])); - this.extra[3 + 1][i] = u1 & (nu2 = ~u2) & u3 & nu4; - this.extra[4 + 1][i] = u1 & nu2 &nu3 & u4; - if ((this.extra[2 + 1][i] | this.extra[3 + 1][i] | this.extra[4 + 1][i]) != 0) { - this.tagBits |= NULL_FLAG_MASK; - } - } - } - } -} - -/** - * Add the information held by another NullInfoRegistry instance to this, - * then return this. - * @param other - NullInfoRegistry: the information to add to this - * @return this, modified to carry the information held by other - */ -public NullInfoRegistry add(NullInfoRegistry other) { - if ((other.tagBits & NULL_FLAG_MASK) == 0) { - return this; - } - this.tagBits |= NULL_FLAG_MASK; - this.nullBit1 |= other.nullBit1; - this.nullBit2 |= other.nullBit2; - this.nullBit3 |= other.nullBit3; - this.nullBit4 |= other.nullBit4; - if (other.extra != null) { - if (this.extra == null) { - this.extra = new long[extraLength][]; - for (int i = 2, length = other.extra[2].length; i < extraLength; i++) { - System.arraycopy(other.extra[i], 0, - (this.extra[i] = new long[length]), 0, length); - } - } else { - int length = this.extra[2].length, otherLength = other.extra[2].length; - if (otherLength > length) { - for (int i = 2; i < extraLength; i++) { - System.arraycopy(this.extra[i], 0, - (this.extra[i] = new long[otherLength]), 0, length); - System.arraycopy(other.extra[i], length, - this.extra[i], length, otherLength - length); - } - } else if (otherLength < length) { - length = otherLength; - } - for (int i = 2; i < extraLength; i++) { - for (int j = 0; j < length; j++) { - this.extra[i][j] |= other.extra[i][j]; - } - } - } - } - return this; -} - -public void markAsComparedEqualToNonNull(LocalVariableBinding local) { - // protected from non-object locals in calling methods - if (this != DEAD_END) { - this.tagBits |= NULL_FLAG_MASK; - int position; - // position is zero-based - if ((position = local.id + this.maxFieldCount) < BitCacheSize) { // use bits - // set protected non null - this.nullBit1 |= (1L << position); - if (COVERAGE_TEST_FLAG) { - if (CoverageTestId == 290) { - this.nullBit1 = 0; - } - } - } - else { - // use extra vector - int vectorIndex = (position / BitCacheSize) - 1; - if (this.extra == null) { - int length = vectorIndex + 1; - this.extra = new long[extraLength][]; - for (int j = 2; j < extraLength; j++) { - this.extra[j] = new long[length]; - } - } - else { - int oldLength; // might need to grow the arrays - if (vectorIndex >= (oldLength = this.extra[2].length)) { - for (int j = 2; j < extraLength; j++) { - System.arraycopy(this.extra[j], 0, - (this.extra[j] = new long[vectorIndex + 1]), 0, - oldLength); - } - } - } - this.extra[2][vectorIndex] |= (1L << (position % BitCacheSize)); - if (COVERAGE_TEST_FLAG) { - if (CoverageTestId == 300) { - this.extra[5][vectorIndex] = ~0; - } - } - } - } -} - -public void markAsDefinitelyNonNull(LocalVariableBinding local) { - // protected from non-object locals in calling methods - if (this != DEAD_END) { - this.tagBits |= NULL_FLAG_MASK; - int position; - // position is zero-based - if ((position = local.id + this.maxFieldCount) < BitCacheSize) { // use bits - // set assigned non null - this.nullBit3 |= (1L << position); - if (COVERAGE_TEST_FLAG) { - if (CoverageTestId == 290) { - this.nullBit1 = 0; - } - } - } - else { - // use extra vector - int vectorIndex = (position / BitCacheSize) - 1; - if (this.extra == null) { - int length = vectorIndex + 1; - this.extra = new long[extraLength][]; - for (int j = 2; j < extraLength; j++) { - this.extra[j] = new long[length]; - } - } - else { - int oldLength; // might need to grow the arrays - if (vectorIndex >= (oldLength = this.extra[2].length)) { - for (int j = 2; j < extraLength; j++) { - System.arraycopy(this.extra[j], 0, - (this.extra[j] = new long[vectorIndex + 1]), 0, - oldLength); - } - } - } - this.extra[4][vectorIndex] |= (1L << (position % BitCacheSize)); - if (COVERAGE_TEST_FLAG) { - if (CoverageTestId == 300) { - this.extra[5][vectorIndex] = ~0; - } - } - } - } -} -// PREMATURE consider ignoring extra 0 to 2 included - means a1 should not be used either -// PREMATURE project protected non null onto something else -public void markAsDefinitelyNull(LocalVariableBinding local) { - // protected from non-object locals in calling methods - if (this != DEAD_END) { - this.tagBits |= NULL_FLAG_MASK; - int position; - // position is zero-based - if ((position = local.id + this.maxFieldCount) < BitCacheSize) { // use bits - // set assigned null - this.nullBit2 |= (1L << position); - if (COVERAGE_TEST_FLAG) { - if (CoverageTestId == 290) { - this.nullBit1 = 0; - } - } - } - else { - // use extra vector - int vectorIndex = (position / BitCacheSize) - 1; - if (this.extra == null) { - int length = vectorIndex + 1; - this.extra = new long[extraLength][]; - for (int j = 2; j < extraLength; j++) { - this.extra[j] = new long[length]; - } - } - else { - int oldLength; // might need to grow the arrays - if (vectorIndex >= (oldLength = this.extra[2].length)) { - for (int j = 2; j < extraLength; j++) { - System.arraycopy(this.extra[j], 0, - (this.extra[j] = new long[vectorIndex + 1]), 0, - oldLength); - } - } - } - this.extra[3][vectorIndex] |= (1L << (position % BitCacheSize)); - if (COVERAGE_TEST_FLAG) { - if (CoverageTestId == 300) { - this.extra[5][vectorIndex] = ~0; - } - } - } - } -} - -public void markAsDefinitelyUnknown(LocalVariableBinding local) { - // protected from non-object locals in calling methods - if (this != DEAD_END) { - this.tagBits |= NULL_FLAG_MASK; - int position; - // position is zero-based - if ((position = local.id + this.maxFieldCount) < BitCacheSize) { // use bits - // set assigned unknown - this.nullBit4 |= (1L << position); - if (COVERAGE_TEST_FLAG) { - if (CoverageTestId == 290) { - this.nullBit1 = 0; - } - } - } - else { - // use extra vector - int vectorIndex = (position / BitCacheSize) - 1; - if (this.extra == null) { - int length = vectorIndex + 1; - this.extra = new long[extraLength][]; - for (int j = 2; j < extraLength; j++) { - this.extra[j] = new long[length]; - } - } - else { - int oldLength; // might need to grow the arrays - if (vectorIndex >= (oldLength = this.extra[2].length)) { - for (int j = 2; j < extraLength; j++) { - System.arraycopy(this.extra[j], 0, - (this.extra[j] = new long[vectorIndex + 1]), 0, - oldLength); - } - } - } - this.extra[5][vectorIndex] |= (1L << (position % BitCacheSize)); - if (COVERAGE_TEST_FLAG) { - if (CoverageTestId == 300) { - this.extra[5][vectorIndex] = ~0; - } - } - } - } -} - -/** - * Mitigate the definite and protected info of flowInfo, depending on what - * this null info registry knows about potential assignments and messages - * sends involving locals. May return flowInfo unchanged, or a modified, - * fresh copy of flowInfo. - * @param flowInfo - FlowInfo: the flow information that this null info - * registry may mitigate - * @return a copy of flowInfo carrying mitigated information, or else - * flowInfo unchanged - */ -public UnconditionalFlowInfo mitigateNullInfoOf(FlowInfo flowInfo) { - if ((this.tagBits & NULL_FLAG_MASK) == 0) { - return flowInfo.unconditionalInits(); - } - long m, m1, nm1, m2, nm2, m3, a2, a3, a4, s1, s2, ns2, s3, ns3, s4, ns4; - boolean newCopy = false; - UnconditionalFlowInfo source = flowInfo.unconditionalInits(); - // clear incompatible protections - m1 = (s1 = source.nullBit1) & (s3 = source.nullBit3) - & (s4 = source.nullBit4) - // prot. non null - & ((a2 = this.nullBit2) | (a4 = this.nullBit4)); - // null or unknown - m2 = s1 & (s2 = this.nullBit2) & (s3 ^ s4) // TODO(stephan): potential typo: should this be "s2 = source.nullBit2"??? - // prot. null - & ((a3 = this.nullBit3) | a4); - // non null or unknown - // clear incompatible assignments - // PREMATURE check effect of protected non null (no NPE on call) - // TODO (maxime) code extensive implementation tests - m3 = s1 & (s2 & (ns3 = ~s3) & (ns4 = ~s4) & (a3 | a4) - | (ns2 = ~s2) & s3 & ns4 & (a2 | a4) - | ns2 & ns3 & s4 & (a2 | a3)); - if ((m = (m1 | m2 | m3)) != 0) { - newCopy = true; - source = source.unconditionalCopy(); - source.nullBit1 &= ~m; - source.nullBit2 &= (nm1 = ~m1) & ((nm2 = ~m2) | a4); - source.nullBit3 &= (nm1 | a2) & nm2; - source.nullBit4 &= nm1 & nm2; - // any variable that is (pot n, pot nn, pot un) at end of try (as captured by *this* NullInfoRegistry) - // has the same uncertainty also for the mitigated case (function result) - // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=320170 - [compiler] [null] Whitebox issues in null analysis - // and org.eclipse.jdt.core.tests.compiler.regression.NullReferenceTest.test0536_try_finally() - long x = ~this.nullBit1 & a2 & a3 & a4; // x is set for all variable ids that have state 0111 (pot n, pot nn, pot un) - if (x != 0) { - // restore state 0111 for all variable ids in x: - source.nullBit1 &= ~x; - source.nullBit2 |= x; - source.nullBit3 |= x; - source.nullBit4 |= x; - } - } - if (this.extra != null && source.extra != null) { - int length = this.extra[2].length, sourceLength = source.extra[0].length; - if (sourceLength < length) { - length = sourceLength; - } - for (int i = 0; i < length; i++) { - m1 = (s1 = source.extra[1 + 1][i]) & (s3 = source.extra[3 + 1][i]) - & (s4 = source.extra[4 + 1][i]) - & ((a2 = this.extra[2 + 1][i]) | (a4 = this.extra[4 + 1][i])); - m2 = s1 & (s2 = this.extra[2 + 1][i]) & (s3 ^ s4) - & ((a3 = this.extra[3 + 1][i]) | a4); - m3 = s1 & (s2 & (ns3 = ~s3) & (ns4 = ~s4) & (a3 | a4) - | (ns2 = ~s2) & s3 & ns4 & (a2 | a4) - | ns2 & ns3 & s4 & (a2 | a3)); - if ((m = (m1 | m2 | m3)) != 0) { - if (! newCopy) { - newCopy = true; - source = source.unconditionalCopy(); - } - source.extra[1 + 1][i] &= ~m; - source.extra[2 + 1][i] &= (nm1 = ~m1) & ((nm2 = ~m2) | a4); - source.extra[3 + 1][i] &= (nm1 | a2) & nm2; - source.extra[4 + 1][i] &= nm1 & nm2; - } - } - } - return source; -} - -public String toString(){ - if (this.extra == null) { - return "NullInfoRegistry<" + this.nullBit1 //$NON-NLS-1$ - + this.nullBit2 + this.nullBit3 + this.nullBit4 - + ">"; //$NON-NLS-1$ - } - else { - String nullS = "NullInfoRegistry<[" + this.nullBit1 //$NON-NLS-1$ - + this.nullBit2 + this.nullBit3 + this.nullBit4; - int i, ceil; - for (i = 0, ceil = this.extra[0].length > 3 ? - 3 : - this.extra[0].length; - i < ceil; i++) { - nullS += "," + this.extra[2][i] //$NON-NLS-1$ - + this.extra[3][i] + this.extra[4][i] + this.extra[5][i]; - } - if (ceil < this.extra[0].length) { - nullS += ",..."; //$NON-NLS-1$ - } - return nullS + "]>"; //$NON-NLS-1$ - } -} - -/** - * Mark a local as potentially having been assigned to an unknown value. - * @param local the local to mark - */ -public void markPotentiallyUnknownBit(LocalVariableBinding local) { - // protected from non-object locals in calling methods - if (this != DEAD_END) { - this.tagBits |= NULL_FLAG_MASK; - int position; - long mask; - if ((position = local.id + this.maxFieldCount) < BitCacheSize) { - // use bits - mask = 1L << position; - isTrue((this.nullBit1 & mask) == 0, "Adding 'unknown' mark in unexpected state"); //$NON-NLS-1$ - this.nullBit4 |= mask; - if (COVERAGE_TEST_FLAG) { - if(CoverageTestId == 46) { - this.nullBit4 = ~0; - } - } - } else { - // use extra vector - int vectorIndex = (position / BitCacheSize) - 1; - if (this.extra == null) { - int length = vectorIndex + 1; - this.extra = new long[extraLength][]; - for (int j = 2; j < extraLength; j++) { - this.extra[j] = new long[length]; - } - } else { - int oldLength; // might need to grow the arrays - if (vectorIndex >= (oldLength = this.extra[2].length)) { - for (int j = 2; j < extraLength; j++) { - System.arraycopy(this.extra[j], 0, - (this.extra[j] = new long[vectorIndex + 1]), 0, - oldLength); - } - } - } - mask = 1L << (position % BitCacheSize); - isTrue((this.extra[2][vectorIndex] & mask) == 0, "Adding 'unknown' mark in unexpected state"); //$NON-NLS-1$ - this.extra[5][vectorIndex] |= mask; - if (COVERAGE_TEST_FLAG) { - if(CoverageTestId == 47) { - this.extra[5][vectorIndex] = ~0; - } - } - } - } -} - -public void markPotentiallyNullBit(LocalVariableBinding local) { - if (this != DEAD_END) { - this.tagBits |= NULL_FLAG_MASK; - int position; - long mask; - if ((position = local.id + this.maxFieldCount) < BitCacheSize) { - // use bits - mask = 1L << position; - isTrue((this.nullBit1 & mask) == 0, "Adding 'potentially null' mark in unexpected state"); //$NON-NLS-1$ - this.nullBit2 |= mask; - if (COVERAGE_TEST_FLAG) { - if(CoverageTestId == 40) { - this.nullBit4 = ~0; - } - } - } else { - // use extra vector - int vectorIndex = (position / BitCacheSize) - 1; - if (this.extra == null) { - int length = vectorIndex + 1; - this.extra = new long[extraLength][]; - for (int j = 2; j < extraLength; j++) { - this.extra[j] = new long[length]; - } - } else { - int oldLength; // might need to grow the arrays - if (vectorIndex >= (oldLength = this.extra[2].length)) { - for (int j = 2; j < extraLength; j++) { - System.arraycopy(this.extra[j], 0, - (this.extra[j] = new long[vectorIndex + 1]), 0, - oldLength); - } - } - } - mask = 1L << (position % BitCacheSize); - this.extra[3][vectorIndex] |= mask; - isTrue((this.extra[2][vectorIndex] & mask) == 0, "Adding 'potentially null' mark in unexpected state"); //$NON-NLS-1$ - if (COVERAGE_TEST_FLAG) { - if(CoverageTestId == 41) { - this.extra[5][vectorIndex] = ~0; - } - } - } - } -} - -public void markPotentiallyNonNullBit(LocalVariableBinding local) { - if (this != DEAD_END) { - this.tagBits |= NULL_FLAG_MASK; - int position; - long mask; - if ((position = local.id + this.maxFieldCount) < BitCacheSize) { - // use bits - mask = 1L << position; - isTrue((this.nullBit1 & mask) == 0, "Adding 'potentially non-null' mark in unexpected state"); //$NON-NLS-1$ - this.nullBit3 |= mask; - if (COVERAGE_TEST_FLAG) { - if(CoverageTestId == 42) { - this.nullBit4 = ~0; - } - } - } else { - // use extra vector - int vectorIndex = (position / BitCacheSize) - 1; - if (this.extra == null) { - int length = vectorIndex + 1; - this.extra = new long[extraLength][]; - for (int j = 2; j < extraLength; j++) { - this.extra[j] = new long[length]; - } - } else { - int oldLength; // might need to grow the arrays - if (vectorIndex >= (oldLength = this.extra[2].length)) { - for (int j = 2; j < extraLength; j++) { - System.arraycopy(this.extra[j], 0, - (this.extra[j] = new long[vectorIndex + 1]), 0, - oldLength); - } - } - } - mask = 1L << (position % BitCacheSize); - isTrue((this.extra[2][vectorIndex] & mask) == 0, "Adding 'potentially non-null' mark in unexpected state"); //$NON-NLS-1$ - this.extra[4][vectorIndex] |= mask; - if (COVERAGE_TEST_FLAG) { - if(CoverageTestId == 43) { - this.extra[5][vectorIndex] = ~0; - } - } - } - } -} -} - |