diff options
author | sergey ignatov <sergign60@mail.ru> | 2017-07-19 00:34:06 +0300 |
---|---|---|
committer | Jan Kotas <jkotas@microsoft.com> | 2017-07-19 00:34:06 +0300 |
commit | 7d84a06eedf4076206cd56a66bddd4da353f170b (patch) | |
tree | c8c799526c70d4aaca4052f1829b4fa50c036042 /src/Native/Runtime/arm | |
parent | d5c4c61239ac7c1960db6103e1e3f0742e5d8ca8 (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.S | 3 | ||||
-rw-r--r-- | src/Native/Runtime/arm/CallingConventionConverterHelpers.S | 62 | ||||
-rw-r--r-- | src/Native/Runtime/arm/ExceptionHandling.S | 450 |
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 |