// 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 I2NStubFrameSize (8 * 30)
#define CALLEE_ADDR %r8
#define THREAD_LOCAL_DATA %r9

// Frame layout (offsets from rbp):
//   rbp - 8:    rdi (arg1)
//   rbp - 16:   rsi (arg2)
//   rbp - 24:   rdx (arg3)
//   rbp - 32:   rcx (arg4)
//   rbp - 40:   CALLEE_ADDR (r8, arg5)
//   rbp - 48:   THREAD_LOCAL_DATA (r9, arg6)
//   rbp - 56:   rax (varargs vector register count)
//   (8 bytes padding for xmm alignment)
//   rbp - 80:   xmm0 (16 bytes)
//   rbp - 96:   xmm1 (16 bytes)
//   rbp - 112:  xmm2 (16 bytes)
//   rbp - 128:  xmm3 (16 bytes)
//   rbp - 144:  xmm4 (16 bytes)
//   rbp - 160:  xmm5 (16 bytes)
//   rbp - 176:  xmm6 (16 bytes)
//   rbp - 192:  xmm7 (16 bytes)
//   rbp - 200:  rax (return value)
//   rbp - 208:  rdx (return value)
//   rbp - 224:  xmm0 (return value, 16 bytes)
//   rbp - 240:  xmm1 (return value, 16 bytes)

    .text
    .align 2
    .global CJ_MCC_I2NStub
    .type CJ_MCC_I2NStub, @function
CJ_MCC_I2NStub:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register %rbp
    subq    $I2NStubFrameSize, %rsp

    // Save integer argument registers
    movq    %rdi, -8(%rbp)
    movq    %rsi, -16(%rbp)
    movq    %rdx, -24(%rbp)
    movq    %rcx, -32(%rbp)
    movq    CALLEE_ADDR, -40(%rbp)
    movq    THREAD_LOCAL_DATA, -48(%rbp)
    movq    %rax, -56(%rbp)

    // Save floating-point argument registers
    movapd  %xmm0, -80(%rbp)
    movapd  %xmm1, -96(%rbp)
    movapd  %xmm2, -112(%rbp)
    movapd  %xmm3, -128(%rbp)
    movapd  %xmm4, -144(%rbp)
    movapd  %xmm5, -160(%rbp)
    movapd  %xmm6, -176(%rbp)
    movapd  %xmm7, -192(%rbp)

    // SaveC2NContext(pc, fa, threadLocalData)
    call    .L_current_pc
.L_current_pc:
    popq    %rdi
    movq    %rbp, %rsi
    movq    -48(%rbp), %rdx
    callq   MRT_SaveC2NContext@PLT

    // EnterSaferegion(false)
    movq    $0, %rdi
    callq   MRT_EnterSaferegion@PLT

    // Restore argument registers
    movq    -8(%rbp), %rdi
    movq    -16(%rbp), %rsi
    movq    -24(%rbp), %rdx
    movq    -32(%rbp), %rcx
    movq    -56(%rbp), %rax

    // Restore floating-point argument registers
    movapd  -80(%rbp), %xmm0
    movapd  -96(%rbp), %xmm1
    movapd  -112(%rbp), %xmm2
    movapd  -128(%rbp), %xmm3
    movapd  -144(%rbp), %xmm4
    movapd  -160(%rbp), %xmm5
    movapd  -176(%rbp), %xmm6
    movapd  -192(%rbp), %xmm7

    // Call callee
    movq    -40(%rbp), %r10
    callq   *%r10

    // Save return values
    movq    %rax, -200(%rbp)
    movq    %rdx, -208(%rbp)
    movapd  %xmm0, -224(%rbp)
    movapd  %xmm1, -240(%rbp)

    // LeaveSaferegion()
    callq   MRT_LeaveSaferegion@PLT

    // DeleteC2NContext(threadLocalData)
    movq    -48(%rbp), %rdi
    callq   MRT_DeleteC2NContext@PLT

    // ThrowPendingException(nullptr)
    movq    $0, %rdi
    callq   MRT_ThrowPendingException@PLT

    // Restore return values.
    movq    -200(%rbp), %rax
    movq    -208(%rbp), %rdx
    movapd  -224(%rbp), %xmm0
    movapd  -240(%rbp), %xmm1

    movq    %rbp, %rsp
    popq    %rbp
    .cfi_def_cfa %rsp, 8
    retq
    .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