// Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
// This source file is part of the Cangjie project, licensed under Apache-2.0
// with Runtime Library Exception.
//
// See https://cangjie-lang.cn/pages/LICENSE for license information.

// The Cangjie API is in Beta. For details on its capabilities and limitations, please refer to the README file.

#define cfi_adjust_cfa_offset(off)      .cfi_adjust_cfa_offset off
#define cfi_rel_offset(reg, off)        .cfi_rel_offset reg, off
#define cfi_restore(reg)                .cfi_restore reg
#define cfi_def_cfa_register(reg)       .cfi_def_cfa_register reg

#define I2NStubFrameSize                (8 * 24)

// Frame layout after
//     stp x29, x30, [sp, #-I2NStubFrameSize]!
//     mov x29, sp
//
//                  | ...                       |
//                  | caller frame              |
//                  | saved x30                 |
//                  | caller-saved x29          |
//   stub x29 -->   | stub-saved x29 (prev fp)  | [x29 + 0x00]
//                  | saved x30                 | [x29 + 0x08]
//                  | saved x28                 | [x29 + 0x10]
//                  | callee (x4) / ret x8      | [x29 + 0x18]
//                  | arg0 (x0) / ret x0        | [x29 + 0x20]
//                  | arg1 (x1) / ret x1        | [x29 + 0x28]
//                  | arg2 (x2) / ret x2        | [x29 + 0x30]
//                  | arg3 (x3) / ret x3        | [x29 + 0x38]
//                  | q0 save area / ret d0-d3  | [x29 + 0x40]
//                  | q1 save area              |
//                  | q2 save area              | [x29 + 0x60]
//                  | q3 save area              |
//                  | q4 save area              | [x29 + 0x80]
//                  | q5 save area              |
//                  | q6 save area              | [x29 + 0xA0]
//                  | q7 save area              |
//   stub sp -->    | ...                       |

    .text
    .align 2
    .global CJ_MCC_I2NStub
    .type CJ_MCC_I2NStub, @function
CJ_MCC_I2NStub:
    .cfi_startproc
#if defined(ENABLE_BACKWARD_PTRAUTH_CFI)
    paciasp
#endif
    stp  x29, x30, [sp, #-I2NStubFrameSize]!
    cfi_adjust_cfa_offset (I2NStubFrameSize)
    cfi_rel_offset (x29, 0)
    cfi_rel_offset (x30, 8)
    mov  x29, sp
    cfi_def_cfa_register (x29)

    str  x28, [sp, #0x10]
    cfi_rel_offset (x28, 0x10)

    // Save integer argument registers.
    str  x4, [sp, #0x18]
    stp  x0, x1, [sp, #0x20]
    stp  x2, x3, [sp, #0x30]

    // Save floating-point argument registers.
    stp  q0, q1, [sp, #0x40]
    stp  q2, q3, [sp, #0x60]
    stp  q4, q5, [sp, #0x80]
    stp  q6, q7, [sp, #0xA0]

    // Keep thread-local data in x28 for transition calls.
    mov  x28, x5

    // SaveC2NContext(pc, fa, threadLocalData).
    mov  x1, x29
    adr  x0, .L_unwind_pc
.L_unwind_pc:
    mov  x2, x28
    bl   MRT_SaveC2NContext

    // EnterSaferegion(false).
    mov  x0, #0
    bl   MRT_EnterSaferegion

    // Restore argument registers.
    ldp  x0, x1, [sp, #0x20]
    ldp  x2, x3, [sp, #0x30]

    // Restore floating-point argument registers.
    ldp  q0, q1, [sp, #0x40]
    ldp  q2, q3, [sp, #0x60]
    ldp  q4, q5, [sp, #0x80]
    ldp  q6, q7, [sp, #0xA0]

    // Call callee.
    ldr  x9, [sp, #0x18]
    blr  x9

    // Save potential return values.
    stp  x0, x1, [sp, #0x20]
    stp  x2, x3, [sp, #0x30]
    str  x8, [sp, #0x18]
    stp  d0, d1, [sp, #0x40]
    stp  d2, d3, [sp, #0x50]

    // LeaveSaferegion().
    bl   MRT_LeaveSaferegion

    // DeleteC2NContext(threadLocalData). x28 carries current thread-local data.
    mov  x0, x28
    bl   MRT_DeleteC2NContext

    // ThrowPendingException(nullptr).
    mov  x0, #0
    bl   MRT_ThrowPendingException

    // Restore return values.
    ldp  x0, x1, [sp, #0x20]
    ldp  x2, x3, [sp, #0x30]
    ldr  x8, [sp, #0x18]
    ldp  d0, d1, [sp, #0x40]
    ldp  d2, d3, [sp, #0x50]

    ldr  x28, [sp, #0x10]
    cfi_restore (x28)
    ldp  x29, x30, [sp], #I2NStubFrameSize
    cfi_adjust_cfa_offset (-I2NStubFrameSize)
    cfi_restore (x29)
    cfi_restore (x30)
#if defined(ENABLE_BACKWARD_PTRAUTH_CFI)
    autiasp
#endif
    ret
    .cfi_endproc
    .size CJ_MCC_I2NStub, .-CJ_MCC_I2NStub

    .global CJ_MCC_I2NStubEnd
    .type CJ_MCC_I2NStubEnd, @function
CJ_MCC_I2NStubEnd:
    nop
    .size CJ_MCC_I2NStubEnd, .-CJ_MCC_I2NStubEnd