Browse Source

Fix #1060: Enter/Exit V2 variation failing to convert to lock()

pull/1087/head
Siegfried Pammer 8 years ago
parent
commit
713f4f1490
  1. 2
      ICSharpCode.Decompiler.Tests/Helpers/RemoveCompilerAttribute.cs
  2. 12
      ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs
  3. 48
      ICSharpCode.Decompiler/IL/Transforms/LockTransform.cs

2
ICSharpCode.Decompiler.Tests/Helpers/RemoveCompilerAttribute.cs

@ -10,7 +10,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -10,7 +10,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
var section = (AttributeSection)attribute.Parent;
SimpleType type = attribute.Type as SimpleType;
if (section.AttributeTarget == "assembly" &&
(type.Identifier == "CompilationRelaxations" || type.Identifier == "RuntimeCompatibility" || type.Identifier == "SecurityPermission" || type.Identifier == "AssemblyVersion" || type.Identifier == "Debuggable"))
(type.Identifier == "CompilationRelaxations" || type.Identifier == "RuntimeCompatibility" || type.Identifier == "SecurityPermission" || type.Identifier == "PermissionSet" || type.Identifier == "AssemblyVersion" || type.Identifier == "Debuggable"))
{
attribute.Remove();
if (section.Attributes.Count == 0)

12
ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs

@ -66,6 +66,16 @@ namespace ICSharpCode.Decompiler.Tests @@ -66,6 +66,16 @@ namespace ICSharpCode.Decompiler.Tests
CompilerOptions.Optimize | CompilerOptions.UseRoslyn
};
static readonly CompilerOptions[] defaultOptionsWithMcs =
{
CompilerOptions.None,
CompilerOptions.Optimize,
CompilerOptions.UseRoslyn,
CompilerOptions.Optimize | CompilerOptions.UseRoslyn,
CompilerOptions.UseMcs,
CompilerOptions.Optimize | CompilerOptions.UseMcs
};
[Test]
public void HelloWorld()
{
@ -124,7 +134,7 @@ namespace ICSharpCode.Decompiler.Tests @@ -124,7 +134,7 @@ namespace ICSharpCode.Decompiler.Tests
}
[Test]
public void Lock([ValueSource("defaultOptions")] CompilerOptions cscOptions)
public void Lock([ValueSource("defaultOptionsWithMcs")] CompilerOptions cscOptions)
{
RunForLibrary(cscOptions: cscOptions);
}

48
ICSharpCode.Decompiler/IL/Transforms/LockTransform.cs

@ -36,7 +36,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -36,7 +36,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms
for (int i = block.Instructions.Count - 1; i >= 0; i--) {
if (!TransformLockRoslyn(block, i))
if (!TransformLockV4(block, i))
TransformLockV2(block, i);
if (!TransformLockV2(block, i))
TransformLockMCS(block, i);
// This happens in some cases:
// Use correct index after transformation.
if (i >= block.Instructions.Count)
@ -44,6 +45,51 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -44,6 +45,51 @@ namespace ICSharpCode.Decompiler.IL.Transforms
}
}
/// <summary>
/// stloc lockObj(lockExpression)
/// call Enter(ldloc lockObj)
/// .try BlockContainer {
/// Block lockBlock (incoming: 1) {
/// call WriteLine()
/// leave lockBlock (nop)
/// }
///
/// } finally BlockContainer {
/// Block exitBlock (incoming: 1) {
/// call Exit(ldloc lockObj)
/// leave exitBlock (nop)
/// }
///
/// }
/// =>
/// .lock (lockExpression) BlockContainer {
/// Block lockBlock (incoming: 1) {
/// call WriteLine()
/// leave lockBlock (nop)
/// }
/// }
/// </summary>
bool TransformLockMCS(Block block, int i)
{
if (i < 2) return false;
if (!(block.Instructions[i] is TryFinally body) || !(block.Instructions[i - 2] is StLoc objectStore) ||
!MatchCall(block.Instructions[i - 1] as Call, "Enter", objectStore.Variable))
return false;
if (!objectStore.Variable.IsSingleDefinition)
return false;
if (!(body.TryBlock is BlockContainer tryContainer) || tryContainer.EntryPoint.Instructions.Count == 0 || tryContainer.EntryPoint.IncomingEdgeCount != 1)
return false;
if (!(body.FinallyBlock is BlockContainer finallyContainer) || !MatchExitBlock(finallyContainer.EntryPoint, null, objectStore.Variable))
return false;
if (objectStore.Variable.LoadCount > 2)
return false;
context.Step("LockTransformMCS", block);
block.Instructions.RemoveAt(i - 1);
block.Instructions.RemoveAt(i - 2);
body.ReplaceWith(new LockInstruction(objectStore.Value, body.TryBlock) { ILRange = objectStore.ILRange });
return true;
}
/// <summary>
/// stloc lockObj(ldloc tempVar)
/// call Enter(ldloc tempVar)

Loading…
Cancel
Save