Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for MCS 2.6.4 pinned region with array variable #3110

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions ICSharpCode.Decompiler.Tests/CorrectnessTestRunner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -336,10 +336,6 @@ public async Task StackTypes([Values(false, true)] bool force32Bit)
[Test]
public async Task UnsafeCode([ValueSource(nameof(defaultOptions))] CompilerOptions options)
{
if (options.HasFlag(CompilerOptions.UseMcs2_6_4))
{
Assert.Ignore("Decompiler bug with mono!");
}
await RunCS(options: options);
}

Expand Down
24 changes: 20 additions & 4 deletions ICSharpCode.Decompiler/IL/ControlFlow/DetectPinnedRegions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -614,14 +614,26 @@ bool CreatePinnedRegion(Block block, StLoc stLoc)
}
Branch br = innerBlock.Instructions.LastOrDefault() as Branch;
if (br != null && br.TargetBlock.IncomingEdgeCount == 1
&& br.TargetContainer == sourceContainer && reachedEdgesPerBlock[br.TargetBlock.ChildIndex] == 0)
&& br.TargetContainer == sourceContainer)
{
// branch that leaves body.
Block unpinBlock = null;
if (reachedEdgesPerBlock[br.TargetBlock.ChildIndex] == 0)
{
unpinBlock = br.TargetBlock;
}
else if (innerBlock.Instructions.Count == 2 &&
innerBlock.Instructions[0].MatchIfInstruction(out _, out var trueInstr) &&
trueInstr is Branch trueBr && trueBr.TargetContainer == sourceContainer &&
reachedEdgesPerBlock[trueBr.TargetBlock.ChildIndex] == 0)
{
unpinBlock = trueBr.TargetBlock;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I understand correctly, the point of this change is to check both outgoing edges for an if block?
Should innerBlock.Instructions.Count == 2 be innerBlock.Instructions.Count >= 2 instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I used == 2 since in my testing there were always two instructions with one being an if and the second being the fallthrough br. If we were to extend the limit to more than 2 instructions I think it would be necessary to check other instructions for potential outgoing edges which would mean additional logic. though in my testing it seems that the current code is enough.

}

// The target block should have an instruction that resets the pin; delete that instruction:
StLoc unpin = br.TargetBlock.Instructions.First() as StLoc;
StLoc unpin = unpinBlock?.Instructions.First() as StLoc;
if (unpin != null && unpin.Variable == stLoc.Variable && IsNullOrZero(unpin.Value))
{
br.TargetBlock.Instructions.RemoveAt(0);
unpinBlock.Instructions.RemoveAt(0);
}
}
// move block into body
Expand Down Expand Up @@ -750,6 +762,10 @@ void ProcessPinnedRegion(PinnedRegion pinnedRegion)
// fixing a string
HandleStringToPointer(pinnedRegion);
}
else if (pinnedRegion.Init is Conv { Kind: ConversionKind.StopGCTracking, Argument: LdElema ldElema })
{
pinnedRegion.Init = ldElema;
}
// Detect nested pinned regions:
BlockContainer body = (BlockContainer)pinnedRegion.Body;
foreach (var block in body.Blocks)
Expand Down