Skip to content

Commit f8d9b3c

Browse files
authored
Port NativeAOT exception handling to CoreCLR (#88034)
* Port NativeAOT exception handling to CoreCLR This change ports NativeAOT exception handling to CoreCLR, resulting in 3.5..4 times speedup in exception handling. Due to time constraints and various complexities, thread abort and debugger support is not completed yet, so this change is enabled only when `DOTNET_EnableNewExceptionHandling` env variable is set. By default, the old way is used. This change supports all OSes and targets we support except of x86 Windows. That may be doable too in the future, but the difference in exception handling on x86 Windows adds quite a lot of complexity into the picture. Notes for the PR: * I have left the `ExceptionHandling.cs` and `StackFrameIterator.cs` in the nativeaot folder to simplify the review. I can move it to some common location after the change is reviewed. Also it was not clear to me where that should be, so advise would be welcome here. * Naming of the native helpers like `RhpCallCatchFunclet` was left the same as in the NativeAOT for now. * There are still some little things I'd like to eventually clean up, like `ExInfo` encapsulation and possibly moving `REGDISPLAY` and `CONTEXT` it uses into the `ExInfo` itself or moving debug members of `StackFrameIterator` and `REGDISPLAY` to the end of those structures so that the `AsmOffsets.cs` can be simplified. It also may be possible to unify the exception handling callback that's used for ObjectiveC to use the managed version. I've tried and there were some ugly complications, so I've left it separated. * There are two bug fixes for bugs unrelated to this PR and a removal of unused parameter in existing code that could be made as separate PRs before this PR. * `ProfilerEnter` and `ProfilerLeave` for the case of `UnmanagedCallersOnly` method were being called in preemptive mode. * NativeAOT code for rethrowing exception was incorrectly calling `DispatchEx` with last argument set to `activeExInfo._idxCurClause` to start at the last clause processed when the rethrown exception was originally thrown instead of starting from the first one again. I have a accidentally came with a simple test that discovered this bug and causes failures in the original NativeAOT too. * Changes in the stackwalk.cpp add support for * Usage of `ExInfo` instead of `ExceptionTracker` * Handling of case when GC runs while finally funclet is on the stack and then again when the code is back in the new exception handling code in managed code before other finally or catch funclet is called. The NativeAOT solves that by disabling GC for the 2nd pass of EH, for this change it would not be reasonable. * Handling the GC reporting when funclet is found while walking the stack. It needs to scan frames of the managed code that handles the exception too, since it contains live references. The old EH way doesn't have this case. * I needed to add `GCFrame::Remove` method that can remove the `GCFrame` from any location in the chain. There is a managed runtime method that calls `GCReporting::Unregister` that was popping it with my changes out of order due to the exception handling code being managed. Fix context initialization after rebase * Remove Rhp prefix from the native helpers * Fix handling of exceptions from JIT The `UNINSTALL_UNWIND_AND_CONTINUE_HANDLER_NO_PROBE` in the `EE_TO_JIT_TRANSITION` needs to rethrow an exception (if any) using native exception handling mechanism instead of calling the new managed exception handling, as the native exception needs to propagate through some native code layers from there. This change adds parameter to the `UNINSTALL_UNWIND_AND_CONTINUE_HANDLER_NO_PROBE` macro to select whether to rethrow the exception as native or to invoke the new managed exception handling. This problem didn't show up until I ran the coreclr tests with tiered compilation disabled. * Update UNINSTALL_UNWIND_AND_CONTINUE_HANDLER usage There were three places where the UNINSTALL_UNWIND_AND_CONTINUE_HANDLER needed to be replaced by UNINSTALL_UNWIND_AND_CONTINUE_HANDLER_NO_PROBE(true). * Rename INSTALL_UNWIND_AND_CONTINUE_HANDLER_NO_PROBE To INSTALL_UNWIND_AND_CONTINUE_HANDLER_EX, as the old name is obsolete
1 parent 445f01d commit f8d9b3c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+2716
-157
lines changed

src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,11 @@
210210
<Compile Include="$(BclSourcesRoot)\System\Runtime\CompilerServices\RuntimeHelpers.CoreCLR.cs" />
211211
<Compile Include="$(BclSourcesRoot)\System\Runtime\ControlledExecution.CoreCLR.cs" />
212212
<Compile Include="$(BclSourcesRoot)\System\Runtime\DependentHandle.cs" />
213+
<Compile Include="$(MSBuildThisFileDirectory)..\nativeaot\Runtime.Base\src\System\Runtime\ExceptionHandling.cs" Condition="('$(Platform)' != 'x86' or '$(TargetsWindows)' != 'true')"/>
214+
<Compile Include="$(MSBuildThisFileDirectory)..\nativeaot\Runtime.Base\src\System\Runtime\ExceptionIDs.cs" Condition="('$(Platform)' != 'x86' or '$(TargetsWindows)' != 'true')"/>
215+
<Compile Include="$(MSBuildThisFileDirectory)..\nativeaot\Runtime.Base\src\System\Runtime\StackFrameIterator.cs" Condition="('$(Platform)' != 'x86' or '$(TargetsWindows)' != 'true')"/>
216+
<Compile Include="$(BclSourcesRoot)\System\Runtime\ExceptionServices\AsmOffsets.cs" Condition="('$(Platform)' != 'x86' or '$(TargetsWindows)' != 'true')"/>
217+
<Compile Include="$(BclSourcesRoot)\System\Runtime\ExceptionServices\InternalCalls.cs" Condition="('$(Platform)' != 'x86' or '$(TargetsWindows)' != 'true')"/>
213218
<Compile Include="$(BclSourcesRoot)\System\Runtime\GCSettings.CoreCLR.cs" />
214219
<Compile Include="$(BclSourcesRoot)\System\Runtime\JitInfo.CoreCLR.cs" />
215220
<Compile Include="$(BclSourcesRoot)\System\Runtime\InteropServices\ComTypes\IEnumerable.cs" />
Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
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+
4+
// NOTE: This file is included also during native runtime compilation by the C++ compiler for verification purposes.
5+
// The static asserts at the end are compiled only when this file is included in native build by c++ compiler. They
6+
// provide compile time verification that all the sizes and offsets match between the managed and native code.
7+
8+
#if !__cplusplus
9+
internal static
10+
#endif
11+
class AsmOffsets
12+
{
13+
14+
// Offsets / sizes that are different in Release / Debug builds
15+
#if DEBUG
16+
// Debug build offsets
17+
#if TARGET_AMD64
18+
#if TARGET_UNIX
19+
public const int SIZEOF__REGDISPLAY = 0x1a90;
20+
public const int OFFSETOF__REGDISPLAY__SP = 0x1a78;
21+
public const int OFFSETOF__REGDISPLAY__ControlPC = 0x1a80;
22+
#else // TARGET_UNIX
23+
public const int SIZEOF__REGDISPLAY = 0xbf0;
24+
public const int OFFSETOF__REGDISPLAY__SP = 0xbd8;
25+
public const int OFFSETOF__REGDISPLAY__ControlPC = 0xbe0;
26+
#endif // TARGET_UNIX
27+
#elif TARGET_ARM64
28+
public const int SIZEOF__REGDISPLAY = 0x940;
29+
public const int OFFSETOF__REGDISPLAY__SP = 0x898;
30+
public const int OFFSETOF__REGDISPLAY__ControlPC = 0x8a0;
31+
#elif TARGET_ARM
32+
public const int SIZEOF__REGDISPLAY = 0x410;
33+
public const int OFFSETOF__REGDISPLAY__SP = 0x3ec;
34+
public const int OFFSETOF__REGDISPLAY__ControlPC = 0x3f0;
35+
#elif TARGET_X86
36+
public const int SIZEOF__REGDISPLAY = 0x5fc;
37+
public const int OFFSETOF__REGDISPLAY__SP = 0x5f0;
38+
public const int OFFSETOF__REGDISPLAY__ControlPC = 0x5f4;
39+
#elif TARGET_RISCV64
40+
public const int SIZEOF__REGDISPLAY = 0x6C0;
41+
public const int OFFSETOF__REGDISPLAY__SP = 0x628;
42+
public const int OFFSETOF__REGDISPLAY__ControlPC = 0x630;
43+
#elif TARGET_LOONGARCH64
44+
public const int SIZEOF__REGDISPLAY = 0x6C0;
45+
public const int OFFSETOF__REGDISPLAY__SP = 0x628;
46+
public const int OFFSETOF__REGDISPLAY__ControlPC = 0x630;
47+
#endif
48+
49+
#if TARGET_64BIT
50+
public const int OFFSETOF__REGDISPLAY__m_pCurrentContext = 0x8;
51+
public const int SIZEOF__StackFrameIterator = 0x370;
52+
public const int OFFSETOF__StackFrameIterator__m_isRuntimeWrappedExceptions = 0x352;
53+
public const int OFFSETOF__StackFrameIterator__m_AdjustedControlPC = 0x368;
54+
#else // TARGET_64BIT
55+
public const int OFFSETOF__REGDISPLAY__m_pCurrentContext = 0x4;
56+
public const int SIZEOF__StackFrameIterator = 0x2d8;
57+
public const int OFFSETOF__StackFrameIterator__m_isRuntimeWrappedExceptions = 0x2c2;
58+
public const int OFFSETOF__StackFrameIterator__m_AdjustedControlPC = 0x2d0;
59+
#endif // TARGET_64BIT
60+
61+
#else // DEBUG
62+
// Release build offsets
63+
#if TARGET_AMD64
64+
#if TARGET_UNIX
65+
public const int SIZEOF__REGDISPLAY = 0x1a80;
66+
public const int OFFSETOF__REGDISPLAY__SP = 0x1a70;
67+
public const int OFFSETOF__REGDISPLAY__ControlPC = 0x1a78;
68+
#else // TARGET_UNIX
69+
public const int SIZEOF__REGDISPLAY = 0xbe0;
70+
public const int OFFSETOF__REGDISPLAY__SP = 0xbd0;
71+
public const int OFFSETOF__REGDISPLAY__ControlPC = 0xbd8;
72+
#endif // TARGET_UNIX
73+
#elif TARGET_ARM64
74+
public const int SIZEOF__REGDISPLAY = 0x930;
75+
public const int OFFSETOF__REGDISPLAY__SP = 0x890;
76+
public const int OFFSETOF__REGDISPLAY__ControlPC = 0x898;
77+
#elif TARGET_ARM
78+
public const int SIZEOF__REGDISPLAY = 0x408;
79+
public const int OFFSETOF__REGDISPLAY__SP = 0x3e8;
80+
public const int OFFSETOF__REGDISPLAY__ControlPC = 0x3ec;
81+
#elif TARGET_X86
82+
public const int SIZEOF__REGDISPLAY = 0x5f8;
83+
public const int OFFSETOF__REGDISPLAY__SP = 0x5ec;
84+
public const int OFFSETOF__REGDISPLAY__ControlPC = 0x5f0;
85+
#elif TARGET_RISCV64
86+
public const int SIZEOF__REGDISPLAY = 0x6B0;
87+
public const int OFFSETOF__REGDISPLAY__SP = 0x620;
88+
public const int OFFSETOF__REGDISPLAY__ControlPC = 0x628;
89+
#elif TARGET_LOONGARCH64
90+
public const int SIZEOF__REGDISPLAY = 0x6B0;
91+
public const int OFFSETOF__REGDISPLAY__SP = 0x620;
92+
public const int OFFSETOF__REGDISPLAY__ControlPC = 0x628;
93+
#endif
94+
95+
#if TARGET_64BIT
96+
public const int OFFSETOF__REGDISPLAY__m_pCurrentContext = 0x8;
97+
public const int SIZEOF__StackFrameIterator = 0x370;
98+
public const int OFFSETOF__StackFrameIterator__m_isRuntimeWrappedExceptions = 0x34a;
99+
public const int OFFSETOF__StackFrameIterator__m_AdjustedControlPC = 0x360;
100+
#else // TARGET_64BIT
101+
public const int OFFSETOF__REGDISPLAY__m_pCurrentContext = 0x4;
102+
public const int SIZEOF__StackFrameIterator = 0x2d0;
103+
public const int OFFSETOF__StackFrameIterator__m_isRuntimeWrappedExceptions = 0x2ba;
104+
public const int OFFSETOF__StackFrameIterator__m_AdjustedControlPC = 0x2c8;
105+
#endif // TARGET_64BIT
106+
107+
#endif // DEBUG
108+
109+
#if TARGET_AMD64
110+
#if TARGET_UNIX
111+
public const int SIZEOF__PAL_LIMITED_CONTEXT = 0xc20;
112+
#else // TARGET_UNIX
113+
public const int SIZEOF__PAL_LIMITED_CONTEXT = 0x4d0;
114+
#endif // TARGET_UNIx
115+
#elif TARGET_ARM64
116+
public const int SIZEOF__PAL_LIMITED_CONTEXT = 0x390;
117+
#elif TARGET_ARM
118+
public const int SIZEOF__PAL_LIMITED_CONTEXT = 0x1a0;
119+
#elif TARGET_X86
120+
public const int SIZEOF__PAL_LIMITED_CONTEXT = 0x2cc;
121+
#elif TARGET_RISCV64
122+
public const int SIZEOF__PAL_LIMITED_CONTEXT = 0x220;
123+
#elif TARGET_LOONGARCH64
124+
public const int SIZEOF__PAL_LIMITED_CONTEXT = 0x220;
125+
#endif
126+
127+
#if TARGET_AMD64
128+
public const int OFFSETOF__PAL_LIMITED_CONTEXT__IP = 0xf8;
129+
public const int OFFSETOF__PAL_LIMITED_CONTEXT__FP = 0xa0;
130+
#elif TARGET_ARM64
131+
public const int OFFSETOF__PAL_LIMITED_CONTEXT__IP = 0x108;
132+
public const int OFFSETOF__PAL_LIMITED_CONTEXT__FP = 0xf0;
133+
#elif TARGET_ARM
134+
public const int OFFSETOF__PAL_LIMITED_CONTEXT__IP = 0x40;
135+
public const int OFFSETOF__PAL_LIMITED_CONTEXT__FP = 0x30;
136+
#elif TARGET_X86
137+
public const int OFFSETOF__PAL_LIMITED_CONTEXT__IP = 0xb8;
138+
public const int OFFSETOF__PAL_LIMITED_CONTEXT__FP = 0xb4;
139+
#elif TARGET_RISCV64
140+
public const int OFFSETOF__PAL_LIMITED_CONTEXT__IP = 0x108;
141+
public const int OFFSETOF__PAL_LIMITED_CONTEXT__FP = 0x48;
142+
#elif TARGET_LOONGARCH64
143+
public const int OFFSETOF__PAL_LIMITED_CONTEXT__IP = 0x108;
144+
public const int OFFSETOF__PAL_LIMITED_CONTEXT__FP = 0x48;
145+
#endif
146+
147+
// Offsets / sizes that are different in 64 / 32 bit mode
148+
149+
#if TARGET_64BIT
150+
public const int SIZEOF__EHEnum = 0x20;
151+
public const int OFFSETOF__StackFrameIterator__m_pRegDisplay = 0x228;
152+
public const int OFFSETOF__ExInfo__m_pPrevExInfo = 0;
153+
public const int OFFSETOF__ExInfo__m_pExContext = 8;
154+
public const int OFFSETOF__ExInfo__m_exception = 0x10;
155+
public const int OFFSETOF__ExInfo__m_kind = 0x18;
156+
public const int OFFSETOF__ExInfo__m_passNumber = 0x19;
157+
public const int OFFSETOF__ExInfo__m_idxCurClause = 0x1c;
158+
public const int OFFSETOF__ExInfo__m_frameIter = 0x20;
159+
public const int OFFSETOF__ExInfo__m_notifyDebuggerSP = OFFSETOF__ExInfo__m_frameIter + SIZEOF__StackFrameIterator;
160+
#else // TARGET_64BIT
161+
public const int SIZEOF__EHEnum = 0x10;
162+
public const int OFFSETOF__StackFrameIterator__m_pRegDisplay = 0x218;
163+
public const int OFFSETOF__ExInfo__m_pPrevExInfo = 0;
164+
public const int OFFSETOF__ExInfo__m_pExContext = 4;
165+
public const int OFFSETOF__ExInfo__m_exception = 8;
166+
public const int OFFSETOF__ExInfo__m_kind = 0xC;
167+
public const int OFFSETOF__ExInfo__m_passNumber = 0xD;
168+
public const int OFFSETOF__ExInfo__m_idxCurClause = 0x10;
169+
public const int OFFSETOF__ExInfo__m_frameIter = 0x18;
170+
public const int OFFSETOF__ExInfo__m_notifyDebuggerSP = OFFSETOF__ExInfo__m_frameIter + SIZEOF__StackFrameIterator;
171+
#endif // TARGET_64BIT
172+
173+
#if __cplusplus
174+
static_assert_no_msg(sizeof(CONTEXT) == AsmOffsets::SIZEOF__PAL_LIMITED_CONTEXT);
175+
#if TARGET_AMD64
176+
static_assert_no_msg(offsetof(CONTEXT, Rip) == AsmOffsets::OFFSETOF__PAL_LIMITED_CONTEXT__IP);
177+
static_assert_no_msg(offsetof(CONTEXT, Rbp) == AsmOffsets::OFFSETOF__PAL_LIMITED_CONTEXT__FP);
178+
#elif TARGET_ARM64
179+
static_assert_no_msg(offsetof(CONTEXT, Pc) == AsmOffsets::OFFSETOF__PAL_LIMITED_CONTEXT__IP);
180+
static_assert_no_msg(offsetof(CONTEXT, Fp) == AsmOffsets::OFFSETOF__PAL_LIMITED_CONTEXT__FP);
181+
#elif TARGET_ARM
182+
static_assert_no_msg(offsetof(CONTEXT, Pc) == AsmOffsets::OFFSETOF__PAL_LIMITED_CONTEXT__IP);
183+
static_assert_no_msg(offsetof(CONTEXT, R11) == AsmOffsets::OFFSETOF__PAL_LIMITED_CONTEXT__FP);
184+
#elif TARGET_X86
185+
static_assert_no_msg(offsetof(CONTEXT, Eip) == AsmOffsets::OFFSETOF__PAL_LIMITED_CONTEXT__IP);
186+
static_assert_no_msg(offsetof(CONTEXT, Ebp) == AsmOffsets::OFFSETOF__PAL_LIMITED_CONTEXT__FP);
187+
#elif TARGET_RISCV64
188+
static_assert_no_msg(offsetof(CONTEXT, Pc) == AsmOffsets::OFFSETOF__PAL_LIMITED_CONTEXT__IP);
189+
static_assert_no_msg(offsetof(CONTEXT, Fp) == AsmOffsets::OFFSETOF__PAL_LIMITED_CONTEXT__FP);
190+
#endif
191+
static_assert_no_msg(sizeof(REGDISPLAY) == AsmOffsets::SIZEOF__REGDISPLAY);
192+
static_assert_no_msg(offsetof(REGDISPLAY, SP) == AsmOffsets::OFFSETOF__REGDISPLAY__SP);
193+
static_assert_no_msg(offsetof(REGDISPLAY, ControlPC) == AsmOffsets::OFFSETOF__REGDISPLAY__ControlPC);
194+
static_assert_no_msg(offsetof(REGDISPLAY, pCurrentContext) == AsmOffsets::OFFSETOF__REGDISPLAY__m_pCurrentContext);
195+
static_assert_no_msg(sizeof(StackFrameIterator) == AsmOffsets::SIZEOF__StackFrameIterator);
196+
static_assert_no_msg(offsetof(StackFrameIterator, m_crawl) + offsetof(CrawlFrame, pRD) == OFFSETOF__StackFrameIterator__m_pRegDisplay);
197+
static_assert_no_msg(offsetof(StackFrameIterator, m_isRuntimeWrappedExceptions) == OFFSETOF__StackFrameIterator__m_isRuntimeWrappedExceptions);
198+
static_assert_no_msg(offsetof(StackFrameIterator, m_AdjustedControlPC) == OFFSETOF__StackFrameIterator__m_AdjustedControlPC);
199+
static_assert_no_msg(sizeof(ExtendedEHClauseEnumerator) == AsmOffsets::SIZEOF__EHEnum);
200+
static_assert_no_msg(offsetof(ExInfo, m_pPrevExInfo) == OFFSETOF__ExInfo__m_pPrevExInfo);
201+
static_assert_no_msg(offsetof(ExInfo, m_pExContext) == OFFSETOF__ExInfo__m_pExContext);
202+
static_assert_no_msg(offsetof(ExInfo, m_exception) == OFFSETOF__ExInfo__m_exception);
203+
static_assert_no_msg(offsetof(ExInfo, m_kind) == OFFSETOF__ExInfo__m_kind);
204+
static_assert_no_msg(offsetof(ExInfo, m_passNumber) == OFFSETOF__ExInfo__m_passNumber);
205+
static_assert_no_msg(offsetof(ExInfo, m_idxCurClause) == OFFSETOF__ExInfo__m_idxCurClause);
206+
static_assert_no_msg(offsetof(ExInfo, m_frameIter) == OFFSETOF__ExInfo__m_frameIter);
207+
static_assert_no_msg(offsetof(ExInfo, m_notifyDebuggerSP) == OFFSETOF__ExInfo__m_notifyDebuggerSP);
208+
#endif
209+
210+
}
211+
#if __cplusplus
212+
;
213+
#endif
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
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+
4+
//
5+
// This is where we group together all the internal calls.
6+
//
7+
8+
using System.Runtime.InteropServices;
9+
using System.Runtime.CompilerServices;
10+
11+
namespace System.Runtime.ExceptionServices
12+
{
13+
internal static partial class InternalCalls
14+
{
15+
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "SfiInit")]
16+
[return: MarshalAs(UnmanagedType.Bool)]
17+
internal static unsafe partial bool RhpSfiInit(ref StackFrameIterator pThis, void* pStackwalkCtx, [MarshalAs(UnmanagedType.Bool)] bool instructionFault);
18+
19+
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "SfiNext")]
20+
[return: MarshalAs(UnmanagedType.Bool)]
21+
internal static unsafe partial bool RhpSfiNext(ref StackFrameIterator pThis, uint* uExCollideClauseIdx, bool* fUnwoundReversePInvoke);
22+
23+
#pragma warning disable CS8500
24+
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "CallCatchFunclet")]
25+
internal static unsafe partial IntPtr RhpCallCatchFunclet(
26+
ObjectHandleOnStack exceptionObj, byte* pHandlerIP, void* pvRegDisplay, EH.ExInfo* exInfo);
27+
28+
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "CallFinallyFunclet")]
29+
internal static unsafe partial void RhpCallFinallyFunclet(byte* pHandlerIP, void* pvRegDisplay, EH.ExInfo* exInfo);
30+
31+
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "CallFilterFunclet")]
32+
[return: MarshalAs(UnmanagedType.Bool)]
33+
internal static unsafe partial bool RhpCallFilterFunclet(
34+
ObjectHandleOnStack exceptionObj, byte* pFilterIP, void* pvRegDisplay);
35+
36+
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "AppendExceptionStackFrame")]
37+
internal static unsafe partial void RhpAppendExceptionStackFrame(ObjectHandleOnStack exceptionObj, IntPtr ip, UIntPtr sp, int flags, EH.ExInfo* exInfo);
38+
#pragma warning restore CS8500
39+
40+
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "EHEnumInitFromStackFrameIterator")]
41+
[return: MarshalAs(UnmanagedType.Bool)]
42+
internal static unsafe partial bool RhpEHEnumInitFromStackFrameIterator(ref StackFrameIterator pFrameIter, byte** pMethodStartAddress, void* pEHEnum);
43+
44+
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "EHEnumNext")]
45+
[return: MarshalAs(UnmanagedType.Bool)]
46+
internal static unsafe partial bool RhpEHEnumNext(void* pEHEnum, void* pEHClause);
47+
}
48+
}

