1 | // Licensed to the .NET Foundation under one or more agreements. |
2 | // The .NET Foundation licenses this file to you under the MIT license. |
3 | // See the LICENSE file in the project root for more information. |
4 | |
5 | /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX |
6 | XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX |
7 | XX XX |
8 | XX Exception Handling XX |
9 | XX XX |
10 | XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX |
11 | XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX |
12 | */ |
13 | |
14 | /*****************************************************************************/ |
15 | #ifndef _EH_H_ |
16 | #define _EH_H_ |
17 | |
18 | struct BasicBlock; |
19 | class Compiler; |
20 | |
21 | /*****************************************************************************/ |
22 | |
23 | // The following holds the table of exception handlers. |
24 | |
25 | enum EHHandlerType |
26 | { |
27 | EH_HANDLER_CATCH = 0x1, // Don't use zero (to aid debugging uninitialized memory) |
28 | EH_HANDLER_FILTER, |
29 | EH_HANDLER_FAULT, |
30 | EH_HANDLER_FINALLY, |
31 | EH_HANDLER_FAULT_WAS_FINALLY |
32 | }; |
33 | |
34 | // ToCORINFO_EH_CLAUSE_FLAGS: Convert an internal EHHandlerType to a CORINFO_EH_CLAUSE_FLAGS value |
35 | // to pass back to the VM. |
36 | inline CORINFO_EH_CLAUSE_FLAGS ToCORINFO_EH_CLAUSE_FLAGS(EHHandlerType type) |
37 | { |
38 | switch (type) |
39 | { |
40 | case EH_HANDLER_CATCH: |
41 | return CORINFO_EH_CLAUSE_NONE; |
42 | case EH_HANDLER_FILTER: |
43 | return CORINFO_EH_CLAUSE_FILTER; |
44 | case EH_HANDLER_FAULT: |
45 | case EH_HANDLER_FAULT_WAS_FINALLY: |
46 | return CORINFO_EH_CLAUSE_FAULT; |
47 | case EH_HANDLER_FINALLY: |
48 | return CORINFO_EH_CLAUSE_FINALLY; |
49 | default: |
50 | unreached(); |
51 | } |
52 | } |
53 | |
54 | // ToEHHandlerType: Convert a CORINFO_EH_CLAUSE_FLAGS value obtained from the VM in the EH clause structure |
55 | // to the internal EHHandlerType type. |
56 | inline EHHandlerType ToEHHandlerType(CORINFO_EH_CLAUSE_FLAGS flags) |
57 | { |
58 | if (flags & CORINFO_EH_CLAUSE_FAULT) |
59 | { |
60 | return EH_HANDLER_FAULT; |
61 | } |
62 | else if (flags & CORINFO_EH_CLAUSE_FINALLY) |
63 | { |
64 | return EH_HANDLER_FINALLY; |
65 | } |
66 | else if (flags & CORINFO_EH_CLAUSE_FILTER) |
67 | { |
68 | return EH_HANDLER_FILTER; |
69 | } |
70 | else |
71 | { |
72 | // If it's none of the others, assume it is a try/catch. |
73 | /* XXX Fri 11/7/2008 |
74 | * The VM (and apparently VC) stick in extra bits in the flags field. We ignore any flags |
75 | * we don't know about. |
76 | */ |
77 | return EH_HANDLER_CATCH; |
78 | } |
79 | } |
80 | |
81 | struct EHblkDsc |
82 | { |
83 | BasicBlock* ebdTryBeg; // First block of the try |
84 | BasicBlock* ebdTryLast; // Last block of the try |
85 | BasicBlock* ebdHndBeg; // First block of the handler |
86 | BasicBlock* ebdHndLast; // Last block of the handler |
87 | union { |
88 | BasicBlock* ebdFilter; // First block of filter, if HasFilter() |
89 | unsigned ebdTyp; // Exception type (a class token), otherwise |
90 | }; |
91 | |
92 | EHHandlerType ebdHandlerType; |
93 | |
94 | #if !FEATURE_EH_FUNCLETS |
95 | // How nested is the try/handler within other *handlers* - 0 for outermost clauses, 1 for nesting with a handler, |
96 | // etc. |
97 | unsigned short ebdHandlerNestingLevel; |
98 | #endif // !FEATURE_EH_FUNCLETS |
99 | |
100 | static const unsigned short NO_ENCLOSING_INDEX = USHRT_MAX; |
101 | |
102 | // The index of the enclosing outer try region, NO_ENCLOSING_INDEX if none. |
103 | // Be careful of 'mutually protect' catch and filter clauses (multiple |
104 | // handlers with the same try region): the try regions 'nest' so we set |
105 | // ebdEnclosingTryIndex, but the inner catch is *NOT* nested within the outer catch! |
106 | // That is, if the "inner catch" throws an exception, it won't be caught by |
107 | // the "outer catch" for mutually protect handlers. |
108 | unsigned short ebdEnclosingTryIndex; |
109 | |
110 | // The index of the enclosing outer handler region, NO_ENCLOSING_INDEX if none. |
111 | unsigned short ebdEnclosingHndIndex; |
112 | |
113 | #if FEATURE_EH_FUNCLETS |
114 | |
115 | // After funclets are created, this is the index of corresponding FuncInfoDsc |
116 | // Special case for Filter/Filter-handler: |
117 | // Like the IL the filter funclet immediately preceeds the filter-handler funclet. |
118 | // So this index points to the filter-handler funclet. If you want the filter |
119 | // funclet index, just subtract 1. |
120 | unsigned short ebdFuncIndex; |
121 | |
122 | #endif // FEATURE_EH_FUNCLETS |
123 | |
124 | IL_OFFSET ebdTryBegOffset; // IL offsets of EH try/end regions as they are imported |
125 | IL_OFFSET ebdTryEndOffset; |
126 | IL_OFFSET ebdFilterBegOffset; // only set if HasFilter() |
127 | IL_OFFSET ebdHndBegOffset; |
128 | IL_OFFSET ebdHndEndOffset; |
129 | |
130 | // Returns the last block of the filter. Assumes the EH clause is a try/filter/filter-handler type. |
131 | BasicBlock* BBFilterLast(); |
132 | |
133 | bool HasCatchHandler(); |
134 | bool HasFilter(); |
135 | bool HasFinallyHandler(); |
136 | bool HasFaultHandler(); |
137 | bool HasFinallyOrFaultHandler(); |
138 | |
139 | // Returns the block to which control will flow if an (otherwise-uncaught) exception is raised |
140 | // in the try. This is normally "ebdHndBeg", unless the try region has a filter, in which case that is returned. |
141 | // (This is, in some sense, the "true handler," at least in the sense of control flow. Note |
142 | // that we model the transition from a filter to its handler as normal, non-exceptional control flow.) |
143 | BasicBlock* ExFlowBlock(); |
144 | |
145 | bool InTryRegionILRange(BasicBlock* pBlk); |
146 | bool InFilterRegionILRange(BasicBlock* pBlk); |
147 | bool InHndRegionILRange(BasicBlock* pBlk); |
148 | |
149 | bool InTryRegionBBRange(BasicBlock* pBlk); |
150 | bool InFilterRegionBBRange(BasicBlock* pBlk); |
151 | bool InHndRegionBBRange(BasicBlock* pBlk); |
152 | |
153 | IL_OFFSET ebdTryBegOffs(); |
154 | IL_OFFSET ebdTryEndOffs(); |
155 | IL_OFFSET ebdFilterBegOffs(); |
156 | IL_OFFSET ebdFilterEndOffs(); |
157 | IL_OFFSET ebdHndBegOffs(); |
158 | IL_OFFSET ebdHndEndOffs(); |
159 | |
160 | static bool ebdIsSameILTry(EHblkDsc* h1, EHblkDsc* h2); // Same 'try' region? Compare IL range. |
161 | |
162 | // Return the region index of the most nested EH region that encloses this region, or NO_ENCLOSING_INDEX |
163 | // if this region is directly in the main function body. Set '*inTryRegion' to 'true' if this region is |
164 | // most nested within a 'try' region, or 'false' if this region is most nested within a handler. (Note |
165 | // that filters cannot contain nested EH regions.) |
166 | unsigned ebdGetEnclosingRegionIndex(bool* inTryRegion); |
167 | |
168 | static bool ebdIsSameTry(EHblkDsc* h1, EHblkDsc* h2); // Same 'try' region? Compare begin/last blocks. |
169 | bool ebdIsSameTry(Compiler* comp, unsigned t2); |
170 | bool ebdIsSameTry(BasicBlock* ebdTryBeg, BasicBlock* ebdTryLast); |
171 | |
172 | #ifdef DEBUG |
173 | void DispEntry(unsigned num); // Display this table entry |
174 | #endif // DEBUG |
175 | |
176 | private: |
177 | static bool InBBRange(BasicBlock* pBlk, BasicBlock* pStart, BasicBlock* pEnd); |
178 | }; |
179 | |
180 | /*****************************************************************************/ |
181 | #endif // _EH_H_ |
182 | /*****************************************************************************/ |
183 | |