1;; Licensed to the .NET Foundation under one or more agreements. 2;; The .NET Foundation licenses this file to you under the MIT license. 3;; See the LICENSE file in the project root for more information. 4 5include AsmMacros.inc 6 7ifdef FEATURE_DYNAMIC_CODE 8 9ifdef _DEBUG 10TRASH_SAVED_ARGUMENT_REGISTERS equ 1 11else 12TRASH_SAVED_ARGUMENT_REGISTERS equ 0 13endif 14 15if TRASH_SAVED_ARGUMENT_REGISTERS ne 0 16EXTERN RhpIntegerTrashValues : QWORD 17EXTERN RhpFpTrashValues : QWORD 18endif ;; TRASH_SAVED_ARGUMENT_REGISTERS 19 20SIZEOF_RETADDR equ 8h 21 22SIZEOF_ALIGNMENT_PADDING equ 8h 23 24SIZEOF_RETURN_BLOCK equ 10h ; for 16 bytes of conservatively reported space that the callee can 25 ; use to manage the return value that the call eventually generates 26 27SIZEOF_FP_REGS equ 40h ; xmm0-3 28 29SIZEOF_OUT_REG_HOMES equ 20h ; Callee register spill 30 31; 32; From CallerSP to ChildSP, the stack frame is composed of the following adjacent regions: 33; 34; SIZEOF_RETADDR 35; SIZEOF_ALIGNMENT_PADDING 36; SIZEOF_RETURN_BLOCK 37; SIZEOF_FP_REGS 38; SIZEOF_OUT_REG_HOMES 39; 40 41DISTANCE_FROM_CHILDSP_TO_FP_REGS equ SIZEOF_OUT_REG_HOMES 42 43DISTANCE_FROM_CHILDSP_TO_RETURN_BLOCK equ DISTANCE_FROM_CHILDSP_TO_FP_REGS + SIZEOF_FP_REGS 44 45DISTANCE_FROM_CHILDSP_TO_RETADDR equ DISTANCE_FROM_CHILDSP_TO_RETURN_BLOCK + SIZEOF_RETURN_BLOCK + SIZEOF_ALIGNMENT_PADDING 46 47DISTANCE_FROM_CHILDSP_TO_CALLERSP equ DISTANCE_FROM_CHILDSP_TO_RETADDR + SIZEOF_RETADDR 48 49.errnz DISTANCE_FROM_CHILDSP_TO_CALLERSP mod 16 50 51;; 52;; Defines an assembly thunk used to make a transition from managed code to a callee, 53;; then (based on the return value from the callee), either returning or jumping to 54;; a new location while preserving the input arguments. The usage of this thunk also 55;; ensures arguments passed are properly reported. 56;; 57;; TODO: This code currently only tailcalls, and does not return. 58;; 59;; Inputs: 60;; rcx, rdx, r8, r9, stack space: arguments as normal 61;; r10: The location of the target code the UniversalTransition thunk will call 62;; r11: The only parameter to the target function (passed in rdx to callee) 63;; 64 65; 66; Frame layout is: 67; 68; {StackPassedArgs} ChildSP+0a0 CallerSP+020 69; {IntArgRegs (rcx,rdx,r8,r9) (0x20 bytes)} ChildSP+080 CallerSP+000 70; {CallerRetaddr} ChildSP+078 CallerSP-008 71; {AlignmentPad (0x8 bytes)} ChildSP+070 CallerSP-010 72; {ReturnBlock (0x10 bytes)} ChildSP+060 CallerSP-020 73; {FpArgRegs (xmm0-xmm3) (0x40 bytes)} ChildSP+020 CallerSP-060 74; {CalleeArgumentHomes (0x20 bytes)} ChildSP+000 CallerSP-080 75; {CalleeRetaddr} ChildSP-008 CallerSP-088 76; 77; NOTE: If the frame layout ever changes, the C++ UniversalTransitionStackFrame structure 78; must be updated as well. 79; 80; NOTE: The callee receives a pointer to the base of the ReturnBlock, and the callee has 81; knowledge of the exact layout of all pieces of the frame that lie at or above the pushed 82; FpArgRegs. 83; 84; NOTE: The stack walker guarantees that conservative GC reporting will be applied to 85; everything between the base of the ReturnBlock and the top of the StackPassedArgs. 86; 87 88UNIVERSAL_TRANSITION macro FunctionName 89 90NESTED_ENTRY Rhp&FunctionName, _TEXT 91 92 alloc_stack DISTANCE_FROM_CHILDSP_TO_RETADDR 93 94 save_reg_postrsp rcx, 0h + DISTANCE_FROM_CHILDSP_TO_CALLERSP 95 save_reg_postrsp rdx, 8h + DISTANCE_FROM_CHILDSP_TO_CALLERSP 96 save_reg_postrsp r8, 10h + DISTANCE_FROM_CHILDSP_TO_CALLERSP 97 save_reg_postrsp r9, 18h + DISTANCE_FROM_CHILDSP_TO_CALLERSP 98 99 save_xmm128_postrsp xmm0, DISTANCE_FROM_CHILDSP_TO_FP_REGS 100 save_xmm128_postrsp xmm1, DISTANCE_FROM_CHILDSP_TO_FP_REGS + 10h 101 save_xmm128_postrsp xmm2, DISTANCE_FROM_CHILDSP_TO_FP_REGS + 20h 102 save_xmm128_postrsp xmm3, DISTANCE_FROM_CHILDSP_TO_FP_REGS + 30h 103 104 END_PROLOGUE 105 106if TRASH_SAVED_ARGUMENT_REGISTERS ne 0 107 108 ; Before calling out, trash all of the argument registers except the ones (rcx, rdx) that 109 ; hold outgoing arguments. All of these registers have been saved to the transition 110 ; frame, and the code at the call target is required to use only the transition frame 111 ; copies when dispatching this call to the eventual callee. 112 113 movsd xmm0, mmword ptr [RhpFpTrashValues + 0h] 114 movsd xmm1, mmword ptr [RhpFpTrashValues + 8h] 115 movsd xmm2, mmword ptr [RhpFpTrashValues + 10h] 116 movsd xmm3, mmword ptr [RhpFpTrashValues + 18h] 117 118 mov r8, qword ptr [RhpIntegerTrashValues + 10h] 119 mov r9, qword ptr [RhpIntegerTrashValues + 18h] 120 121endif ; TRASH_SAVED_ARGUMENT_REGISTERS 122 123 ; 124 ; Call out to the target, while storing and reporting arguments to the GC. 125 ; 126 mov rdx, r11 127 lea rcx, [rsp + DISTANCE_FROM_CHILDSP_TO_RETURN_BLOCK] 128 call r10 129 130 EXPORT_POINTER_TO_ADDRESS PointerToReturnFrom&FunctionName 131 132 ; We cannot make the label public as that tricks DIA stackwalker into thinking 133 ; it's the beginning of a method. For this reason we export the address 134 ; by means of an auxiliary variable. 135 136 ; restore fp argument registers 137 movdqa xmm0, [rsp + DISTANCE_FROM_CHILDSP_TO_FP_REGS ] 138 movdqa xmm1, [rsp + DISTANCE_FROM_CHILDSP_TO_FP_REGS + 10h] 139 movdqa xmm2, [rsp + DISTANCE_FROM_CHILDSP_TO_FP_REGS + 20h] 140 movdqa xmm3, [rsp + DISTANCE_FROM_CHILDSP_TO_FP_REGS + 30h] 141 142 ; restore integer argument registers 143 mov rcx, [rsp + 0h + DISTANCE_FROM_CHILDSP_TO_CALLERSP] 144 mov rdx, [rsp + 8h + DISTANCE_FROM_CHILDSP_TO_CALLERSP] 145 mov r8, [rsp + 10h + DISTANCE_FROM_CHILDSP_TO_CALLERSP] 146 mov r9, [rsp + 18h + DISTANCE_FROM_CHILDSP_TO_CALLERSP] 147 148 ; epilog 149 nop 150 151 ; Pop the space that was allocated between the ChildSP and the caller return address. 152 add rsp, DISTANCE_FROM_CHILDSP_TO_RETADDR 153 154 TAILJMP_RAX 155 156NESTED_END Rhp&FunctionName, _TEXT 157 158 endm 159 160 ; To enable proper step-in behavior in the debugger, we need to have two instances 161 ; of the thunk. For the first one, the debugger steps into the call in the function, 162 ; for the other, it steps over it. 163 UNIVERSAL_TRANSITION UniversalTransition 164 UNIVERSAL_TRANSITION UniversalTransition_DebugStepTailCall 165 166endif 167 168end 169