src/coreclr/clr.featuredefines.props

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@
4040
<FeatureObjCMarshal>true</FeatureObjCMarshal>
4141
</PropertyGroup>
4242

43+
<PropertyGroup Condition="!('$(TargetsWindows)' == 'true' AND '$(Platform)' == 'x86')">
44+
<FeatureEHFunclets>true</FeatureEHFunclets>
45+
</PropertyGroup>
46+
4347
<PropertyGroup>
4448
<DefineConstants Condition="'$(FeatureArrayStubAsIL)' == 'true'">$(DefineConstants);FEATURE_ARRAYSTUB_AS_IL</DefineConstants>
4549
<DefineConstants Condition="'$(FeatureMulticastStubAsIL)' == 'true'">$(DefineConstants);FEATURE_MULTICASTSTUB_AS_IL</DefineConstants>
@@ -59,6 +63,7 @@
5963
<DefineConstants Condition="'$(FeatureBasicFreeze)' == 'true'">$(DefineConstants);FEATURE_BASICFREEZE</DefineConstants>
6064
<DefineConstants Condition="'$(FeaturePortableShuffleThunks)' == 'true'">$(DefineConstants);FEATURE_PORTABLE_SHUFFLE_THUNKS</DefineConstants>
6165
<DefineConstants Condition="'$(FeatureICastable)' == 'true'">$(DefineConstants);FEATURE_ICASTABLE</DefineConstants>
66+
<DefineConstants Condition="'$(FeatureEHFunclets)' == 'true'">$(DefineConstants);FEATURE_EH_FUNCLETS</DefineConstants>
6267

