Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/corert.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsergey ignatov <sergign60@mail.ru>2017-07-19 00:34:06 +0300
committerJan Kotas <jkotas@microsoft.com>2017-07-19 00:34:06 +0300
commit7d84a06eedf4076206cd56a66bddd4da353f170b (patch)
treec8c799526c70d4aaca4052f1829b4fa50c036042 /src/Native/Runtime/arm
parentd5c4c61239ac7c1960db6103e1e3f0742e5d8ca8 (diff)
[arm linux] Provided asm stubs for ExceptionHandling.S & CallingConve… (#4170)
* [arm linux] Provided asm stubs for ExceptionHandling.S & CallingConventionConverterHelpers.S * Synced UNHIJACK part of RhpThrowEx with arm windows version * Fixed asm version of RhpNewFast * Added CallingConventionConverter_SpecifyCommonStubData
Diffstat (limited to 'src/Native/Runtime/arm')
-rw-r--r--src/Native/Runtime/arm/AllocFast.S3
-rw-r--r--src/Native/Runtime/arm/CallingConventionConverterHelpers.S62
-rw-r--r--src/Native/Runtime/arm/ExceptionHandling.S450
3 files changed, 407 insertions, 108 deletions
diff --git a/src/Native/Runtime/arm/AllocFast.S b/src/Native/Runtime/arm/AllocFast.S
index f53cf0acf..8fbdd16f9 100644
--- a/src/Native/Runtime/arm/AllocFast.S
+++ b/src/Native/Runtime/arm/AllocFast.S
@@ -34,6 +34,9 @@ LEAF_ENTRY RhpNewFast, _TEXT
// set the new alloc pointer
str r2, [r0, #OFFSETOF__Thread__m_alloc_context__alloc_ptr]
+ // Set the new object's EEType pointer
+ str r4, [r3, #OFFSETOF__Object__m_pEEType]
+
mov r0, r3
EPILOG_POP "{r4,pc}"
diff --git a/src/Native/Runtime/arm/CallingConventionConverterHelpers.S b/src/Native/Runtime/arm/CallingConventionConverterHelpers.S
index 0b2f046d0..c42d6d1f7 100644
--- a/src/Native/Runtime/arm/CallingConventionConverterHelpers.S
+++ b/src/Native/Runtime/arm/CallingConventionConverterHelpers.S
@@ -2,36 +2,27 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-#include <unixasmmacros.inc>
-
// TODO: Implement Arm support
.syntax unified
.thumb
-#ifdef _DEBUG
-.rodata
-AssertMsg: .asciz "__FILE__:%s: %s is not implemented\n"
-FileName: .asciz "CallingConventionConverterHelpers.S"
-CallingConventionConverter_ReturnThunkName: .asciz "CallingConventionConverter_ReturnThunk"
-__jmpstub__CallingConventionConverter_CommonCallingStubName: .asciz "__jmpstub__CallingConventionConverter_CommonCallingStub"
-CallingConventionConverter_SpecifyCommonStubDataName: .asciz "CallingConventionConverter_SpecifyCommonStubData"
-CallingConventionConverter_GetStubsName: .asciz "CallingConventionConverter_GetStubs"
-
-.text
-.macro GEN_ASSERT_FUNC func
- GEN_ASSERT AssertMsg, FileName, \func
-.endm
-#endif
+#include <unixasmmacros.inc>
+#include <AsmOffsets.inc> // generated by the build from AsmOffsets.cpp
//
-// void CallingConventionConverter_ReturnThunk()
+// void CallingConventionConverter_ReturnVoidReturnThunk()
//
-LEAF_ENTRY CallingConventionConverter_ReturnThunk
-#ifdef _DEBUG
- GEN_ASSERT_FUNC CallingConventionConverter_ReturnThunkName
-#endif
-LEAF_END CallingConventionConverter_ReturnThunk
+LEAF_ENTRY CallingConventionConverter_ReturnVoidReturnThunk, _TEXT
+ bx lr
+LEAF_END CallingConventionConverter_ReturnVoidReturnThunk, _TEXT
+//
+// int CallingConventionConverter_ReturnIntegerReturnThunk(int)
+//
+LEAF_ENTRY CallingConventionConverter_ReturnIntegerReturnThunk, _TEXT
+ // UNIXTODO: Implement this function
+ EMIT_BREAKPOINT
+LEAF_END CallingConventionConverter_ReturnIntegerReturnThunk, _TEXT
//
// __jmpstub__CallingConventionConverter_CommonCallingStub
@@ -54,25 +45,22 @@ LEAF_END CallingConventionConverter_ReturnThunk
//
//
LEAF_ENTRY __jmpstub__CallingConventionConverter_CommonCallingStub
-#ifdef _DEBUG
- GEN_ASSERT_FUNC __jmpstub__CallingConventionConverter_CommonCallingStubName
-#endif
+ // UNIXTODO: Implement this function
+ EMIT_BREAKPOINT
LEAF_END __jmpstub__CallingConventionConverter_CommonCallingStub
//
-// void CallingConventionConverter_SpecifyCommonStubData(CallingConventionConverter_CommonCallingStub_PointerData *commonData);
-//
-LEAF_ENTRY CallingConventionConverter_SpecifyCommonStubData
-#ifdef _DEBUG
- GEN_ASSERT_FUNC CallingConventionConverter_SpecifyCommonStubDataName
-#endif
-LEAF_END CallingConventionConverter_SpecifyCommonStubData
-
-//
// void CallingConventionConverter_GetStubs(IntPtr *returnVoidStub, IntPtr *returnIntegerStub, IntPtr *commonCallingStub)
//
LEAF_ENTRY CallingConventionConverter_GetStubs, _TEXT
-#ifdef _DEBUG
- GEN_ASSERT_FUNC CallingConventionConverter_GetStubsName
-#endif
+ // UNIXTODO: Implement this function
+ EMIT_BREAKPOINT
LEAF_END CallingConventionConverter_GetStubs, _TEXT
+
+//
+// void CallingConventionConverter_SpecifyCommonStubData(CallingConventionConverter_CommonCallingStub_PointerData *commonData);
+//
+LEAF_ENTRY CallingConventionConverter_SpecifyCommonStubData
+ // UNIXTODO: Implement this function
+ EMIT_BREAKPOINT
+LEAF_END CallingConventionConverter_SpecifyCommonStubData
diff --git a/src/Native/Runtime/arm/ExceptionHandling.S b/src/Native/Runtime/arm/ExceptionHandling.S
index 813d4ac5e..b3bfd3ae7 100644
--- a/src/Native/Runtime/arm/ExceptionHandling.S
+++ b/src/Native/Runtime/arm/ExceptionHandling.S
@@ -2,52 +2,76 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-#include <unixasmmacros.inc>
-
.syntax unified
.thumb
-#ifdef _DEBUG
-.rodata
-AssertMsg: .asciz "__FILE__:%s: %s is not implemented\n"
-FileName: .asciz "ExceptionHandling.S"
-RhpThrowHwExName: .asciz "RhpThrowHwEx"
-RhpThrowExName: .asciz "RhpThrowEx"
-RhpRethrowName: .asciz "RhpRethrow"
-RhpCallCatchFuncletName: .asciz "RhpCallCatchFunclet"
-RhpCallFinallyFuncletName: .asciz "RhpCallFinallyFunclet"
-RhpCallFilterFuncletName: .asciz "RhpCallFilterFunclet"
-
-.text
-.macro GEN_ASSERT_FUNC func
- GEN_ASSERT AssertMsg, FileName, \func
-.endm
-#endif
-
-// TODO: Implement Arm support
+#include <unixasmmacros.inc>
+#include <AsmOffsets.inc> // generated by the build from AsmOffsets.cpp
+
+#define STACKSIZEOF_ExInfo ((SIZEOF__ExInfo + 7)&(~7))
+
+#define rsp_offsetof_ExInfo 0
+#define rsp_offsetof_Context STACKSIZEOF_ExInfo
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// RhpThrowHwEx
//
-// INPUT: RDI: exception code of fault
-// RSI: faulting RIP
+// INPUT: R0: exception code of fault
+// R1: faulting RIP
//
// OUTPUT:
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
NESTED_ENTRY RhpThrowHwEx, _TEXT, NoHandler
-ALTERNATE_ENTRY RhpThrowHwEx2
-
-#ifdef _DEBUG
- GEN_ASSERT_FUNC RhpThrowHwExName
-#endif
+ mov r2, r0 // save exception code into r2
+ mov r0, sp // get SP of fault site
+
+ mov lr, r1 // set IP of fault site
+
+ // Setup a PAL_LIMITED_CONTEXT on the stack {
+ PROLOG_VPUSH {d8-d15}
+ PROLOG_PUSH "{r0,lr}" // push {sp, pc} of fault site
+ PROLOG_PUSH "{r0,r4-r11,lr}"
+ // } end PAL_LIMITED_CONTEXT
+
+ PROLOG_STACK_ALLOC STACKSIZEOF_ExInfo
+
+ // r0: SP of fault site
+ // r1: IP of fault site
+ // r2: exception code of fault
+ // lr: IP of fault site (as a 'return address')
+ mov r4, r2 // save exception code of fault
+
+ // r0 = GetThread()
+ INLINE_GETTHREAD
+
+ // r1 <- ExInfo*
+ add r1, sp, #rsp_offsetof_ExInfo
+ mov r3, #0
+ str r3, [r1, #OFFSETOF__ExInfo__m_exception] // pExInfo->m_exception = null
+ mov r3, #1
+ strb r3, [r1, #OFFSETOF__ExInfo__m_passNumber] // pExInfo->m_passNumber = 1
+ mov r3, #0xFFFFFFFF
+ str r3, [r1, #OFFSETOF__ExInfo__m_idxCurClause] // pExInfo->m_idxCurClause = MaxTryRegionIdx
+ mov r3, #2
+ strb r3, [r1, #OFFSETOF__ExInfo__m_kind] // pExInfo->m_kind = ExKind.HardwareFault
+
+ // link the ExInfo into the thread's ExInfo chain
+ ldr r3, [r0, #OFFSETOF__Thread__m_pExInfoStackHead]
+ str r3, [r1, #OFFSETOF__ExInfo__m_pPrevExInfo] // pExInfo->m_pPrevExInfo = m_pExInfoStackHead
+ str r1, [r0, #OFFSETOF__Thread__m_pExInfoStackHead] // m_pExInfoStackHead = pExInfo
+
+ mov r0, r4 // restore the exception code
+ // r0 contains the exception code
+ // r1 contains the address of the ExInfo
+ bl C_FUNC(RhThrowHwEx)
EXPORT_POINTER_TO_ADDRESS PointerToRhpThrowHwEx2
// no return
- bkpt
+ EMIT_BREAKPOINT
NESTED_END RhpThrowHwEx
@@ -56,23 +80,99 @@ NESTED_END RhpThrowHwEx
//
// RhpThrowEx
//
-// INPUT: RDI: exception object
+// INPUT: R0: exception object
//
// OUTPUT:
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
NESTED_ENTRY RhpThrowEx, _TEXT, NoHandler
-ALTERNATE_ENTRY RhpThrowEx2
+ // Setup a PAL_LIMITED_CONTEXT on the stack {
+ PROLOG_VPUSH {d8-d15}
+ PROLOG_PUSH "{r0,lr}" // Reserve space for SP and store LR
+ PROLOG_PUSH "{r0,r4-r11,lr}"
+ // } end PAL_LIMITED_CONTEXT
+
+ PROLOG_STACK_ALLOC STACKSIZEOF_ExInfo
+
+ mov r4, r0 // Save exception object
+ // r0 = GetThread()
+ INLINE_GETTHREAD
+
+ add r2, sp, #(rsp_offsetof_Context + SIZEOF__PAL_LIMITED_CONTEXT + 0x8) // r2 <- addr of return address
+
+ // There is runtime C# code that can tail call to RhpThrowEx using a binder intrinsic. So the return
+ // address could have been hijacked when we were in that C# code and we must remove the hijack and
+ // reflect the correct return address in our exception context record. The other throw helpers don't
+ // need this because they cannot be tail-called from C#.
+ // NOTE: we cannot use INLINE_THREAD_UNHIJACK because it will write into the stack at the location
+ // where the tail-calling thread had saved LR, which may not match where we have saved LR.
+
+ ldr r1, [r0, #OFFSETOF__Thread__m_pvHijackedReturnAddress]
+ cbz r1, LOCAL_LABEL(NotHijacked)
+
+ ldr r3, [r0, #OFFSETOF__Thread__m_ppvHijackedReturnAddressLocation]
+
+ // r4: exception object
+ // r1: hijacked return address
+ // r0: pThread
+ // r3: hijacked return address location
+
+ add r12, sp, #(STACKSIZEOF_ExInfo + SIZEOF__PAL_LIMITED_CONTEXT) // re-compute SP at callsite
+ cmp r3, r12 // if (m_ppvHijackedReturnAddressLocation < SP at callsite)
+ blo LOCAL_LABEL(TailCallWasHijacked)
+
+ // normal case where a valid return address location is hijacked
+ str r1, [r3]
+ b LOCAL_LABEL(ClearThreadState)
+
+LOCAL_LABEL(TailCallWasHijacked):
+
+ // Abnormal case where the return address location is now invalid because we ended up here via a tail
+ // call. In this case, our hijacked return address should be the correct caller of this method.
+ //
+
+ // stick the previous return address in LR as well as in the right spots in our PAL_LIMITED_CONTEXT.
+ mov lr, r1
+ str lr, [sp, #(rsp_offsetof_Context + OFFSETOF__PAL_LIMITED_CONTEXT__LR)]
+ str lr, [sp, #(rsp_offsetof_Context + OFFSETOF__PAL_LIMITED_CONTEXT__IP)]
+
+LOCAL_LABEL(ClearThreadState):
+
+ // clear the Thread's hijack state
+ mov r3, #0
+ str r3, [r0, #OFFSETOF__Thread__m_ppvHijackedReturnAddressLocation]
+ str r3, [r0, #OFFSETOF__Thread__m_pvHijackedReturnAddress]
+
+LOCAL_LABEL(NotHiJacked):
+
+ add r1, sp, #rsp_offsetof_ExInfo // r1 <- ExInfo*
+ mov r3, #0
+ str r3, [r1, #OFFSETOF__ExInfo__m_exception] // init the exception object to null
+ mov r3, #1
+ strb r3, [r1, #OFFSETOF__ExInfo__m_passNumber] // init to the first pass
+ strb r3, [r1, #OFFSETOF__ExInfo__m_kind]
+ mov r3, #0xFFFFFFFF
+ str r3, [r1, #OFFSETOF__ExInfo__m_idxCurClause] // ExKind.Throw
+
+ // link the ExInfo into the thread's ExInfo chain
+ ldr r3, [r0, #OFFSETOF__Thread__m_pExInfoStackHead]
+ str r3, [r1, #OFFSETOF__ExInfo__m_pPrevExInfo] // pExInfo->m_pPrevExInfo = m_pExInfoStackHead
+ str r1, [r0, #OFFSETOF__Thread__m_pExInfoStackHead] // m_pExInfoStackHead = pExInfo
-#ifdef _DEBUG
- GEN_ASSERT_FUNC RhpThrowExName
-#endif
+ // set the exception context field on the ExInfo
+ add r3, sp, #rsp_offsetof_Context // r3 <- PAL_LIMITED_CONTEXT*
+ str r3, [r1, #OFFSETOF__ExInfo__m_pExContext] // init ExInfo.m_pExContext
+
+ mov r0, r4 // Restore exception object
+ // r0 contains the exception object
+ // r1 contains the address of the new ExInfo
+ bl C_FUNC(RhThrowEx)
EXPORT_POINTER_TO_ADDRESS PointerToRhpThrowEx2
// no return
- bkpt
+ EMIT_BREAKPOINT
NESTED_END RhpThrowEx, _TEXT
@@ -90,51 +190,147 @@ NESTED_END RhpThrowEx, _TEXT
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
NESTED_ENTRY RhpRethrow, _TEXT, NoHandler
-ALTERNATE_ENTRY RhpRethrow2
+ // Setup a PAL_LIMITED_CONTEXT on the stack {
+ PROLOG_VPUSH {d8-d15}
+ PROLOG_PUSH "{r0,lr}" // Reserve space for SP and store LR
+ PROLOG_PUSH "{r0,r4-r11,lr}"
+ // } end PAL_LIMITED_CONTEXT
+
+ PROLOG_STACK_ALLOC STACKSIZEOF_ExInfo
+
+ // r0 = GetThread();
+ INLINE_GETTHREAD
+
+ // r1 <- ExInfo*
+ add r1, sp, #rsp_offsetof_ExInfo
+
+ mov r3, #0
+ str r3, [r1, #OFFSETOF__ExInfo__m_exception] // init the exception object to null
+ mov r3, #0xFFFFFFFF
+ str r3, [r1, #OFFSETOF__ExInfo__m_idxCurClause]
+
+ // link the ExInfo into the thread's ExInfo chain
+ ldr r3, [r0, #OFFSETOF__Thread__m_pExInfoStackHead] // r3 <- currently active ExInfo
+ str r3, [r1, #OFFSETOF__ExInfo__m_pPrevExInfo] // pExInfo->m_pPrevExInfo = m_pExInfoStackHead
+ str r1, [r0, #OFFSETOF__Thread__m_pExInfoStackHead] // m_pExInfoStackHead = pExInfo
-#ifdef _DEBUG
- GEN_ASSERT_FUNC RhpRethrowName
-#endif
+ // set the exception context field on the ExInfo
+ add r2, sp, #rsp_offsetof_Context // r2 <- PAL_LIMITED_CONTEXT*
+ str r2, [r1, #OFFSETOF__ExInfo__m_pExContext] // init ExInfo.m_pExContext
+
+ mov r0, r3
+ // r0 contains the currently active ExInfo
+ // r1 contains the address of the new ExInfo
+ blx C_FUNC(RhRethrow)
EXPORT_POINTER_TO_ADDRESS PointerToRhpRethrow2
// no return
- bkpt
+ EMIT_BREAKPOINT
NESTED_END RhpRethrow, _TEXT
-//
-// Prologue of all funclet calling helpers (RhpCallXXXXFunclet)
-//
-
-//
-// Epilogue of all funclet calling helpers (RhpCallXXXXFunclet)
-//
-
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
-// void* FASTCALL RhpCallCatchFunclet(RtuObjectRef exceptionObj, void* pHandlerIP, REGDISPLAY* pRegDisplay,
+// void* FASTCALL RhpCallCatchFunclet(RtuObjectRef exceptionObj,
+// void* pHandlerIP,
+// REGDISPLAY* pRegDisplay,
// ExInfo* pExInfo)
//
-// INPUT: RDI: exception object
-// RSI: handler funclet address
-// RDX: REGDISPLAY*
-// RCX: ExInfo*
+// INPUT: R0: exception object
+// R1: handler funclet address
+// R2: REGDISPLAY*
+// R3: ExInfo*
//
// OUTPUT:
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
NESTED_ENTRY RhpCallCatchFunclet, _TEXT, NoHandler
-ALTERNATE_ENTRY RhpCallCatchFunclet2
+ PROLOG_PUSH "{r0,r2-r11,lr}" // r0, r2 & r3 are saved so we have the exception object,
+ // REGDISPLAY and ExInfo later
+ PROLOG_VPUSH {d8-d15}
+
+#define rsp_offset_r2 (8 * 8) + 4
+#define rsp_offset_r3 (8 * 8) + 8
+
+ mov r4, r0 // Save exception object
+ mov r5, r1 // Save handler funclet address
+ mov r6, r2 // Save REGDISPLAY*
+
+ // Clear the DoNotTriggerGc state before calling out to our managed catch funclet,
+ // trashes r0-r2.
+ // r0 = GetThread()
+ INLINE_GETTHREAD
+
+LOCAL_LABEL(ClearRetry_Catch):
+ ldrex r1, [r0, #OFFSETOF__Thread__m_ThreadStateFlags]
+ bics r1, #TSF_DoNotTriggerGc
+ strex r2, r1, [r0, #OFFSETOF__Thread__m_ThreadStateFlags]
+ cbz r2, LOCAL_LABEL(ClearSuccess_Catch)
+ b LOCAL_LABEL(ClearRetry_Catch)
+LOCAL_LABEL(ClearSuccess_Catch):
+
+ mov r1, r4 // Reload exception object
+ mov r3, r5 // Reload handler funclet address
+ mov r2, r6 // Reload REGDISPLAY pointer
+
+ //
+ // set preserved regs to the values expected by the funclet
+ //
+ ldr r12, [r2, #OFFSETOF__REGDISPLAY__pR4]
+ ldr r4, [r12]
+ ldr r12, [r2, #OFFSETOF__REGDISPLAY__pR5]
+ ldr r5, [r12]
+ ldr r12, [r2, #OFFSETOF__REGDISPLAY__pR6]
+ ldr r6, [r12]
+ ldr r12, [r2, #OFFSETOF__REGDISPLAY__pR7]
+ ldr r7, [r12]
+ ldr r12, [r2, #OFFSETOF__REGDISPLAY__pR8]
+ ldr r8, [r12]
+ ldr r12, [r2, #OFFSETOF__REGDISPLAY__pR9]
+ ldr r9, [r12]
+ ldr r12, [r2, #OFFSETOF__REGDISPLAY__pR10]
+ ldr r10, [r12]
+ ldr r12, [r2, #OFFSETOF__REGDISPLAY__pR11]
+ ldr r11, [r12]
+
+ //
+ // load vfp preserved regs
+ //
+ add r12, r2, #OFFSETOF__REGDISPLAY__D
+ vldm r12!, {d8-d15}
+
+ ldr r0, [r2, #OFFSETOF__REGDISPLAY__SP] // r0 <- establisher frame
+ // r1 <- exception object
+ blx r3 // call handler funclet
+
+ mov r4, r0 // Save the result
+ EXPORT_POINTER_TO_ADDRESS PointerToRhpCallCatchFunclet2
-#ifdef _DEBUG
- GEN_ASSERT_FUNC RhpCallCatchFuncletName
-#endif
+ INLINE_GETTHREAD // r0 <- Thread*
+ // We must unhijack the thread at this point because the section of stack where the
+ // hijack is applied may go dead. If it does, then the next time we try to unhijack
+ // the thread, it will corrupt the stack.
+ INLINE_THREAD_UNHIJACK r0, r3, r12 // Thread in r0, trashes r3 and r1
+ ldr r2, [sp, #rsp_offset_r2] // r2 <- REGDISPLAY*
+ ldr r3, [sp, #rsp_offset_r3] // r3 <- current ExInfo*
+ ldr r2, [r2, #OFFSETOF__REGDISPLAY__SP] // r2 <- resume SP value
- EXPORT_POINTER_TO_ADDRESS PointerToRhpCallCatchFunclet2
+LOCAL_LABEL(PopExInfoLoop):
+ ldr r3, [r3, #OFFSETOF__ExInfo__m_pPrevExInfo] // r3 <- next ExInfo
+ cbz r3, LOCAL_LABEL(DonePopping) // if (pExInfo == null) { we're done }
+ cmp r3, r2
+ blt LOCAL_LABEL(PopExInfoLoop) // if (pExInfo < resume SP} { keep going }
+LOCAL_LABEL(DonePopping):
+
+ str r3, [r0, #OFFSETOF__Thread__m_pExInfoStackHead] // store the new head on the Thread
+
+ // reset RSP and jump to the continuation address
+ mov sp, r2
+ bx r4
NESTED_END RhpCallCatchFunclet, _TEXT
@@ -142,43 +338,155 @@ NESTED_END RhpCallCatchFunclet, _TEXT
//
// void FASTCALL RhpCallFinallyFunclet(void* pHandlerIP, REGDISPLAY* pRegDisplay)
//
-// INPUT: RDI: handler funclet address
-// RSI: REGDISPLAY*
+// INPUT: R0: handler funclet address
+// R1: REGDISPLAY*
//
// OUTPUT:
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
NESTED_ENTRY RhpCallFinallyFunclet, _TEXT, NoHandler
-ALTERNATE_ENTRY RhpCallFinallyFunclet2
-
-#ifdef _DEBUG
- GEN_ASSERT_FUNC RhpCallFinallyFuncletName
-#endif
+ PROLOG_PUSH "{r1,r4-r11,lr}" // r1 is saved so we have the REGDISPLAY later
+ PROLOG_VPUSH {d8-d15}
+#define rsp_offset_r1 8 * 8
+
+ //
+ // We want to suppress hijacking between invocations of subsequent finallys. We do
+ // this because we cannot tolerate a GC after one finally has run (and possibly
+ // side-effected the GC state of the method) and then been popped off the stack,
+ // leaving behind no trace of its effect.
+ //
+ // So we clear the state before and set it after invocation of the handler.
+ //
+
+ mov r4, r0 // Save handler funclet address
+ mov r5, r1 // Save REGDISPLAY*
+ //
+ // clear the DoNotTriggerGc flag, trashes r0-r2
+ //
+ INLINE_GETTHREAD // r0 <- Thread*
+
+LOCAL_LABEL(ClearRetry):
+ ldrex r1, [r0, #OFFSETOF__Thread__m_ThreadStateFlags]
+ bics r1, #TSF_DoNotTriggerGc
+ strex r2, r1, [r0, #OFFSETOF__Thread__m_ThreadStateFlags]
+ cbz r2, LOCAL_LABEL(ClearSuccess)
+ b LOCAL_LABEL(ClearRetry)
+LOCAL_LABEL(ClearSuccess):
+
+ mov r2, r4 // reload handler funclet address
+ mov r1, r5 // reload REGDISPLAY pointer
+
+ //
+ // set preserved regs to the values expected by the funclet
+ //
+ ldr r12, [r1, #OFFSETOF__REGDISPLAY__pR4]
+ ldr r4, [r12]
+ ldr r12, [r1, #OFFSETOF__REGDISPLAY__pR5]
+ ldr r5, [r12]
+ ldr r12, [r1, #OFFSETOF__REGDISPLAY__pR6]
+ ldr r6, [r12]
+ ldr r12, [r1, #OFFSETOF__REGDISPLAY__pR7]
+ ldr r7, [r12]
+ ldr r12, [r1, #OFFSETOF__REGDISPLAY__pR8]
+ ldr r8, [r12]
+ ldr r12, [r1, #OFFSETOF__REGDISPLAY__pR9]
+ ldr r9, [r12]
+ ldr r12, [r1, #OFFSETOF__REGDISPLAY__pR10]
+ ldr r10, [r12]
+ ldr r12, [r1, #OFFSETOF__REGDISPLAY__pR11]
+ ldr r11, [r12]
+
+ //
+ // load vfp preserved regs
+ //
+ add r12, r1, #OFFSETOF__REGDISPLAY__D
+ vldm r12!, {d8-d15}
+
+ ldr r0, [r1, #OFFSETOF__REGDISPLAY__SP] // r0 <- establisher frame
+ blx r2 // handler funclet address
EXPORT_POINTER_TO_ADDRESS PointerToRhpCallFinallyFunclet2
+ ldr r1, [sp, #rsp_offset_r1] // reload REGDISPLAY pointer
+
+ //
+ // save new values of preserved regs into REGDISPLAY
+ //
+ ldr r12, [r1, #OFFSETOF__REGDISPLAY__pR4]
+ str r4, [r12]
+ ldr r12, [r1, #OFFSETOF__REGDISPLAY__pR5]
+ str r5, [r12]
+ ldr r12, [r1, #OFFSETOF__REGDISPLAY__pR6]
+ str r6, [r12]
+ ldr r12, [r1, #OFFSETOF__REGDISPLAY__pR7]
+ str r7, [r12]
+ ldr r12, [r1, #OFFSETOF__REGDISPLAY__pR8]
+ str r8, [r12]
+ ldr r12, [r1, #OFFSETOF__REGDISPLAY__pR9]
+ str r9, [r12]
+ ldr r12, [r1, #OFFSETOF__REGDISPLAY__pR10]
+ str r10, [r12]
+ ldr r12, [r1, #OFFSETOF__REGDISPLAY__pR11]
+ str r11, [r12]
+
+ //
+ // store vfp preserved regs
+ //
+ add r12, r1, #OFFSETOF__REGDISPLAY__D
+ vstm r12!, {d8-d15}
+
+ //
+ // set the DoNotTriggerGc flag, trashes r0-r2
+ //
+ INLINE_GETTHREAD // r0 <- Thread*
+LOCAL_LABEL(SetRetry):
+ ldrex r1, [r0, #OFFSETOF__Thread__m_ThreadStateFlags]
+ orrs r1, #TSF_DoNotTriggerGc
+ strex r2, r1, [r0, #OFFSETOF__Thread__m_ThreadStateFlags]
+ cbz r2, LOCAL_LABEL(SetSuccess)
+ b LOCAL_LABEL(SetRetry)
+LOCAL_LABEL(SetSuccess):
+
+ EPILOG_VPOP {d8-d15}
+ EPILOG_POP "{r1,r4-r11,pc}"
+
NESTED_END RhpCallFinallyFunclet, _TEXT
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// void* FASTCALL RhpCallFilterFunclet(RtuObjectRef exceptionObj, void* pFilterIP, REGDISPLAY* pRegDisplay)
//
-// INPUT: RDI: exception object
-// RSI: filter funclet address
-// RDX: REGDISPLAY*
+// INPUT: R0: exception object
+// R1: filter funclet address
+// R2: REGDISPLAY*
//
// OUTPUT:
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
NESTED_ENTRY RhpCallFilterFunclet, _TEXT, NoHandler
-ALTERNATE_ENTRY RhpCallFilterFunclet2
+ PROLOG_PUSH "{r4-r11,lr}"
+ PROLOG_VPUSH {d8-d15}
+
+ ldr r12, [r2, #OFFSETOF__REGDISPLAY__pR7]
+ ldr r7, [r12]
+
+ mov r12, r1 // r12 <- handler funclet address
+ mov r1, r0 // r1 <- exception object
+ ldr r0, [r2, #OFFSETOF__REGDISPLAY__SP] // r0 <- establisher frame
-#ifdef _DEBUG
- GEN_ASSERT_FUNC RhpCallFilterFuncletName
-#endif
+ //
+ // call the funclet
+ // r0 = establisher frame
+ // r1 = exception object
+ blx r12
EXPORT_POINTER_TO_ADDRESS PointerToRhpCallFilterFunclet2
+ // R0 contains the result of the filter execution
+
+ EPILOG_VPOP {d8-d15}
+ EPILOG_POP "{r4-r11,pc}"
+
NESTED_END RhpCallFilterFunclet, _TEXT