summaryrefslogtreecommitdiff
path: root/src/jit/unwind.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/jit/unwind.cpp')
-rw-r--r--src/jit/unwind.cpp171
1 files changed, 171 insertions, 0 deletions
diff --git a/src/jit/unwind.cpp b/src/jit/unwind.cpp
new file mode 100644
index 0000000000..4568fed75a
--- /dev/null
+++ b/src/jit/unwind.cpp
@@ -0,0 +1,171 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XX XX
+XX UnwindInfo XX
+XX XX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+*/
+
+#include "jitpch.h"
+#ifdef _MSC_VER
+#pragma hdrstop
+#endif
+
+#if FEATURE_EH_FUNCLETS
+
+//------------------------------------------------------------------------
+// Compiler::unwindGetFuncLocations: Get the start/end emitter locations for this
+// function or funclet. If 'getHotSectionData' is true, get the start/end locations
+// for the hot section. Otherwise, get the data for the cold section.
+//
+// Note that we grab these locations before the prolog and epilogs are generated, so the
+// locations must remain correct after the prolog and epilogs are generated.
+//
+// For the prolog, instructions are put in the special, preallocated, prolog instruction group.
+// We don't want to expose the emitPrologIG unnecessarily (locations are actually pointers to
+// emitter instruction groups). Since we know the offset of the start of the function/funclet,
+// where the prolog is, will be zero, we use a nullptr start location to indicate that.
+//
+// There is no instruction group beyond the end of the end of the function, so there is no
+// location to indicate that. Once again, use nullptr for that.
+//
+// Intermediate locations point at the first instruction group of a funclet, which is a
+// placeholder IG. These are converted to real IGs, not deleted and replaced, so the location
+// remains valid.
+//
+// Arguments:
+// func - main function or funclet to get locations for.
+// getHotSectionData - 'true' to get the hot section data, 'false' to get the cold section data.
+// ppStartLoc - OUT parameter. Set to the start emitter location.
+// ppEndLoc - OUT parameter. Set to the end emitter location (the location immediately
+// the range; the 'end' location is not inclusive).
+//
+// Notes:
+// A start location of nullptr means the beginning of the code.
+// An end location of nullptr means the end of the code.
+//
+void Compiler::unwindGetFuncLocations(FuncInfoDsc* func,
+ bool getHotSectionData,
+ /* OUT */ emitLocation** ppStartLoc,
+ /* OUT */ emitLocation** ppEndLoc)
+{
+ if (func->funKind == FUNC_ROOT)
+ {
+ // Since all funclets are pulled out of line, the main code size is everything
+ // up to the first handler. If the function is hot/cold split, we need to get the
+ // appropriate sub-range.
+
+ if (getHotSectionData)
+ {
+ *ppStartLoc = nullptr; // nullptr emit location means the beginning of the code. This is to handle the first
+ // fragment prolog.
+
+ if (fgFirstColdBlock != nullptr)
+ {
+ // The hot section only goes up to the cold section
+ assert(fgFirstFuncletBB == nullptr);
+
+ *ppEndLoc = new (this, CMK_UnwindInfo) emitLocation(ehEmitCookie(fgFirstColdBlock));
+ }
+ else
+ {
+ if (fgFirstFuncletBB != nullptr)
+ {
+ *ppEndLoc = new (this, CMK_UnwindInfo) emitLocation(ehEmitCookie(fgFirstFuncletBB));
+ }
+ else
+ {
+ *ppEndLoc = nullptr; // nullptr end location means the end of the code
+ }
+ }
+ }
+ else
+ {
+ assert(fgFirstFuncletBB == nullptr); // TODO-CQ: support hot/cold splitting in functions with EH
+ assert(fgFirstColdBlock != nullptr); // There better be a cold section!
+
+ *ppStartLoc = new (this, CMK_UnwindInfo) emitLocation(ehEmitCookie(fgFirstColdBlock));
+ *ppEndLoc = nullptr; // nullptr end location means the end of the code
+ }
+ }
+ else
+ {
+ assert(getHotSectionData); // TODO-CQ: support funclets in cold section
+
+ EHblkDsc* HBtab = ehGetDsc(func->funEHIndex);
+
+ if (func->funKind == FUNC_FILTER)
+ {
+ assert(HBtab->HasFilter());
+ *ppStartLoc = new (this, CMK_UnwindInfo) emitLocation(ehEmitCookie(HBtab->ebdFilter));
+ *ppEndLoc = new (this, CMK_UnwindInfo) emitLocation(ehEmitCookie(HBtab->ebdHndBeg));
+ }
+ else
+ {
+ assert(func->funKind == FUNC_HANDLER);
+ *ppStartLoc = new (this, CMK_UnwindInfo) emitLocation(ehEmitCookie(HBtab->ebdHndBeg));
+ *ppEndLoc = (HBtab->ebdHndLast->bbNext == nullptr)
+ ? nullptr
+ : new (this, CMK_UnwindInfo) emitLocation(ehEmitCookie(HBtab->ebdHndLast->bbNext));
+ }
+ }
+}
+
+#endif // FEATURE_EH_FUNCLETS
+
+#if defined(_TARGET_AMD64_)
+
+// See unwindAmd64.cpp
+
+#elif defined(_TARGET_ARM64_)
+
+// See unwindArm64.cpp
+
+#elif defined(_TARGET_ARM_)
+
+// See unwindArm.cpp
+
+#elif defined(_TARGET_X86_)
+
+// Stub routines that do nothing
+void Compiler::unwindBegProlog()
+{
+}
+void Compiler::unwindEndProlog()
+{
+}
+void Compiler::unwindBegEpilog()
+{
+}
+void Compiler::unwindEndEpilog()
+{
+}
+void Compiler::unwindReserve()
+{
+}
+void Compiler::unwindEmit(void* pHotCode, void* pColdCode)
+{
+}
+void Compiler::unwindPush(regNumber reg)
+{
+}
+void Compiler::unwindAllocStack(unsigned size)
+{
+}
+void Compiler::unwindSetFrameReg(regNumber reg, unsigned offset)
+{
+}
+void Compiler::unwindSaveReg(regNumber reg, unsigned offset)
+{
+}
+
+#else // _TARGET_*
+
+#error Unsupported or unset target architecture
+
+#endif // _TARGET_*