Welcome to mirror list, hosted at ThFree Co, Russian Federation.

UniversalTransition.asm « arm64 « Runtime « Native « src - github.com/mono/corert.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: dc699ebed4bfda7e4d16d273d1a3664f75b6c2b4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
;; 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"

#ifdef _DEBUG
#define TRASH_SAVED_ARGUMENT_REGISTERS
#endif

#ifdef TRASH_SAVED_ARGUMENT_REGISTERS
    EXTERN RhpIntegerTrashValues
    EXTERN RhpFpTrashValues
#endif ;; TRASH_SAVED_ARGUMENT_REGISTERS

;; Padding to account for the odd number of saved integer registers
#define ALIGNMENT_PADDING_SIZE (8)

#define COUNT_ARG_REGISTERS (9)
#define INTEGER_REGISTER_SIZE (8)
#define ARGUMENT_REGISTERS_SIZE (COUNT_ARG_REGISTERS * INTEGER_REGISTER_SIZE)

;; Largest return block is 4 doubles
#define RETURN_BLOCK_SIZE (32) 

#define COUNT_FLOAT_ARG_REGISTERS (8)
#define FLOAT_REGISTER_SIZE (8)
#define FLOAT_ARG_REGISTERS_SIZE (COUNT_FLOAT_ARG_REGISTERS * FLOAT_REGISTER_SIZE)

#define PUSHED_LR_SIZE (8)
#define PUSHED_FP_SIZE (8)

;;
;; From CallerSP to ChildSP, the stack frame is composed of the following adjacent regions:
;;
;;      ALIGNMENT_PADDING_SIZE
;;      ARGUMENT_REGISTERS_SIZE
;;      RETURN_BLOCK_SIZE
;;      FLOAT_ARG_REGISTERS_SIZE
;;      PUSHED_LR_SIZE
;;      PUSHED_FP_SIZE
;;

#define DISTANCE_FROM_CHILDSP_TO_RETURN_BLOCK (PUSHED_FP_SIZE + PUSHED_LR_SIZE + FLOAT_ARG_REGISTERS_SIZE)

#define STACK_SIZE (ALIGNMENT_PADDING_SIZE + ARGUMENT_REGISTERS_SIZE + RETURN_BLOCK_SIZE + FLOAT_ARG_REGISTERS_SIZE + \
    PUSHED_LR_SIZE + PUSHED_FP_SIZE)

#define FLOAT_ARG_OFFSET (PUSHED_FP_SIZE + PUSHED_LR_SIZE)
#define ARGUMENT_REGISTERS_OFFSET (FLOAT_ARG_OFFSET + FLOAT_ARG_REGISTERS_SIZE + RETURN_BLOCK_SIZE)

