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

VTableResolver.asm « arm « System.Private.TypeLoader.Native « Native « src - github.com/mono/corert.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 36e244e931570b5d6b898693adea91c3a4e72e9a (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
163
;; 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 "kxarm.h"

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;  DATA SECTIONS  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
        DATAAREA

g_vtableResolveCallback DCD 0  ; The vtableresolve method
    EXPORT g_vtableResolveCallback
g_universalTransition DCD 0  ; The address of Redhawk's UniversalTransition thunk

#define VTableThunkSize 0x20
;; TODO - do something similar to Redhawk's asmoffsets to compute the value at compile time
#define EETypeVTableOffset 0x14
#define PointerSize 4
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ConstrainedCall Support Helpers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

        TEXTAREA
;;
;; Note: The "__jmpstub__" prefix is used to indicate to debugger
;; that it must step-through this stub when it encounters it while
;; stepping.
;;

;; Returns the size of the pre-generated thunks
;; int VTableResolver_Init(IntPtr *__jmpstub__VTableResolverSlot0,
;;                          IntPtr vtableResolveCallback,
;;                          IntPtr universalTransition,
;;                          int *slotCount)
;;
    LEAF_ENTRY VTableResolver_Init
        ldr     r12, __jmpstub__VTableSlot000
        add     r12, r12, 1 ; Add thumb bit
        str     r12, [r0]
        ldr r12, =g_vtableResolveCallback
        str     r1, [r12]
        ldr r12, =g_universalTransition
        str     r2, [r12]
        mov     r12, 100 ; This file defines 100 slot helpers
        str     r12, [r3]
        mov     r0, VTableThunkSize ; Each thunk is VTableThunkSize in bytes
        bx      lr
    LEAF_END VTableResolver_Init

;; void* VTableResolver_GetCommonCallingStub()
;;  - Get the address of the common calling stub
    LEAF_ENTRY VTableResolver_GetCommonCallingStub
        ldr     r0, __jmpstub__VTableResolver_CommonCallingStub
        bx      lr
    LEAF_END VTableResolver_GetCommonCallingStub

;;
;; __jmpstub__VTableResolver_CommonCallingStub(?)
;;  Used when we dynamically need a VTableResolver not pre-generated
;;
;; sp-4 contains a pointer to a VTableResolverStruct
;;   struct VTableResolverStruct
;;   {
;;       int offsetFromStartOfEETypePtr;
;;       IntPtr VTableThunkAddress;
;;   };
;;
    LEAF_ENTRY __jmpstub__VTableResolver_CommonCallingStub
        ;; Custom calling convention:
        ;;      red zone has pointer to the VTableResolverStruct
        ;;      Copy red zone value into r12 so that the PROLOG_PUSH doesn't destroy it
        PROLOG_NOP  ldr r12, [sp, #-4]
        PROLOG_PUSH {r3}
        PROLOG_PUSH {r1-r2}
        ldr r2, [r0]
        ;; r2 is the EEType pointer add the VTableOffset + slot_number * pointer size to get the vtable entry
        ;; compare the that value to the address of the thunk being executed and if the values are equal then
        ;; call to the resolver otherwise call the method
        ldr r1, [r12]
        ;; r1 is the offset from start of EEType to interesting slot
        ldr r3, [r2,r1]
        ;; r3 is now the function pointer in the vtable
        ldr r2,[r12,#4]
        ;; is now the address of the function pointer that serves as the entry point for this particular instantiation
        ;; of __jmpstub__VTableResolver_CommonCallingStub
        cmp r2,r3
        beq  __jmpstub__JumpToVTableResolver
        mov r12,r3 ; Move the target function pointer to r12
        EPILOG_POP {r1,r2}
        EPILOG_POP {r3}
        EPILOG_BRANCH_REG r12
    LEAF_END __jmpstub__VTableResolver_CommonCallingStub

;; stub for dispatch will come in with r1 set to EETypeVTableOffset + ($slot_number * PointerSize), 
;; and r1, r2 and r3 of the function we really want to call pushed on the stack
    LEAF_ENTRY __jmpstub__JumpToVTableResolver
        mov r3, r1
        POP {r1,r2}
        str r3,  [sp, #-4] ; Store slot number into red zone at appropriate spot
        POP {r3}
        ldr     r12, =g_vtableResolveCallback
        ldr     r12, [r12]
        str     r12,  [sp, #-4] ; Store vtable resolve callback into red zone
        ldr     r12, =g_universalTransition
        ldr     r12, [r12]
        bx      r12
    LEAF_END __jmpstub__VTableResolver_Init


    MACRO
        VTableThunkDecl $name, $slot_number
        ALIGN 16 ; The alignment here forces the thunks to be the same size which gives all of the macros the same size and allows us to index
        LEAF_ENTRY __jmpstub__$name
        ;; rcx is the this pointer to the call being made
        PUSH {r3}
        PUSH {r1,r2}                            ; Push r1,r2
        ldr r2, [r0]
        ;; r2 is the EEType pointer add the VTableOffset + slot_number * pointer size to get the vtable entry
        ;; compare the that value to the address of the thunk being executed and if the values are equal then
        ;; call to the resolver otherwise call the method
        mov r1, EETypeVTableOffset + ($slot_number * PointerSize)
        ldr r3, [r2,r1]
        ; r3 is now the function pointer in the vtable
        ldr r2,=__jmpstub__$name
        cmp r2,r3
        beq  JumpVTableResolver$name
        mov r12,r3 ; Move the target function pointer to r12 before popping r2 and r3. We used r3 instead of r12 here so that
                   ; we could use the 2 byte thumb instructions and the whole thunk could fit in less than 32 bytes
        POP {r1,r2,r3}
        bx r12
JumpVTableResolver$name
        b  __jmpstub__JumpToVTableResolver
        LEAF_END __jmpstub__$name
    MEND

    MACRO
        VTableThunkDeclTen $slotnumberDecimal
        VTableThunkDecl VTableSlot$slotnumberDecimal0,$slotnumberDecimal0
        VTableThunkDecl VTableSlot$slotnumberDecimal1,$slotnumberDecimal1
        VTableThunkDecl VTableSlot$slotnumberDecimal2,$slotnumberDecimal2
        VTableThunkDecl VTableSlot$slotnumberDecimal3,$slotnumberDecimal3
        VTableThunkDecl VTableSlot$slotnumberDecimal4,$slotnumberDecimal4
        VTableThunkDecl VTableSlot$slotnumberDecimal5,$slotnumberDecimal5
        VTableThunkDecl VTableSlot$slotnumberDecimal6,$slotnumberDecimal6
        VTableThunkDecl VTableSlot$slotnumberDecimal7,$slotnumberDecimal7
        VTableThunkDecl VTableSlot$slotnumberDecimal8,$slotnumberDecimal8
        VTableThunkDecl VTableSlot$slotnumberDecimal9,$slotnumberDecimal9
    MEND

    MACRO
        VTableThunkDeclHundred $slotnumberPerHundred
        VTableThunkDeclTen $slotnumberPerHundred0
        VTableThunkDeclTen $slotnumberPerHundred1
        VTableThunkDeclTen $slotnumberPerHundred2
        VTableThunkDeclTen $slotnumberPerHundred3
        VTableThunkDeclTen $slotnumberPerHundred4
        VTableThunkDeclTen $slotnumberPerHundred5
        VTableThunkDeclTen $slotnumberPerHundred6
        VTableThunkDeclTen $slotnumberPerHundred7
        VTableThunkDeclTen $slotnumberPerHundred8
        VTableThunkDeclTen $slotnumberPerHundred9
    MEND

    VTableThunkDeclHundred 0

    END