Skip to content

Commit

Permalink
Replace FEATURE_EH_FUNCLETS in JIT with runtime switch (#99191)
Browse files Browse the repository at this point in the history
* Replace FEATURE_EH_FUNCLETS/FEATURE_EH_CALLFINALLY_THUNKS in JIT with runtime switch

* Cache Native AOT ABI check to see if TP improves

---------

Co-authored-by: Bruce Forstall <brucefo@microsoft.com>
  • Loading branch information
filipnavara and BruceForstall committed Apr 5, 2024
1 parent e1f5378 commit 41b1091
Show file tree
Hide file tree
Showing 50 changed files with 1,104 additions and 1,311 deletions.
6 changes: 4 additions & 2 deletions docs/design/coreclr/botr/clr-abi.md
Original file line number Diff line number Diff line change
Expand Up @@ -177,11 +177,13 @@ This section describes the conventions the JIT needs to follow when generating c

## Funclets

For all platforms except Windows/x86, all managed EH handlers (finally, fault, filter, filter-handler, and catch) are extracted into their own 'funclets'. To the OS they are treated just like first class functions (separate PDATA and XDATA (`RUNTIME_FUNCTION` entry), etc.). The CLR currently treats them just like part of the parent function in many ways. The main function and all funclets must be allocated in a single code allocation (see hot cold splitting). They 'share' GC info. Only the main function prolog can be hot patched.
For all platforms except Windows/x86 on CoreCLR, all managed EH handlers (finally, fault, filter, filter-handler, and catch) are extracted into their own 'funclets'. To the OS they are treated just like first class functions (separate PDATA and XDATA (`RUNTIME_FUNCTION` entry), etc.). The CLR currently treats them just like part of the parent function in many ways. The main function and all funclets must be allocated in a single code allocation (see hot cold splitting). They 'share' GC info. Only the main function prolog can be hot patched.

The only way to enter a handler funclet is via a call. In the case of an exception, the call is from the VM's EH subsystem as part of exception dispatch/unwind. In the non-exceptional case, this is called local unwind or a non-local exit. In C# this is accomplished by simply falling-through/out of a try body or an explicit goto. In IL this is always accomplished via a LEAVE opcode, within a try body, targeting an IL offset outside the try body. In such cases the call is from the JITed code of the parent function.

For Windows/x86, all handlers are generated within the method body, typically in lexical order. A nested try/catch is generated completely within the EH region in which it is nested. These handlers are essentially "in-line funclets", but they do not look like normal functions: they do not have a normal prolog or epilog, although they do have special entry/exit and register conventions. Also, nested handlers are not un-nested as for funclets: the code for a nested handler is generated within the handler in which it is nested.
For Windows/x86 on CoreCLR, all handlers are generated within the method body, typically in lexical order. A nested try/catch is generated completely within the EH region in which it is nested. These handlers are essentially "in-line funclets", but they do not look like normal functions: they do not have a normal prolog or epilog, although they do have special entry/exit and register conventions. Also, nested handlers are not un-nested as for funclets: the code for a nested handler is generated within the handler in which it is nested.

For Windows/x86 on NativeAOT and Linux/x86, funclets are used just like on other platforms.

## Cloned finallys

Expand Down
4 changes: 0 additions & 4 deletions src/coreclr/clrdefinitions.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -288,8 +288,4 @@ function(set_target_definitions_to_custom_os_and_arch)
if (TARGETDETAILS_ARCH STREQUAL "armel")
target_compile_definitions(${TARGETDETAILS_TARGET} PRIVATE ARM_SOFTFP)
endif()

if (NOT (TARGETDETAILS_ARCH STREQUAL "x86") OR (TARGETDETAILS_OS MATCHES "^unix") OR (TARGETDETAILS_OS MATCHES "win_aot"))
target_compile_definitions(${TARGETDETAILS_TARGET} PRIVATE FEATURE_EH_FUNCLETS)
endif (NOT (TARGETDETAILS_ARCH STREQUAL "x86") OR (TARGETDETAILS_OS MATCHES "^unix") OR (TARGETDETAILS_OS MATCHES "win_aot"))
endfunction()
7 changes: 0 additions & 7 deletions src/coreclr/crosscomponents.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,6 @@ if (CLR_CMAKE_HOST_OS STREQUAL CLR_CMAKE_TARGET_OS OR CLR_CMAKE_TARGET_IOS OR CL
DESTINATIONS .
COMPONENT crosscomponents
)
if (CLR_CMAKE_TARGET_ARCH_I386)
install_clr (TARGETS
clrjit_win_aot_${ARCH_TARGET_NAME}_${ARCH_HOST_NAME}
DESTINATIONS .
COMPONENT crosscomponents
)
endif()
endif()
endif()
endif()
Expand Down
2 changes: 0 additions & 2 deletions src/coreclr/inc/clrnt.h
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,6 @@ typedef struct _DISPATCHER_CONTEXT {
#define RUNTIME_FUNCTION__BeginAddress(prf) (prf)->BeginAddress
#define RUNTIME_FUNCTION__SetBeginAddress(prf,addr) ((prf)->BeginAddress = (addr))

#ifdef FEATURE_EH_FUNCLETS
#include "win64unwind.h"
#include "daccess.h"

Expand Down Expand Up @@ -235,7 +234,6 @@ RtlVirtualUnwind (
__inout_opt PT_KNONVOLATILE_CONTEXT_POINTERS ContextPointers
);
#endif // HOST_X86
#endif // FEATURE_EH_FUNCLETS

#endif // TARGET_X86

Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/inc/gcinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const unsigned OFFSET_MASK = 0x3; // mask to access the low 2 bits
//
const unsigned byref_OFFSET_FLAG = 0x1; // the offset is an interior ptr
const unsigned pinned_OFFSET_FLAG = 0x2; // the offset is a pinned ptr
#if defined(TARGET_X86) && !defined(FEATURE_EH_FUNCLETS)
#if defined(TARGET_X86)
// JIT32_ENCODER has additional restriction on x86 without funclets:
// - for untracked locals the flags allowed are "pinned" and "byref"
// - for tracked locals the flags allowed are "this" and "byref"
Expand Down
3 changes: 0 additions & 3 deletions src/coreclr/jit/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ function(create_standalone_jit)

if(TARGETDETAILS_OS STREQUAL "unix_osx" OR TARGETDETAILS_OS STREQUAL "unix_anyos")
set(JIT_ARCH_LINK_LIBRARIES gcinfo_unix_${TARGETDETAILS_ARCH})
elseif(TARGETDETAILS_OS STREQUAL "win_aot")
set(JIT_ARCH_LINK_LIBRARIES gcinfo_win_${TARGETDETAILS_ARCH})
else()
set(JIT_ARCH_LINK_LIBRARIES gcinfo_${TARGETDETAILS_OS}_${TARGETDETAILS_ARCH})
endif()
Expand Down Expand Up @@ -658,7 +656,6 @@ else()
create_standalone_jit(TARGET clrjit_universal_arm_${ARCH_HOST_NAME} OS universal ARCH arm DESTINATIONS .)
target_compile_definitions(clrjit_universal_arm_${ARCH_HOST_NAME} PRIVATE ARM_SOFTFP CONFIGURABLE_ARM_ABI)
create_standalone_jit(TARGET clrjit_win_x86_${ARCH_HOST_NAME} OS win ARCH x86 DESTINATIONS .)
create_standalone_jit(TARGET clrjit_win_aot_x86_${ARCH_HOST_NAME} OS win_aot ARCH x86 DESTINATIONS .)
endif (CLR_CMAKE_TARGET_ARCH_RISCV64)

if (CLR_CMAKE_TARGET_ARCH_I386 AND CLR_CMAKE_TARGET_UNIX)
Expand Down
13 changes: 1 addition & 12 deletions src/coreclr/jit/block.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1812,9 +1812,7 @@ bool BasicBlock::hasEHBoundaryIn() const
bool returnVal = (bbCatchTyp != BBCT_NONE);
if (!returnVal)
{
#if FEATURE_EH_FUNCLETS
assert(!HasFlag(BBF_FUNCLET_BEG));
#endif // FEATURE_EH_FUNCLETS
}
return returnVal;
}
Expand All @@ -1833,16 +1831,7 @@ bool BasicBlock::hasEHBoundaryIn() const
//
bool BasicBlock::hasEHBoundaryOut() const
{
bool returnVal = KindIs(BBJ_EHFILTERRET, BBJ_EHFINALLYRET, BBJ_EHFAULTRET);

#if FEATURE_EH_FUNCLETS
if (bbKind == BBJ_EHCATCHRET)
{
returnVal = true;
}
#endif // FEATURE_EH_FUNCLETS

return returnVal;
return KindIs(BBJ_EHFILTERRET, BBJ_EHFINALLYRET, BBJ_EHFAULTRET, BBJ_EHCATCHRET);
}

//------------------------------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/jit/block.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ enum BBKinds : BYTE
BBJ_EHFINALLYRET,// block ends with 'endfinally' (for finally)
BBJ_EHFAULTRET, // block ends with 'endfinally' (IL alias for 'endfault') (for fault)
BBJ_EHFILTERRET, // block ends with 'endfilter'
BBJ_EHCATCHRET, // block ends with a leave out of a catch (only #if defined(FEATURE_EH_FUNCLETS))
BBJ_EHCATCHRET, // block ends with a leave out of a catch
BBJ_THROW, // block ends with 'throw'
BBJ_RETURN, // block ends with 'ret'
BBJ_ALWAYS, // block always jumps to the target
Expand Down
19 changes: 2 additions & 17 deletions src/coreclr/jit/codegen.h
Original file line number Diff line number Diff line change
Expand Up @@ -559,8 +559,6 @@ class CodeGen final : public CodeGenInterface
void genFnProlog();
void genFnEpilog(BasicBlock* block);

#if defined(FEATURE_EH_FUNCLETS)

void genReserveFuncletProlog(BasicBlock* block);
void genReserveFuncletEpilog(BasicBlock* block);
void genFuncletProlog(BasicBlock* block);
Expand Down Expand Up @@ -643,16 +641,6 @@ class CodeGen final : public CodeGenInterface

void genUpdateCurrentFunclet(BasicBlock* block);

#else // !FEATURE_EH_FUNCLETS

// This is a no-op when there are no funclets!
void genUpdateCurrentFunclet(BasicBlock* block)
{
return;
}

#endif // !FEATURE_EH_FUNCLETS

void genGeneratePrologsAndEpilogs();

#if defined(DEBUG)
Expand Down Expand Up @@ -747,9 +735,7 @@ class CodeGen final : public CodeGenInterface
void siOpenScopesForNonTrackedVars(const BasicBlock* block, unsigned int lastBlockILEndOffset);

protected:
#if defined(FEATURE_EH_FUNCLETS)
bool siInFuncletRegion; // Have we seen the start of the funclet region?
#endif // FEATURE_EH_FUNCLETS

IL_OFFSET siLastEndOffs; // IL offset of the (exclusive) end of the last block processed

Expand Down Expand Up @@ -1294,11 +1280,10 @@ class CodeGen final : public CodeGenInterface
void genCodeForBfiz(GenTreeOp* tree);
#endif // TARGET_ARM64

#if defined(FEATURE_EH_FUNCLETS)
void genEHCatchRet(BasicBlock* block);
#else // !FEATURE_EH_FUNCLETS
#if defined(FEATURE_EH_WINDOWS_X86)
void genEHFinallyOrFilterRet(BasicBlock* block);
#endif // !FEATURE_EH_FUNCLETS
#endif // FEATURE_EH_WINDOWS_X86

void genMultiRegStoreToSIMDLocal(GenTreeLclVar* lclNode);
void genMultiRegStoreToLocal(GenTreeLclVar* lclNode);
Expand Down
Loading

0 comments on commit 41b1091

Please sign in to comment.