Repository: dotnet/runtime
File: src/coreclr/nativeaot/Runtime/arm/GcProbe.S (Assembly)

Code before:
    PROLOG_PUSH         "{r4-r10}"          // Save non-volatile registers
    PROLOG_STACK_ALLOC  8                   // Space for flags and Thread*
    PROLOG_PUSH         "{r11,lr}"          // Save caller's frame pointer and return address

    str         \threadReg, [sp, #OFFSETOF__PInvokeTransitionFrame__m_pThread]
    mov         \trashReg, \BITMASK
    str         \trashReg, [sp, #OFFSETOF__PInvokeTransitionFrame__m_Flags]

    // Compute SP value at entry to this method and save it in slot of the frame.
    add         \trashReg, sp, #(16 * 4 + 4 * 8)
    str         \trashReg, [sp, #(11 * 4)]

    // Link the frame into the Thread
    str         sp, [\threadReg, #OFFSETOF__Thread__m_pDeferredTransitionFrame]
.endm

//
// Remove the frame from a previous call to PUSH_PROBE_FRAME from the top of the stack and restore preserved
// registers and return value to their values from before the probe was called (while also updating any
// object refs or byrefs).
//
.macro POP_PROBE_FRAME
    EPILOG_POP          "{r11,lr}"          // Restore caller's frame pointer and return address
    EPILOG_STACK_FREE   8                   // Discard flags and Thread*
    EPILOG_POP          "{r4-r10}"          // Restore non-volatile registers
    EPILOG_STACK_FREE   4                   // Discard caller's SP
    EPILOG_POP          "{r0-r3}"           // Restore return registers (r0-r2), r3 was for alignment
    EPILOG_VPOP         "{d0-d3}"           // Restore d0-d3 which can have the floating point return value
.endm

//
// The prolog for all GC suspension hijacks (normal and stress). Fixes up the hijacked return address, and
// clears the hijack state.
//
// Register state on entry:
//  All registers correct for return to the original return address.
//
// Register state on exit:
//  r3: thread pointer
//  r0, r1, r2: preserved, other volatile regs trashed
//
.macro FixupHijackedCallstack
    push        {r0, r1, r2}

    // align stack to 8 bytes
    sub         sp, sp, #4

    // r0 <- GetThread()
    INLINE_GETTHREAD

    mov         r3, r0

Review comment (suggestion):
```suggestion
    EPILOG_STACK_FREE   8                   // Discard caller's SP and alignment
```

Code after:
    PROLOG_PUSH         "{r4-r10}"          // Save non-volatile registers
    PROLOG_STACK_ALLOC  8                   // Space for flags and Thread*
    PROLOG_PUSH         "{r11,lr}"          // Save caller's frame pointer and return address

    str         \threadReg, [sp, #OFFSETOF__PInvokeTransitionFrame__m_pThread]
    mov         \trashReg, \BITMASK
    str         \trashReg, [sp, #OFFSETOF__PInvokeTransitionFrame__m_Flags]

    // Compute SP value at entry to this method and save it in slot of the frame.
    add         \trashReg, sp, #(16 * 4 + 4 * 8)
    str         \trashReg, [sp, #(11 * 4)]

    // Link the frame into the Thread
    str         sp, [\threadReg, #OFFSETOF__Thread__m_pDeferredTransitionFrame]
.endm

//
// Remove the frame from a previous call to PUSH_PROBE_FRAME from the top of the stack and restore preserved
// registers and return value to their values from before the probe was called (while also updating any
// object refs or byrefs).
//
.macro POP_PROBE_FRAME
    EPILOG_POP          "{r11,lr}"          // Restore caller's frame pointer and return address
    EPILOG_STACK_FREE   8                   // Discard flags and Thread*
    EPILOG_POP          "{r4-r10}"          // Restore non-volatile registers
    EPILOG_STACK_FREE   8                   // Discard caller's SP and alignment
    EPILOG_POP          "{r0-r2}"           // Restore return registers (r0-r2)
    EPILOG_VPOP         "{d0-d3}"           // Restore d0-d3 which can have the floating point return value
.endm

//
// The prolog for all GC suspension hijacks (normal and stress). Fixes up the hijacked return address, and
// clears the hijack state.
//
// Register state on entry:
//  All registers correct for return to the original return address.
//
// Register state on exit:
//  r3: thread pointer
//  r0, r1, r2: preserved, other volatile regs trashed
//
.macro FixupHijackedCallstack
    push        {r0, r1, r2}

    // align stack to 8 bytes
    sub         sp, sp, #4

    // r0 <- GetThread()
    INLINE_GETTHREAD

    mov         r3, r0