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

Code before:
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

.syntax unified
.thumb

#include <unixasmmacros.inc>
#include "AsmOffsets.inc"

.global RhpGcPoll2
.global RhpThrowHwEx

// See PUSH_COOP_PINVOKE_FRAME, this macro is very similar, but also saves return registers
// and accepts the register bitmask
// Call this macro first in the method (no further prolog instructions can be added after this).
//
//  threadReg     : register containing the Thread* (this will be preserved).
//  trashReg      : register that can be trashed by this macro
//  BITMASK       : value to initialize m_dwFlags field with (register or #constant)
.macro PUSH_PROBE_FRAME threadReg, trashReg, BITMASK
    // Define the method prolog, allocating enough stack space for the PInvokeTransitionFrame and saving
    // incoming register values into it.
    PROLOG_VPUSH        "{d0-d3}"           // Save d0-d3 which can have the floating point return value
    PROLOG_PUSH         "{r0-r3}"           // Save return registers (r0-r2) and r3 for alignment
    PROLOG_STACK_ALLOC  4                   // Space for caller's SP
    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

Review comment (suggestion):
```suggestion
    PROLOG_PUSH         "{r0-r2}"           // Save return registers (r0-r2)
    PROLOG_STACK_ALLOC  8                   // Space for caller's SP and alignment
```
Nit: Actually, not that I am looking at this again. It makes more sense to include the alignment in the stackalloc

Code after:
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

.syntax unified
.thumb

#include <unixasmmacros.inc>
#include "AsmOffsets.inc"

.global RhpGcPoll2
.global RhpThrowHwEx

// See PUSH_COOP_PINVOKE_FRAME, this macro is very similar, but also saves return registers
// and accepts the register bitmask
// Call this macro first in the method (no further prolog instructions can be added after this).
//
//  threadReg     : register containing the Thread* (this will be preserved).
//  trashReg      : register that can be trashed by this macro
//  BITMASK       : value to initialize m_dwFlags field with (register or #constant)
.macro PUSH_PROBE_FRAME threadReg, trashReg, BITMASK
    // Define the method prolog, allocating enough stack space for the PInvokeTransitionFrame and saving
    // incoming register values into it.
    PROLOG_VPUSH        "{d0-d3}"           // Save d0-d3 which can have the floating point return value
    PROLOG_PUSH         "{r0-r2}"           // Save return registers (r0-r2)
    PROLOG_STACK_ALLOC  8                   // Space for caller's SP and alignment
    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