Browse Source

Custom BitSet implementation

pull/728/head
Daniel Grunwald 9 years ago
parent
commit
a06ca0c0be
  1. 2
      ICSharpCode.Decompiler/FlowAnalysis/DefiniteAssignmentVisitor.cs
  2. 28
      ICSharpCode.Decompiler/Tests/TestRunner.cs
  3. 159
      ICSharpCode.Decompiler/Util/BitSet.cs

2
ICSharpCode.Decompiler/FlowAnalysis/DefiniteAssignmentVisitor.cs

@ -48,7 +48,7 @@ namespace ICSharpCode.Decompiler.FlowAnalysis
public State(int variableCount) public State(int variableCount)
{ {
this.bits = new BitSet(variableCount); this.bits = new BitSet(variableCount);
this.bits.SetAll(); this.bits.Set(0, variableCount);
} }
private State(BitSet bits) private State(BitSet bits)

28
ICSharpCode.Decompiler/Tests/TestRunner.cs

@ -117,23 +117,27 @@ namespace ICSharpCode.Decompiler.Tests
if (result1 != result2 || output1 != output2 || error1 != error2) { if (result1 != result2 || output1 != output2 || error1 != error2) {
Console.WriteLine("Test {0} failed.", testFileName); Console.WriteLine("Test {0} failed.", testFileName);
Console.WriteLine("Decompiled code in {0}:line 1", decompiledCodeFile); Console.WriteLine("Decompiled code in {0}:line 1", decompiledCodeFile);
string outputFileName = Path.Combine(Path.GetTempPath(), Path.GetFileNameWithoutExtension(testFileName)); if (error1 == "" && error2 != "") {
File.WriteAllText(outputFileName + ".original.out", output1); Console.WriteLine(error2);
File.WriteAllText(outputFileName + ".decompiled.out", output2); } else {
int diffLine = 0; string outputFileName = Path.Combine(Path.GetTempPath(), Path.GetFileNameWithoutExtension(testFileName));
foreach (var pair in output1.Split('\n').Zip(output2.Split('\n'), Tuple.Create)) { File.WriteAllText(outputFileName + ".original.out", output1);
diffLine++; File.WriteAllText(outputFileName + ".decompiled.out", output2);
if (pair.Item1 != pair.Item2) { int diffLine = 0;
break; foreach (var pair in output1.Split('\n').Zip(output2.Split('\n'), Tuple.Create)) {
diffLine++;
if (pair.Item1 != pair.Item2) {
break;
}
} }
Console.WriteLine("Output: {0}.original.out:line {1}", outputFileName, diffLine);
Console.WriteLine("Output: {0}.decompiled.out:line {1}", outputFileName, diffLine);
} }
Console.WriteLine("Output: {0}.original.out:line {1}", outputFileName, diffLine);
Console.WriteLine("Output: {0}.decompiled.out:line {1}", outputFileName, diffLine);
} }
Assert.AreEqual(result1, result2); Assert.AreEqual(result1, result2, "Exit codes differ; did the decompiled code crash?");
Assert.AreEqual(output1, output2);
Assert.AreEqual(error1, error2); Assert.AreEqual(error1, error2);
Assert.AreEqual(output1, output2);
} finally { } finally {
if (outputFile != null) if (outputFile != null)
outputFile.TempFiles.Delete(); outputFile.TempFiles.Delete();

159
ICSharpCode.Decompiler/Util/BitSet.cs

@ -30,70 +30,93 @@ namespace ICSharpCode.Decompiler
/// </summary> /// </summary>
public class BitSet public class BitSet
{ {
readonly BitArray bits; const int BitsPerWord = 64;
const int Log2BitsPerWord = 6;
const ulong Mask = 0xffffffffffffffffUL;
readonly ulong[] words;
static int WordIndex(int bitIndex)
{
Debug.Assert(bitIndex >= 0);
return bitIndex >> Log2BitsPerWord;
}
/// <summary> /// <summary>
/// Creates a new bitset, where initially all bits are zero. /// Creates a new bitset, where initially all bits are zero.
/// </summary> /// </summary>
public BitSet(int capacity) public BitSet(int capacity)
{ {
this.bits = new BitArray(capacity); this.words = new ulong[Math.Max(1, WordIndex(capacity + BitsPerWord - 1))];
} }
private BitSet(BitArray bits) private BitSet(ulong[] bits)
{ {
this.bits = bits; this.words = bits;
} }
public BitSet Clone() public BitSet Clone()
{ {
return new BitSet((BitArray)bits.Clone()); return new BitSet((ulong[])words.Clone());
} }
public bool this[int index] { public bool this[int index] {
get { get {
return bits[index]; return (words[WordIndex(index)] & (1UL << index)) != 0;
} }
set { set {
bits[index] = value; if (value)
Set(index);
else
Clear(index);
} }
} }
/// <summary>
/// Gets whether at least one bit is set.
/// </summary>
public bool Any() public bool Any()
{ {
for (int i = 0; i < bits.Length; i++) { for (int i = 0; i < words.Length; i++) {
if (bits[i]) if (words[i] != 0)
return true; return true;
} }
return false; return false;
} }
/// <summary>
/// Gets whether both bitsets have the same content.
/// </summary>
public bool SetEquals(BitSet other)
{
Debug.Assert(words.Length == other.words.Length);
for (int i = 0; i < words.Length; i++) {
if (words[i] != other.words[i])
return false;
}
return true;
}
/// <summary> /// <summary>
/// Gets whether this set is a subset of other, or equal. /// Gets whether this set is a subset of other, or equal.
/// </summary> /// </summary>
public bool IsSubsetOf(BitSet other) public bool IsSubsetOf(BitSet other)
{ {
for (int i = 0; i < bits.Length; i++) { for (int i = 0; i < words.Length; i++) {
if (bits[i] && !other[i]) if ((words[i] & ~other.words[i]) != 0)
return false; return false;
} }
return true; return true;
} }
/// <summary>
/// Gets whether this set is a superset of other, or equal.
/// </summary>
public bool IsSupersetOf(BitSet other) public bool IsSupersetOf(BitSet other)
{ {
return other.IsSubsetOf(this); return other.IsSubsetOf(this);
} }
public bool SetEquals(BitSet other)
{
for (int i = 0; i < bits.Length; i++) {
if (bits[i] != other[i])
return false;
}
return true;
}
public bool IsProperSubsetOf(BitSet other) public bool IsProperSubsetOf(BitSet other)
{ {
return IsSubsetOf(other) && !SetEquals(other); return IsSubsetOf(other) && !SetEquals(other);
@ -104,10 +127,13 @@ namespace ICSharpCode.Decompiler
return IsSubsetOf(other) && !SetEquals(other); return IsSubsetOf(other) && !SetEquals(other);
} }
/// <summary>
/// Gets whether at least one bit is set in both bitsets.
/// </summary>
public bool Overlaps(BitSet other) public bool Overlaps(BitSet other)
{ {
for (int i = 0; i < bits.Length; i++) { for (int i = 0; i < words.Length; i++) {
if (bits[i] && other[i]) if ((words[i] & other.words[i]) != 0)
return true; return true;
} }
return false; return false;
@ -115,62 +141,99 @@ namespace ICSharpCode.Decompiler
public void UnionWith(BitSet other) public void UnionWith(BitSet other)
{ {
bits.Or(other.bits); Debug.Assert(words.Length == other.words.Length);
for (int i = 0; i < words.Length; i++) {
words[i] |= other.words[i];
}
} }
public void IntersectWith(BitSet other) public void IntersectWith(BitSet other)
{ {
bits.And(other.bits); for (int i = 0; i < words.Length; i++) {
words[i] &= other.words[i];
}
} }
public void ClearAll() public void Set(int index)
{
words[WordIndex(index)] |= (1UL << index);
}
/// <summary>
/// Sets all bits i; where startIndex &lt;= i &lt; endIndex.
/// </summary>
public void Set(int startIndex, int endIndex)
{ {
bits.SetAll(false); Debug.Assert(startIndex <= endIndex);
if (startIndex >= endIndex) {
return;
}
int startWordIndex = WordIndex(startIndex);
int endWordIndex = WordIndex(endIndex - 1);
ulong startMask = Mask << startIndex;
ulong endMask = Mask >> -endIndex; // same as (Mask >> (64 - (endIndex % 64)))
if (startWordIndex == endWordIndex) {
words[startWordIndex] |= (startMask & endMask);
} else {
words[startWordIndex] |= startMask;
for (int i = startWordIndex + 1; i < endWordIndex; i++) {
words[i] = 0;
}
words[endWordIndex] |= endMask;
}
} }
// Note: intentionally no SetAll(), because it would also set the
// extra bits (due to the capacity being rounded up to a full word).
public void Clear(int index) public void Clear(int index)
{ {
bits[index] = false; words[WordIndex(index)] &= ~(1UL << index);
} }
/// <summary>
/// Clear all bits i; where startIndex &lt;= i &lt; endIndex.
/// </summary>
public void Clear(int startIndex, int endIndex) public void Clear(int startIndex, int endIndex)
{ {
for (int i = startIndex; i < endIndex; i++) { Debug.Assert(startIndex <= endIndex);
bits[i] = false; if (startIndex >= endIndex) {
return;
}
int startWordIndex = WordIndex(startIndex);
int endWordIndex = WordIndex(endIndex - 1);
ulong startMask = Mask << startIndex;
ulong endMask = Mask >> -endIndex; // same as (Mask >> (64 - (endIndex % 64)))
if (startWordIndex == endWordIndex) {
words[startWordIndex] &= ~(startMask & endMask);
} else {
words[startWordIndex] &= ~startMask;
for (int i = startWordIndex + 1; i < endWordIndex; i++) {
words[i] = 0;
}
words[endWordIndex] &= ~endMask;
} }
} }
public void SetAll() public void ClearAll()
{
bits.SetAll(true);
}
public void Set(int index)
{
bits[index] = true;
}
public void Set(int startIndex, int endIndex)
{ {
for (int i = startIndex; i < endIndex; i++) { for (int i = 0; i < words.Length; i++) {
bits[i] = true; words[i] = 0;
} }
} }
public void ReplaceWith(BitSet incoming) public void ReplaceWith(BitSet incoming)
{ {
Debug.Assert(bits.Length == incoming.bits.Length); Debug.Assert(words.Length == incoming.words.Length);
for (int i = 0; i < bits.Length; i++) { Array.Copy(incoming.words, 0, words, 0, words.Length);
bits[i] = incoming.bits[i];
}
} }
public override string ToString() public override string ToString()
{ {
StringBuilder b = new StringBuilder(); StringBuilder b = new StringBuilder();
b.Append('{'); b.Append('{');
for (int i = 0; i < bits.Length; i++) { for (int i = 0; i < words.Length; i++) {
if (bits[i]) { if (this[i]) {
if (b.Length > 1) if (b.Length > 1)
b.Append(", "); b.Append(", ");
if (b.Length > 500) { if (b.Length > 500) {

Loading…
Cancel
Save