|
19 | 19 | using System.Collections.Generic;
|
20 | 20 | using System.Diagnostics;
|
21 | 21 | using System.Linq;
|
| 22 | +using System.Runtime.InteropServices.ComTypes; |
22 | 23 |
|
23 | 24 | using ICSharpCode.Decompiler.IL.Transforms;
|
24 | 25 | using ICSharpCode.Decompiler.TypeSystem;
|
@@ -612,18 +613,16 @@ bool CreatePinnedRegion(Block block, StLoc stLoc)
|
612 | 613 | innerBlock = (Block)innerBlock.Clone();
|
613 | 614 | clonedBlocks[i] = innerBlock;
|
614 | 615 | }
|
615 |
| - Branch br = innerBlock.Instructions.LastOrDefault() as Branch; |
616 |
| - if (br != null && br.TargetBlock.IncomingEdgeCount == 1 |
617 |
| - && br.TargetContainer == sourceContainer && reachedEdgesPerBlock[br.TargetBlock.ChildIndex] == 0) |
| 616 | + if (innerBlock.MatchIfAtEndOfBlock(out _, out var trueInst, out var falseInst)) |
618 | 617 | {
|
619 |
| - // branch that leaves body. |
620 |
| - // The target block should have an instruction that resets the pin; delete that instruction: |
621 |
| - StLoc unpin = br.TargetBlock.Instructions.First() as StLoc; |
622 |
| - if (unpin != null && unpin.Variable == stLoc.Variable && IsNullOrZero(unpin.Value)) |
623 |
| - { |
624 |
| - br.TargetBlock.Instructions.RemoveAt(0); |
625 |
| - } |
| 618 | + HandleBranchLeavingPinnedRegion(trueInst, reachedEdgesPerBlock, sourceContainer, stLoc.Variable); |
| 619 | + HandleBranchLeavingPinnedRegion(falseInst, reachedEdgesPerBlock, sourceContainer, stLoc.Variable); |
| 620 | + } |
| 621 | + else |
| 622 | + { |
| 623 | + HandleBranchLeavingPinnedRegion(innerBlock.Instructions.LastOrDefault(), reachedEdgesPerBlock, sourceContainer, stLoc.Variable); |
626 | 624 | }
|
| 625 | + |
627 | 626 | // move block into body
|
628 | 627 | if (sourceContainer.Blocks[i] == entryBlock)
|
629 | 628 | {
|
@@ -698,6 +697,21 @@ bool CreatePinnedRegion(Block block, StLoc stLoc)
|
698 | 697 | return true;
|
699 | 698 | }
|
700 | 699 |
|
| 700 | + static void HandleBranchLeavingPinnedRegion(ILInstruction potentialBranch, int[] reachedEdgesPerBlock, BlockContainer sourceContainer, ILVariable pinnedRegionVar) |
| 701 | + { |
| 702 | + if (potentialBranch is Branch branch && branch.TargetBlock.IncomingEdgeCount == 1 |
| 703 | + && branch.TargetContainer == sourceContainer && reachedEdgesPerBlock[branch.TargetBlock.ChildIndex] == 0) |
| 704 | + { |
| 705 | + // branch that leaves body. |
| 706 | + // The target block should have an instruction that resets the pin; delete that instruction: |
| 707 | + StLoc unpin = branch.TargetBlock.Instructions.First() as StLoc; |
| 708 | + if (unpin != null && unpin.Variable == pinnedRegionVar && IsNullOrZero(unpin.Value)) |
| 709 | + { |
| 710 | + branch.TargetBlock.Instructions.RemoveAt(0); |
| 711 | + } |
| 712 | + } |
| 713 | + } |
| 714 | + |
701 | 715 | static bool IsNullOrZero(ILInstruction inst)
|
702 | 716 | {
|
703 | 717 | while (inst is Conv conv)
|
@@ -750,6 +764,13 @@ void ProcessPinnedRegion(PinnedRegion pinnedRegion)
|
750 | 764 | // fixing a string
|
751 | 765 | HandleStringToPointer(pinnedRegion);
|
752 | 766 | }
|
| 767 | + else if (pinnedRegion.Init is Conv { Kind: ConversionKind.StopGCTracking, Argument: var convArg }) |
| 768 | + { |
| 769 | + // If pinnedRegion.Variable was already a pointer type, the input IL has a StopGCTracking conversion. |
| 770 | + // We can simply remove this conversion, as it is not needed. |
| 771 | + context.Step("Remove StopGCTracking conversion", pinnedRegion); |
| 772 | + pinnedRegion.Init = convArg; |
| 773 | + } |
753 | 774 | // Detect nested pinned regions:
|
754 | 775 | BlockContainer body = (BlockContainer)pinnedRegion.Body;
|
755 | 776 | foreach (var block in body.Blocks)
|
|
0 commit comments