diff --git a/eng/pipelines/common/templates/runtimes/run-test-job.yml b/eng/pipelines/common/templates/runtimes/run-test-job.yml
index f7f310dfb9742..9e75af0ac8f6b 100644
--- a/eng/pipelines/common/templates/runtimes/run-test-job.yml
+++ b/eng/pipelines/common/templates/runtimes/run-test-job.yml
@@ -572,6 +572,7 @@ jobs:
- jitosr_stress
- jitosr_pgo
- jitosr_stress_random
+ - jit_stress_splitting
- jitpartialcompilation
- jitpartialcompilation_osr
- jitpartialcompilation_osr_pgo
diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h
index b4cfe60a692d9..9656fed89dbfb 100644
--- a/src/coreclr/jit/compiler.h
+++ b/src/coreclr/jit/compiler.h
@@ -7966,6 +7966,10 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
void unwindReserveFuncHelper(FuncInfoDsc* func, bool isHotCode);
void unwindEmitFuncHelper(FuncInfoDsc* func, void* pHotCode, void* pColdCode, bool isHotCode);
+#ifdef DEBUG
+ void fakeUnwindEmitFuncHelper(FuncInfoDsc* func, void* pHotCode);
+#endif // DEBUG
+
#endif // TARGET_AMD64 || (TARGET_X86 && FEATURE_EH_FUNCLETS)
UNATIVE_OFFSET unwindGetCurrentOffset(FuncInfoDsc* func);
diff --git a/src/coreclr/jit/ee_il_dll.cpp b/src/coreclr/jit/ee_il_dll.cpp
index c7ac7b32e5e99..f8c437e326694 100644
--- a/src/coreclr/jit/ee_il_dll.cpp
+++ b/src/coreclr/jit/ee_il_dll.cpp
@@ -1125,14 +1125,13 @@ void Compiler::eeDispLineInfos()
void Compiler::eeAllocMem(AllocMemArgs* args)
{
#ifdef DEBUG
- // Fake splitting implementation: hot section = hot code + 4K buffer + cold code
- const UNATIVE_OFFSET hotSizeRequest = args->hotCodeSize;
- const UNATIVE_OFFSET coldSizeRequest = args->coldCodeSize;
- const UNATIVE_OFFSET fakeSplittingBuffer = 4096;
+ const UNATIVE_OFFSET hotSizeRequest = args->hotCodeSize;
+ const UNATIVE_OFFSET coldSizeRequest = args->coldCodeSize;
+ // Fake splitting implementation: place hot/cold code in contiguous section
if (JitConfig.JitFakeProcedureSplitting() && (coldSizeRequest > 0))
{
- args->hotCodeSize = hotSizeRequest + fakeSplittingBuffer + coldSizeRequest;
+ args->hotCodeSize = hotSizeRequest + coldSizeRequest;
args->coldCodeSize = 0;
}
#endif
@@ -1143,8 +1142,8 @@ void Compiler::eeAllocMem(AllocMemArgs* args)
if (JitConfig.JitFakeProcedureSplitting() && (coldSizeRequest > 0))
{
// Fix up hot/cold code pointers
- args->coldCodeBlock = ((BYTE*)args->hotCodeBlock) + hotSizeRequest + fakeSplittingBuffer;
- args->coldCodeBlockRW = ((BYTE*)args->hotCodeBlockRW) + hotSizeRequest + fakeSplittingBuffer;
+ args->coldCodeBlock = ((BYTE*)args->hotCodeBlock) + hotSizeRequest;
+ args->coldCodeBlockRW = ((BYTE*)args->hotCodeBlockRW) + hotSizeRequest;
// Reset args' hot/cold code sizes in case caller reads them later
args->hotCodeSize = hotSizeRequest;
@@ -1161,13 +1160,6 @@ void Compiler::eeReserveUnwindInfo(bool isFunclet, bool isColdCode, ULONG unwind
printf("reserveUnwindInfo(isFunclet=%s, isColdCode=%s, unwindSize=0x%x)\n", isFunclet ? "true" : "false",
isColdCode ? "true" : "false", unwindSize);
}
-
- // Fake splitting currently does not handle unwind info for cold code
- if (isColdCode && JitConfig.JitFakeProcedureSplitting())
- {
- JITDUMP("reserveUnwindInfo for cold code with JitFakeProcedureSplitting enabled: ignoring cold unwind info\n");
- return;
- }
#endif // DEBUG
if (info.compMatchedVM)
@@ -1207,13 +1199,6 @@ void Compiler::eeAllocUnwindInfo(BYTE* pHotCode,
}
printf(")\n");
}
-
- // Fake splitting currently does not handle unwind info for cold code
- if (pColdCode && JitConfig.JitFakeProcedureSplitting())
- {
- JITDUMP("allocUnwindInfo for cold code with JitFakeProcedureSplitting enabled: ignoring cold unwind info\n");
- return;
- }
#endif // DEBUG
if (info.compMatchedVM)
diff --git a/src/coreclr/jit/emit.cpp b/src/coreclr/jit/emit.cpp
index 10c5c096f8934..bd5dccdfabc74 100644
--- a/src/coreclr/jit/emit.cpp
+++ b/src/coreclr/jit/emit.cpp
@@ -6637,10 +6637,13 @@ unsigned emitter::emitEndCodeGen(Compiler* comp,
{
// The allocated chunk is bigger than used, fill in unused space in it.
unsigned unusedSize = allocatedHotCodeSize - emitCurCodeOffs(cp);
+ BYTE* cpRW = cp + writeableOffset;
for (unsigned i = 0; i < unusedSize; ++i)
{
- *cp++ = DEFAULT_CODE_BUFFER_INIT;
+ *cpRW++ = DEFAULT_CODE_BUFFER_INIT;
}
+
+ cp = cpRW - writeableOffset;
assert(allocatedHotCodeSize == emitCurCodeOffs(cp));
}
}
diff --git a/src/coreclr/jit/jitconfigvalues.h b/src/coreclr/jit/jitconfigvalues.h
index 29e977cf1d8c9..dbf4b6069fc40 100644
--- a/src/coreclr/jit/jitconfigvalues.h
+++ b/src/coreclr/jit/jitconfigvalues.h
@@ -196,11 +196,6 @@ CONFIG_INTEGER(JitDumpInlinePhases, W("JitDumpInlinePhases"), 1) // Dump inline
CONFIG_METHODSET(JitEHDump, W("JitEHDump")) // Dump the EH table for the method, as reported to the VM
CONFIG_METHODSET(JitExclude, W("JitExclude"))
CONFIG_INTEGER(JitFakeProcedureSplitting, W("JitFakeProcedureSplitting"), 0) // Do code splitting independent of VM.
- // For now, this disables unwind info for
- // cold sections, breaking stack walks.
- // Set COMPlus_GCgen0size=1000000 to avoid
- // running the GC, which requires
- // stack-walking.
CONFIG_METHODSET(JitForceProcedureSplitting, W("JitForceProcedureSplitting"))
CONFIG_METHODSET(JitGCDump, W("JitGCDump"))
CONFIG_METHODSET(JitDebugDump, W("JitDebugDump"))
diff --git a/src/coreclr/jit/unwindamd64.cpp b/src/coreclr/jit/unwindamd64.cpp
index caaf7c2dbe29b..2c8e90fa5a944 100644
--- a/src/coreclr/jit/unwindamd64.cpp
+++ b/src/coreclr/jit/unwindamd64.cpp
@@ -656,11 +656,21 @@ void Compiler::unwindReserve()
//
void Compiler::unwindReserveFunc(FuncInfoDsc* func)
{
- unwindReserveFuncHelper(func, true);
-
- if (fgFirstColdBlock != nullptr)
+#ifdef DEBUG
+ if (JitConfig.JitFakeProcedureSplitting() && (fgFirstColdBlock != nullptr))
{
- unwindReserveFuncHelper(func, false);
+ assert(func->funKind == FUNC_ROOT); // No fake-splitting of funclets.
+ unwindReserveFuncHelper(func, true);
+ }
+ else
+#endif // DEBUG
+ {
+ unwindReserveFuncHelper(func, true);
+
+ if (fgFirstColdBlock != nullptr)
+ {
+ unwindReserveFuncHelper(func, false);
+ }
}
}
@@ -880,12 +890,43 @@ void Compiler::unwindEmitFunc(FuncInfoDsc* func, void* pHotCode, void* pColdCode
static_assert_no_msg(FUNC_HANDLER == (FuncKind)CORJIT_FUNC_HANDLER);
static_assert_no_msg(FUNC_FILTER == (FuncKind)CORJIT_FUNC_FILTER);
- unwindEmitFuncHelper(func, pHotCode, pColdCode, true);
+#ifdef DEBUG
+ if (JitConfig.JitFakeProcedureSplitting() && (pColdCode != nullptr))
+ {
+ fakeUnwindEmitFuncHelper(func, pHotCode);
+ }
+ else
+#endif // DEBUG
+ {
+ unwindEmitFuncHelper(func, pHotCode, pColdCode, true);
+
+ if (pColdCode != nullptr)
+ {
+ unwindEmitFuncHelper(func, pHotCode, pColdCode, false);
+ }
+ }
+}
+
+#ifdef DEBUG
+void Compiler::fakeUnwindEmitFuncHelper(FuncInfoDsc* func, void* pHotCode)
+{
+ assert(fgFirstColdBlock != nullptr);
+ assert(func->funKind == FUNC_ROOT); // No fake-splitting of funclets.
- if (pColdCode != nullptr)
+ const UNATIVE_OFFSET startOffset = 0;
+ const UNATIVE_OFFSET endOffset = info.compNativeCodeSize;
+ const DWORD unwindCodeBytes = sizeof(func->unwindCodes) - func->unwindCodeSlot;
+ BYTE* pUnwindBlock = &func->unwindCodes[func->unwindCodeSlot];
+
+ if (opts.dspUnwind)
{
- unwindEmitFuncHelper(func, pHotCode, pColdCode, false);
+ DumpUnwindInfo(true, startOffset, endOffset, (const UNWIND_INFO* const)pUnwindBlock);
}
+
+ // Pass pColdCode = nullptr; VM allocs unwind info for combined hot/cold section
+ eeAllocUnwindInfo((BYTE*)pHotCode, nullptr, startOffset, endOffset, unwindCodeBytes, pUnwindBlock,
+ (CorJitFuncKind)func->funKind);
}
+#endif // DEBUG
#endif // TARGET_AMD64
diff --git a/src/coreclr/jit/unwindx86.cpp b/src/coreclr/jit/unwindx86.cpp
index 0cd88fd29ba1e..bd27e46cbef49 100644
--- a/src/coreclr/jit/unwindx86.cpp
+++ b/src/coreclr/jit/unwindx86.cpp
@@ -113,11 +113,21 @@ void Compiler::unwindEmit(void* pHotCode, void* pColdCode)
//
void Compiler::unwindReserveFunc(FuncInfoDsc* func)
{
- unwindReserveFuncHelper(func, true);
-
- if (fgFirstColdBlock != nullptr)
+#ifdef DEBUG
+ if (JitConfig.JitFakeProcedureSplitting() && (fgFirstColdBlock != nullptr))
{
- unwindReserveFuncHelper(func, false);
+ assert(func->funKind == FUNC_ROOT); // No fake-splitting of funclets.
+ unwindReserveFuncHelper(func, true);
+ }
+ else
+#endif // DEBUG
+ {
+ unwindReserveFuncHelper(func, true);
+
+ if (fgFirstColdBlock != nullptr)
+ {
+ unwindReserveFuncHelper(func, false);
+ }
}
}
@@ -154,11 +164,20 @@ void Compiler::unwindEmitFunc(FuncInfoDsc* func, void* pHotCode, void* pColdCode
static_assert_no_msg(FUNC_HANDLER == (FuncKind)CORJIT_FUNC_HANDLER);
static_assert_no_msg(FUNC_FILTER == (FuncKind)CORJIT_FUNC_FILTER);
- unwindEmitFuncHelper(func, pHotCode, pColdCode, true);
-
- if (pColdCode != nullptr)
+#ifdef DEBUG
+ if (JitConfig.JitFakeProcedureSplitting() && (pColdCode != nullptr))
+ {
+ fakeUnwindEmitFuncHelper(func, pHotCode);
+ }
+ else
+#endif // DEBUG
{
- unwindEmitFuncHelper(func, pHotCode, pColdCode, false);
+ unwindEmitFuncHelper(func, pHotCode, pColdCode, true);
+
+ if (pColdCode != nullptr)
+ {
+ unwindEmitFuncHelper(func, pHotCode, pColdCode, false);
+ }
}
}
@@ -256,4 +275,23 @@ void Compiler::unwindEmitFuncHelper(FuncInfoDsc* func, void* pHotCode, void* pCo
eeAllocUnwindInfo((BYTE*)pHotCode, (BYTE*)pColdCode, startOffset, endOffset, sizeof(UNWIND_INFO),
(BYTE*)&unwindInfo, (CorJitFuncKind)func->funKind);
}
+
+#ifdef DEBUG
+void Compiler::fakeUnwindEmitFuncHelper(FuncInfoDsc* func, void* pHotCode)
+{
+ assert(fgFirstColdBlock != nullptr);
+ assert(func->funKind == FUNC_ROOT); // No fake-splitting of funclets.
+
+ const UNATIVE_OFFSET startOffset = 0;
+ const UNATIVE_OFFSET endOffset = info.compNativeCodeSize;
+
+ UNWIND_INFO unwindInfo;
+ unwindInfo.FunctionLength = (ULONG)(endOffset);
+
+ // Pass pColdCode = nullptr; VM allocs unwind info for combined hot/cold section
+ eeAllocUnwindInfo((BYTE*)pHotCode, nullptr, startOffset, endOffset, sizeof(UNWIND_INFO), (BYTE*)&unwindInfo,
+ (CorJitFuncKind)func->funKind);
+}
+#endif // DEBUG
+
#endif // FEATURE_EH_FUNCLETS
diff --git a/src/tests/Common/testenvironment.proj b/src/tests/Common/testenvironment.proj
index fcc3e3926febc..4cc62162bc2f2 100644
--- a/src/tests/Common/testenvironment.proj
+++ b/src/tests/Common/testenvironment.proj
@@ -42,7 +42,9 @@
COMPlus_HeapVerify;
COMPlus_JITMinOpts;
COMPlus_JitELTHookEnabled;
+ COMPlus_JitFakeProcedureSplitting;
COMPlus_JitStress;
+ COMPlus_JitStressProcedureSplitting;
COMPlus_JitStressRegs;
COMPlus_TailcallStress;
COMPlus_ReadyToRun;
@@ -188,6 +190,7 @@
+