;; Licensed to the .NET Foundation under one or more agreements. ;; The .NET Foundation licenses this file to you under the MIT license. ;; See the LICENSE file in the project root for more information. #include "AsmMacros.h" TEXTAREA ;;----------------------------------------------------------------------------- ;; This helper routine enregisters the appropriate arguments and makes the ;; actual call. ;; ;; INPUT: x0: pointer to CallDescrData struct ;; ;;----------------------------------------------------------------------------- ;;void RhCallDescrWorker(CallDescrData * pCallDescrData); NESTED_ENTRY RhCallDescrWorker PROLOG_SAVE_REG_PAIR fp, lr, #-32! PROLOG_SAVE_REG_PAIR x19, x20, #16 ;; Save the value of SP before we start pushing any arguments mov x20, sp mov x19, x0 ; save pCallDescrData in x19 ldr w1, [x19, #OFFSETOF__CallDescrData__numStackSlots] cbz w1, Ldonestack ;; Add frame padding to ensure frame size is a multiple of 16 (a requirement of the OS ABI). ;; We push two registers (above) and numStackSlots arguments (below). If this comes to an odd number ;; of slots we must pad with another. This simplifies to "if the low bit of numStackSlots is set, ;; extend the stack another eight bytes". ldr x0, [x19, #OFFSETOF__CallDescrData__pSrc] add x0, x0, x1 lsl #3 ; pSrcEnd=pSrc+8*numStackSlots ands x2, x1, #1 beq Lstackloop ;; This loop copies numStackSlots words ;; from [pSrcEnd-8,pSrcEnd-16,...] to [sp-8,sp-16,...] ;; Pad and store one stack slot as number of slots are odd ldr x4, [x0,#-8]! str x4, [sp,#-16]! subs x1, x1, #1 beq Ldonestack Lstackloop ldp x2, x4, [x0,#-16]! stp x2, x4, [sp,#-16]! subs x1, x1, #2 bne Lstackloop Ldonestack ;; If FP arguments are supplied in registers (x9 != NULL) then initialize all of them from the pointer ;; given in x9. ldr x9, [x19, #OFFSETOF__CallDescrData__pFloatArgumentRegisters] cbz x9, LNoFloatingPoint ldp d0, d1, [x9] ldp d2, d3, [x9, #16] ldp d4, d5, [x9, #32] ldp d6, d7, [x9, #48] LNoFloatingPoint ;; Copy [pArgumentRegisters, ..., pArgumentRegisters + 64] ;; into x0, ..., x7, x8 ldr x9, [x19, #OFFSETOF__CallDescrData__pArgumentRegisters] ldp x0, x1, [x9] ldp x2, x3, [x9, #16] ldp x4, x5, [x9, #32] ldp x6, x7, [x9, #48] ldr x8, [x9, #64] ;; call pTarget ldr x9, [x19, #OFFSETOF__CallDescrData__pTarget] blr x9 EXPORT_POINTER_TO_ADDRESS PointerToReturnFromCallDescrThunk ;; Symbol used to identify thunk call to managed function so the special ;; case unwinder can unwind through this function. Sadly we cannot directly ;; export this symbol right now because it confuses DIA unwinder to believe ;; it's the beginning of a new method, therefore we export the address ;; of an auxiliary variable holding the address instead. ldr w3, [x19, #OFFSETOF__CallDescrData__fpReturnSize] ;; Unlike desktop returnValue is a pointer to a return buffer, not the buffer itself ldr x19, [x19, #OFFSETOF__CallDescrData__pReturnBuffer] ;; Int return case cbz w3, LIntReturn ;; Float return case cmp w3, #4 beq LFloatOrDoubleReturn ;; Double return case cmp w3, #8 bne LCheckHFAReturn LFloatOrDoubleReturn str d0, [x19] b LReturnDone LCheckHFAReturn cmp w3, #16 beq LFloatOrDoubleHFAReturn cmp w3, #32 beq LFloatOrDoubleHFAReturn b LNoHFAReturn LFloatOrDoubleHFAReturn ;;Single/Double HFAReturn return case stp d0, d1, [x19, #00] stp d2, d3, [x19, #16] b LReturnDone LNoHFAReturn EMIT_BREAKPOINT ; Unreachable LIntReturn ;; Save return value(s) into retbuf for int stp x0, x1, [x19] LReturnDone #ifdef _DEBUG ;; Trash the floating point registers to ensure that the HFA return values ;; won't survive by accident ldp d0, d1, [sp] ldp d2, d3, [sp, #16] #endif ;; Restore the value of SP mov sp, x20 EPILOG_RESTORE_REG_PAIR x19, x20, #16 EPILOG_RESTORE_REG_PAIR fp, lr, #32! EPILOG_RETURN NESTED_END RhCallDescrWorker END