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
6XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7XX XX
8XX Exception Handling XX
9XX XX
10XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
11XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
12*/
13
14/*****************************************************************************/
15#ifndef _EH_H_
16#define _EH_H_
17
18struct BasicBlock;
19class Compiler;
20
21/*****************************************************************************/
22
23// The following holds the table of exception handlers.
24
25enum 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.
36inline 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.
56inline 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
81struct 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
176private:
177 static bool InBBRange(BasicBlock* pBlk, BasicBlock* pStart, BasicBlock* pEnd);
178};
179
180/*****************************************************************************/
181#endif // _EH_H_
182/*****************************************************************************/
183