;;
;; RhpUniversalTransition
;; 
;; At input to this function, x0-8, d0-7 and the stack may contain any number of arguments.
;;
;; In addition, there are 2 extra arguments passed in the intra-procedure-call scratch register:
;;  xip0 will contain the managed function that is to be called by this transition function
;;  xip1 will contain the pointer sized extra argument to the managed function
;;
;; When invoking the callee:
;;
;;  x0 shall contain a pointer to the TransitionBlock
;;  x1 shall contain the value that was in xip1 at entry to this function
;;
;; Frame layout is:
;;
;;  {StackPassedArgs}                           ChildSP+0C0     CallerSP+000
;;  {AlignmentPad (0x8 bytes)}                  ChildSP+0B8     CallerSP-008
;;  {IntArgRegs (x0-x8) (0x48 bytes)}           ChildSP+070     CallerSP-050
;;  {ReturnBlock (0x20 bytes)}                  ChildSP+050     CallerSP-070
;;   -- The base address of the Return block is the TransitionBlock pointer, the floating point args are
;;      in the neg space of the TransitionBlock pointer.  Note that the callee has knowledge of the exact
;;      layout of all pieces of the frame that lie at or above the pushed floating point registers.
;;  {FpArgRegs (d0-d7) (0x40 bytes)}            ChildSP+010     CallerSP-0B0
;;  {PushedLR}                                  ChildSP+008     CallerSP-0B8
;;  {PushedFP}                                  ChildSP+000     CallerSP-0C0
;;
;; NOTE: If the frame layout ever changes, the C++ UniversalTransitionStackFrame structure
;; must be updated as well.
;;
;; NOTE: The callee receives a pointer to the base of the ReturnBlock, and the callee has
;; knowledge of the exact layout of all pieces of the frame that lie at or above the pushed
;; FpArgRegs.
;;
;; NOTE: The stack walker guarantees that conservative GC reporting will be applied to
;; everything between the base of the ReturnBlock and the top of the StackPassedArgs.
;;

    TEXTAREA

    MACRO 
        UNIVERSAL_TRANSITION $FunctionName

    NESTED_ENTRY Rhp$FunctionName

        ;; FP and LR registers
        PROLOG_SAVE_REG_PAIR   fp, lr, #-STACK_SIZE!            ;; Push down stack pointer and store FP and LR

        ;; Floating point registers
        stp         d0, d1, [sp, #(FLOAT_ARG_OFFSET       )]
        stp         d2, d3, [sp, #(FLOAT_ARG_OFFSET + 0x10)]
        stp         d4, d5, [sp, #(FLOAT_ARG_OFFSET + 0x20)]
        stp         d6, d7, [sp, #(FLOAT_ARG_OFFSET + 0x30)]

        ;; Space for return buffer data (0x40 bytes)

        ;; Save argument registers
        stp         x0, x1,  [sp, #(ARGUMENT_REGISTERS_OFFSET       )]
        stp         x2, x3,  [sp, #(ARGUMENT_REGISTERS_OFFSET + 0x10)]
        stp         x4, x5,  [sp, #(ARGUMENT_REGISTERS_OFFSET + 0x20)]
        stp         x6, x7,  [sp, #(ARGUMENT_REGISTERS_OFFSET + 0x30)]
        stp         x8, xzr, [sp, #(ARGUMENT_REGISTERS_OFFSET + 0x40)]

#ifdef TRASH_SAVED_ARGUMENT_REGISTERS
        ;; ARM64TODO
#endif // TRASH_SAVED_ARGUMENT_REGISTERS

        add         x0, sp, #DISTANCE_FROM_CHILDSP_TO_RETURN_BLOCK  ;; First parameter to target function is a pointer to the return block
        mov         x8, x0                                          ;; Arm64 calling convention: Address of return block shall be passed in x8
        mov         x1, xip1                                        ;; Second parameter to target function
        blr         xip0

        ;; We cannot make the label public as that tricks DIA stackwalker into thinking
        ;; it's the beginning of a method. For this reason we export an auxiliary variable
        ;; holding the address instead.
    EXPORT_POINTER_TO_ADDRESS PointerToReturnFrom$FunctionName

        ;; Move the result (the target address) to x12 so it doesn't get overridden when we restore the
        ;; argument registers.
        mov         x12, x0

        ;; Restore floating point registers
        ldp         d0, d1, [sp, #(FLOAT_ARG_OFFSET       )]
        ldp         d2, d3, [sp, #(FLOAT_ARG_OFFSET + 0x10)]
        ldp         d4, d5, [sp, #(FLOAT_ARG_OFFSET + 0x20)]
        ldp         d6, d7, [sp, #(FLOAT_ARG_OFFSET + 0x30)]

        ;; Restore the argument registers
        ldp         x0, x1,  [sp, #(ARGUMENT_REGISTERS_OFFSET       )]
        ldp         x2, x3,  [sp, #(ARGUMENT_REGISTERS_OFFSET + 0x10)]
        ldp         x4, x5,  [sp, #(ARGUMENT_REGISTERS_OFFSET + 0x20)]
        ldp         x6, x7,  [sp, #(ARGUMENT_REGISTERS_OFFSET + 0x30)]
        ldr         x8,      [sp, #(ARGUMENT_REGISTERS_OFFSET + 0x40)]

        ;; Restore FP and LR registers, and free the allocated stack block
        EPILOG_RESTORE_REG_PAIR   fp, lr, #STACK_SIZE!

        ;; Tailcall to the target address.
        EPILOG_NOP br x12

    NESTED_END Rhp$FunctionName

    MEND

    ; To enable proper step-in behavior in the debugger, we need to have two instances
    ; of the thunk. For the first one, the debugger steps into the call in the function, 
    ; for the other, it steps over it.
    UNIVERSAL_TRANSITION UniversalTransition
    UNIVERSAL_TRANSITION UniversalTransition_DebugStepTailCall

    END