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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
/*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XX XX
XX Exception Handling XX
XX XX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
*/
/*****************************************************************************/
#ifndef _EH_H_
#define _EH_H_
struct BasicBlock;
class Compiler;
/*****************************************************************************/
// The following holds the table of exception handlers.
enum EHHandlerType
{
EH_HANDLER_CATCH = 0x1, // Don't use zero (to aid debugging uninitialized memory)
EH_HANDLER_FILTER,
EH_HANDLER_FAULT,
EH_HANDLER_FINALLY,
EH_HANDLER_FAULT_WAS_FINALLY
};
// ToCORINFO_EH_CLAUSE_FLAGS: Convert an internal EHHandlerType to a CORINFO_EH_CLAUSE_FLAGS value
// to pass back to the VM.
inline CORINFO_EH_CLAUSE_FLAGS ToCORINFO_EH_CLAUSE_FLAGS(EHHandlerType type)
{
switch (type)
{
case EH_HANDLER_CATCH:
return CORINFO_EH_CLAUSE_NONE;
case EH_HANDLER_FILTER:
return CORINFO_EH_CLAUSE_FILTER;
case EH_HANDLER_FAULT:
case EH_HANDLER_FAULT_WAS_FINALLY:
return CORINFO_EH_CLAUSE_FAULT;
case EH_HANDLER_FINALLY:
return CORINFO_EH_CLAUSE_FINALLY;
default:
unreached();
}
}
// ToEHHandlerType: Convert a CORINFO_EH_CLAUSE_FLAGS value obtained from the VM in the EH clause structure
// to the internal EHHandlerType type.
inline EHHandlerType ToEHHandlerType(CORINFO_EH_CLAUSE_FLAGS flags)
{
if (flags & CORINFO_EH_CLAUSE_FAULT)
{
return EH_HANDLER_FAULT;
}
else if (flags & CORINFO_EH_CLAUSE_FINALLY)
{
return EH_HANDLER_FINALLY;
}
else if (flags & CORINFO_EH_CLAUSE_FILTER)
{
return EH_HANDLER_FILTER;
}
else
{
// If it's none of the others, assume it is a try/catch.
/* XXX Fri 11/7/2008
* The VM (and apparently VC) stick in extra bits in the flags field. We ignore any flags
* we don't know about.
*/
return EH_HANDLER_CATCH;
}
}
struct EHblkDsc
{
BasicBlock* ebdTryBeg; // First block of the try
BasicBlock* ebdTryLast; // Last block of the try
BasicBlock* ebdHndBeg; // First block of the handler
BasicBlock* ebdHndLast; // Last block of the handler
union {
BasicBlock* ebdFilter; // First block of filter, if HasFilter()
unsigned ebdTyp; // Exception type (a class token), otherwise
};
EHHandlerType ebdHandlerType;
#if !FEATURE_EH_FUNCLETS
// How nested is the try/handler within other *handlers* - 0 for outermost clauses, 1 for nesting with a handler,
// etc.
unsigned short ebdHandlerNestingLevel;
#endif // !FEATURE_EH_FUNCLETS
static const unsigned short NO_ENCLOSING_INDEX = USHRT_MAX;
// The index of the enclosing outer try region, NO_ENCLOSING_INDEX if none.
// Be careful of 'mutually protect' catch and filter clauses (multiple
// handlers with the same try region): the try regions 'nest' so we set
// ebdEnclosingTryIndex, but the inner catch is *NOT* nested within the outer catch!
// That is, if the "inner catch" throws an exception, it won't be caught by
// the "outer catch" for mutually protect handlers.
unsigned short ebdEnclosingTryIndex;
// The index of the enclosing outer handler region, NO_ENCLOSING_INDEX if none.
unsigned short ebdEnclosingHndIndex;
#if FEATURE_EH_FUNCLETS
// After funclets are created, this is the index of corresponding FuncInfoDsc
// Special case for Filter/Filter-handler:
// Like the IL the filter funclet immediately preceeds the filter-handler funclet.
// So this index points to the filter-handler funclet. If you want the filter
// funclet index, just subtract 1.
unsigned short ebdFuncIndex;
#endif // FEATURE_EH_FUNCLETS
IL_OFFSET ebdTryBegOffset; // IL offsets of EH try/end regions as they are imported
IL_OFFSET ebdTryEndOffset;
IL_OFFSET ebdFilterBegOffset; // only set if HasFilter()
IL_OFFSET ebdHndBegOffset;
IL_OFFSET ebdHndEndOffset;
// Returns the last block of the filter. Assumes the EH clause is a try/filter/filter-handler type.
BasicBlock* BBFilterLast();
bool HasCatchHandler();
bool HasFilter();
bool HasFinallyHandler();
bool HasFaultHandler();
bool HasFinallyOrFaultHandler();
// Returns the block to which control will flow if an (otherwise-uncaught) exception is raised
// in the try. This is normally "ebdHndBeg", unless the try region has a filter, in which case that is returned.
// (This is, in some sense, the "true handler," at least in the sense of control flow. Note
// that we model the transition from a filter to its handler as normal, non-exceptional control flow.)
BasicBlock* ExFlowBlock();
bool InTryRegionILRange(BasicBlock* pBlk);
bool InFilterRegionILRange(BasicBlock* pBlk);
bool InHndRegionILRange(BasicBlock* pBlk);
bool InTryRegionBBRange(BasicBlock* pBlk);
bool InFilterRegionBBRange(BasicBlock* pBlk);
bool InHndRegionBBRange(BasicBlock* pBlk);
IL_OFFSET ebdTryBegOffs();
IL_OFFSET ebdTryEndOffs();
IL_OFFSET ebdFilterBegOffs();
IL_OFFSET ebdFilterEndOffs();
IL_OFFSET ebdHndBegOffs();
IL_OFFSET ebdHndEndOffs();
static bool ebdIsSameILTry(EHblkDsc* h1, EHblkDsc* h2); // Same 'try' region? Compare IL range.
// Return the region index of the most nested EH region that encloses this region, or NO_ENCLOSING_INDEX
// if this region is directly in the main function body. Set '*inTryRegion' to 'true' if this region is
// most nested within a 'try' region, or 'false' if this region is most nested within a handler. (Note
// that filters cannot contain nested EH regions.)
unsigned ebdGetEnclosingRegionIndex(bool* inTryRegion);
static bool ebdIsSameTry(EHblkDsc* h1, EHblkDsc* h2); // Same 'try' region? Compare begin/last blocks.
bool ebdIsSameTry(Compiler* comp, unsigned t2);
bool ebdIsSameTry(BasicBlock* ebdTryBeg, BasicBlock* ebdTryLast);
#ifdef DEBUG
void DispEntry(unsigned num); // Display this table entry
#endif // DEBUG
private:
static bool InBBRange(BasicBlock* pBlk, BasicBlock* pStart, BasicBlock* pEnd);
};
/*****************************************************************************/
#endif // _EH_H_
/*****************************************************************************/
|