forked from dotnet/corefxlab
-
Notifications
You must be signed in to change notification settings - Fork 0
/
CilExceptionRegion.cs
113 lines (107 loc) · 4.42 KB
/
CilExceptionRegion.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Cil.Decoder;
namespace System.Reflection.Metadata.Cil
{
public enum HandlerKind
{
Try,
Catch,
Finally,
Filter,
Fault
}
public struct CilExceptionRegion
{
public readonly HandlerKind Kind;
public readonly EntityHandle CatchType;
public readonly int StartOffset;
public readonly int FilterHandlerStart;
public readonly int EndOffset;
internal CilExceptionRegion(HandlerKind kind, EntityHandle catchType, int startOffset, int filterHandlerStart, int endOffset)
{
Kind = kind;
CatchType = catchType;
StartOffset = startOffset;
FilterHandlerStart = filterHandlerStart;
EndOffset = endOffset;
}
/// <summary>
/// This method is used to sort regions from outter to inner (smaller offsets first) so that the regions are dumped
/// with the desired format on msil in case we've got nested regions.
/// </summary>
/// <param name="other">Region to compare to</param>
/// <returns>This method returns -1 if the first is smaller, 0 if they are equal, 1 if the first is greater.</returns>
public int CompareTo(CilExceptionRegion other)
{
int offset1 = StartOffset;
int offset2 = other.StartOffset;
if (offset1 == offset2)
{
return other.EndOffset - EndOffset;
}
return offset1 - offset2;
}
public string ToString(CilTypeProvider provider)
{
switch (Kind)
{
case HandlerKind.Try:
return ".try";
case HandlerKind.Finally:
return "finally";
case HandlerKind.Filter:
return "filter";
case HandlerKind.Fault:
return "fault";
case HandlerKind.Catch:
return string.Format("catch {0}", CilDecoder.DecodeType(CatchType, provider).ToString(false));
default:
throw new InvalidOperationException("Handler Kind doesn't exist.");
}
}
public static IReadOnlyList<CilExceptionRegion> CreateRegions(ImmutableArray<ExceptionRegion> exceptionRegions)
{
if (exceptionRegions.Length == 0)
{
return new CilExceptionRegion[0];
}
var spans = new List<CilExceptionRegion>();
foreach (ExceptionRegion region in exceptionRegions)
{
var startOffset = region.TryOffset;
var endOffset = region.TryOffset + region.TryLength;
var span = new CilExceptionRegion(HandlerKind.Try, region.CatchType, startOffset, -1, endOffset);
if (spans.Count == 0 || spans[spans.Count - 1].CompareTo(span) != 0)
{
spans.Add(span);
continue;
}
}
foreach (ExceptionRegion region in exceptionRegions)
{
var startOffset = region.HandlerOffset;
var endOffset = region.HandlerOffset + region.HandlerLength;
switch (region.Kind)
{
case ExceptionRegionKind.Catch:
spans.Add(new CilExceptionRegion(HandlerKind.Catch, region.CatchType, startOffset, -1, endOffset));
break;
case ExceptionRegionKind.Fault:
spans.Add(new CilExceptionRegion(HandlerKind.Fault, region.CatchType, startOffset, -1, endOffset));
break;
case ExceptionRegionKind.Filter:
spans.Add(new CilExceptionRegion(HandlerKind.Filter, region.CatchType, startOffset, region.FilterOffset, endOffset));
break;
case ExceptionRegionKind.Finally:
spans.Add(new CilExceptionRegion(HandlerKind.Finally, region.CatchType, startOffset, -1, endOffset));
break;
}
}
spans.Sort((CilExceptionRegion region1, CilExceptionRegion region2) => { return region1.CompareTo(region2); });
return spans;
}
}
}