6368
<DefineConstants Condition="'$(ProfilingSupportedBuild)' == 'true'">$(DefineConstants);PROFILING_SUPPORTED</DefineConstants>
6469
<DefineConstants Condition="'$(FeatureProfAttach)' == 'true'">$(DefineConstants);FEATURE_PROFAPI_ATTACH_DETACH</DefineConstants>

src/coreclr/debug/daccess/dacdbiimplstackwalk.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,22 @@ BOOL DacDbiInterfaceImpl::UnwindStackWalkFrame(StackWalkHandle pSFIHandle)
261261
// Just continue onto the next managed stack frame.
262262
continue;
263263
}
264+
#ifdef FEATURE_EH_FUNCLETS
265+
else if (g_isNewExceptionHandlingEnabled && pIter->GetFrameState() == StackFrameIterator::SFITER_FRAMELESS_METHOD)
266+
{
267+
// Skip the new exception handling managed code, the debugger clients are not supposed to see them
268+
MethodDesc *pMD = pIter->m_crawl.GetFunction();
269+
PTR_MethodDesc ptrMD = dac_cast<PTR_MethodDesc>(pMD);
270+
271+
// EH.DispatchEx, EH.RhThrowEx, EH.RhThrowHwEx
272+
if (ptrMD->GetMethodTable() == g_pEHClass)
273+
{
274+
continue;
275+
}
276+
277+
fIsAtEndOfStack = FALSE;
278+
}
279+
#endif // FEATURE_EH_FUNCLETS
264280
else
265281
{
266282
fIsAtEndOfStack = FALSE;
@@ -433,6 +449,20 @@ ULONG32 DacDbiInterfaceImpl::GetCountOfInternalFrames(VMPTR_Thread vmThread)
433449
ULONG32 uCount = 0;
434450
while (pFrame != FRAME_TOP)
435451
{
452+
#ifdef FEATURE_EH_FUNCLETS
453+
if (g_isNewExceptionHandlingEnabled && InlinedCallFrame::FrameHasActiveCall(pFrame))
454+
{
455+
// Skip new exception handling helpers
456+
InlinedCallFrame *pInlinedCallFrame = (InlinedCallFrame *)pFrame;
457+
PTR_NDirectMethodDesc pMD = pInlinedCallFrame->m_Datum;
458+
TADDR datum = dac_cast<TADDR>(pMD);
459+
if ((datum & (TADDR)InlinedCallFrameMarker::Mask) == (TADDR)InlinedCallFrameMarker::ExceptionHandlingHelper)
460+
{
461+
pFrame = pFrame->Next();
462+
continue;
463+
}
464+
}
465+
#endif // FEATURE_EH_FUNCLETS
436466
CorDebugInternalFrameType ift = GetInternalFrameType(pFrame);
437467
if (ift != STUBFRAME_NONE)
438468
{
@@ -472,6 +502,20 @@ void DacDbiInterfaceImpl::EnumerateInternalFrames(VMPTR_Thread
472502

473503
while (pFrame != FRAME_TOP)
474504
{
505+
#ifdef FEATURE_EH_FUNCLETS
506+
if (g_isNewExceptionHandlingEnabled && InlinedCallFrame::FrameHasActiveCall(pFrame))
507+
{
508+
// Skip new exception handling helpers
509+
InlinedCallFrame *pInlinedCallFrame = (InlinedCallFrame *)pFrame;
510+
PTR_NDirectMethodDesc pMD = pInlinedCallFrame->m_Datum;
511+
TADDR datum = dac_cast<TADDR>(pMD);
512+
if ((datum & (TADDR)InlinedCallFrameMarker::Mask) == (TADDR)InlinedCallFrameMarker::ExceptionHandlingHelper)
513+
{
514+
pFrame = pFrame->Next();
515+
continue;
516+
}
517+
}
518+
#endif // FEATURE_EH_FUNCLETS
475519
// check if the internal frame is interesting
476520
frameData.stubFrame.frameType = GetInternalFrameType(pFrame);
477521
if (frameData.stubFrame.frameType != STUBFRAME_NONE)

src/coreclr/inc/clrconfigvalues.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,8 @@ RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_legacyCorruptedStateExceptionsPolicy, W("le
259259
CONFIG_DWORD_INFO(INTERNAL_SuppressLostExceptionTypeAssert, W("SuppressLostExceptionTypeAssert"), 0, "")
260260
RETAIL_CONFIG_DWORD_INFO(INTERNAL_UseEntryPointFilter, W("UseEntryPointFilter"), 0, "")
261261
RETAIL_CONFIG_DWORD_INFO(INTERNAL_Corhost_Swallow_Uncaught_Exceptions, W("Corhost_Swallow_Uncaught_Exceptions"), 0, "")
262+
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_EnableNewExceptionHandling, W("EnableNewExceptionHandling"), 0, "Enable new exception handling.");
263+
262264

263265
///
264266
/// Garbage collector

src/coreclr/inc/dacvars.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,11 @@ DEFINE_DACVAR(DWORD, dac__g_debuggerWordTLSIndex, g_debuggerWordTLSIndex)
113113
#endif
114114
DEFINE_DACVAR(DWORD, dac__g_TlsIndex, g_TlsIndex)
115115

116+
#ifdef FEATURE_EH_FUNCLETS
117+
DEFINE_DACVAR(UNKNOWN_POINTER_TYPE, dac__g_pEHClass, ::g_pEHClass)
118+
DEFINE_DACVAR(BOOL, dac__g_isNewExceptionHandlingEnabled, ::g_isNewExceptionHandlingEnabled)
119+
#endif
120+
116121
DEFINE_DACVAR(PTR_SString, SString__s_Empty, SString::s_Empty)
117122

118123
DEFINE_DACVAR(INT32, ArrayBase__s_arrayBoundsZero, ArrayBase::s_arrayBoundsZero)

0 commit comments

Comments
 (0)