diff --git a/ICSharpCode.Decompiler/FlowAnalysis/DefiniteAssignmentVisitor.cs b/ICSharpCode.Decompiler/FlowAnalysis/DefiniteAssignmentVisitor.cs index b71286c32..26dcfdf93 100644 --- a/ICSharpCode.Decompiler/FlowAnalysis/DefiniteAssignmentVisitor.cs +++ b/ICSharpCode.Decompiler/FlowAnalysis/DefiniteAssignmentVisitor.cs @@ -48,7 +48,7 @@ namespace ICSharpCode.Decompiler.FlowAnalysis public State(int variableCount) { this.bits = new BitSet(variableCount); - this.bits.SetAll(); + this.bits.Set(0, variableCount); } private State(BitSet bits) diff --git a/ICSharpCode.Decompiler/Tests/TestRunner.cs b/ICSharpCode.Decompiler/Tests/TestRunner.cs index 036c92723..2ac194e57 100644 --- a/ICSharpCode.Decompiler/Tests/TestRunner.cs +++ b/ICSharpCode.Decompiler/Tests/TestRunner.cs @@ -117,23 +117,27 @@ namespace ICSharpCode.Decompiler.Tests if (result1 != result2 || output1 != output2 || error1 != error2) { Console.WriteLine("Test {0} failed.", testFileName); Console.WriteLine("Decompiled code in {0}:line 1", decompiledCodeFile); - string outputFileName = Path.Combine(Path.GetTempPath(), Path.GetFileNameWithoutExtension(testFileName)); - File.WriteAllText(outputFileName + ".original.out", output1); - File.WriteAllText(outputFileName + ".decompiled.out", output2); - int diffLine = 0; - foreach (var pair in output1.Split('\n').Zip(output2.Split('\n'), Tuple.Create)) { - diffLine++; - if (pair.Item1 != pair.Item2) { - break; + if (error1 == "" && error2 != "") { + Console.WriteLine(error2); + } else { + string outputFileName = Path.Combine(Path.GetTempPath(), Path.GetFileNameWithoutExtension(testFileName)); + File.WriteAllText(outputFileName + ".original.out", output1); + File.WriteAllText(outputFileName + ".decompiled.out", output2); + int diffLine = 0; + 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(output1, output2); + Assert.AreEqual(result1, result2, "Exit codes differ; did the decompiled code crash?"); Assert.AreEqual(error1, error2); + Assert.AreEqual(output1, output2); } finally { if (outputFile != null) outputFile.TempFiles.Delete(); diff --git a/ICSharpCode.Decompiler/Util/BitSet.cs b/ICSharpCode.Decompiler/Util/BitSet.cs index 7f315b1f6..804b75084 100644 --- a/ICSharpCode.Decompiler/Util/BitSet.cs +++ b/ICSharpCode.Decompiler/Util/BitSet.cs @@ -30,70 +30,93 @@ namespace ICSharpCode.Decompiler /// 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; + } /// /// Creates a new bitset, where initially all bits are zero. /// 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() { - return new BitSet((BitArray)bits.Clone()); + return new BitSet((ulong[])words.Clone()); } public bool this[int index] { get { - return bits[index]; + return (words[WordIndex(index)] & (1UL << index)) != 0; } set { - bits[index] = value; + if (value) + Set(index); + else + Clear(index); } } + /// + /// Gets whether at least one bit is set. + /// public bool Any() { - for (int i = 0; i < bits.Length; i++) { - if (bits[i]) + for (int i = 0; i < words.Length; i++) { + if (words[i] != 0) return true; } return false; } + /// + /// Gets whether both bitsets have the same content. + /// + 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; + } + /// /// Gets whether this set is a subset of other, or equal. /// public bool IsSubsetOf(BitSet other) { - for (int i = 0; i < bits.Length; i++) { - if (bits[i] && !other[i]) + for (int i = 0; i < words.Length; i++) { + if ((words[i] & ~other.words[i]) != 0) return false; } return true; } + /// + /// Gets whether this set is a superset of other, or equal. + /// public bool IsSupersetOf(BitSet other) { 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) { return IsSubsetOf(other) && !SetEquals(other); @@ -104,10 +127,13 @@ namespace ICSharpCode.Decompiler return IsSubsetOf(other) && !SetEquals(other); } + /// + /// Gets whether at least one bit is set in both bitsets. + /// public bool Overlaps(BitSet other) { - for (int i = 0; i < bits.Length; i++) { - if (bits[i] && other[i]) + for (int i = 0; i < words.Length; i++) { + if ((words[i] & other.words[i]) != 0) return true; } return false; @@ -115,62 +141,99 @@ namespace ICSharpCode.Decompiler 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) { - 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); + } + + /// + /// Sets all bits i; where startIndex <= i < endIndex. + /// + 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) { - bits[index] = false; + words[WordIndex(index)] &= ~(1UL << index); } + /// + /// Clear all bits i; where startIndex <= i < endIndex. + /// public void Clear(int startIndex, int endIndex) { - for (int i = startIndex; i < endIndex; i++) { - bits[i] = 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; } } - public void SetAll() - { - bits.SetAll(true); - } - - public void Set(int index) - { - bits[index] = true; - } - - public void Set(int startIndex, int endIndex) + public void ClearAll() { - for (int i = startIndex; i < endIndex; i++) { - bits[i] = true; + for (int i = 0; i < words.Length; i++) { + words[i] = 0; } } public void ReplaceWith(BitSet incoming) { - Debug.Assert(bits.Length == incoming.bits.Length); - for (int i = 0; i < bits.Length; i++) { - bits[i] = incoming.bits[i]; - } + Debug.Assert(words.Length == incoming.words.Length); + Array.Copy(incoming.words, 0, words, 0, words.Length); } public override string ToString() { StringBuilder b = new StringBuilder(); b.Append('{'); - for (int i = 0; i < bits.Length; i++) { - if (bits[i]) { + for (int i = 0; i < words.Length; i++) { + if (this[i]) { if (b.Length > 1) b.Append(", "); if (b.Length > 500) {