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
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
|
// 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.
.syntax unified
.thumb
#include <AsmOffsets.inc> // generated by the build from AsmOffsets.cpp
#include <unixasmmacros.inc>
#ifdef FEATURE_CACHED_INTERFACE_DISPATCH
// TODO: Implement Arm support
#ifdef _DEBUG
.rodata
AssertMsg: .asciz "__FILE__:%s: %s is not implemented\n"
FileName: .asciz "StubDispatch.S"
RhpCastableObjectDispatch_CommonStubName: .asciz "RhpCastableObjectDispatch_CommonStub"
RhpTailCallTLSDispatchCellName: .asciz "RhpTailCallTLSDispatchCell"
RhpCastableObjectDispatchHelper_TailCalledName: .asciz "RhpCastableObjectDispatchHelper_TailCalled"
RhpCastableObjectDispatchHelperName: .asciz "RhpCastableObjectDispatchHelper"
RhpVTableOffsetDispatchName: .asciz "RhpVTableOffsetDispatch"
.text
.macro GEN_ASSERT_FUNC func
GEN_ASSERT AssertMsg, FileName, \func
.endm
#endif
LEAF_ENTRY RhpCastableObjectDispatch_CommonStub, _TEXT
#ifdef _DEBUG
GEN_ASSERT_FUNC RhpCastableObjectDispatch_CommonStubName
#else
// UNIXTODO: Implement this function
EMIT_BREAKPOINT
#endif
LEAF_END RhpCastableObjectDispatch_CommonStub, _TEXT
LEAF_ENTRY RhpTailCallTLSDispatchCell, _TEXT
#ifdef _DEBUG
GEN_ASSERT_FUNC RhpTailCallTLSDispatchCellName
#else
// UNIXTODO: Implement this function
EMIT_BREAKPOINT
#endif
LEAF_END RhpTailCallTLSDispatchCell, _TEXT
LEAF_ENTRY RhpCastableObjectDispatchHelper_TailCalled, _TEXT
#ifdef _DEBUG
GEN_ASSERT_FUNC RhpCastableObjectDispatchHelper_TailCalledName
#else
// UNIXTODO: Implement this function
EMIT_BREAKPOINT
#endif
LEAF_END RhpCastableObjectDispatchHelper_TailCalled, _TEXT
LEAF_ENTRY RhpCastableObjectDispatchHelper, _TEXT
#ifdef _DEBUG
GEN_ASSERT_FUNC RhpCastableObjectDispatchHelperName
#else
// UNIXTODO: Implement this function
EMIT_BREAKPOINT
#endif
LEAF_END RhpCastableObjectDispatchHelper, _TEXT
// Macro that generates a stub consuming a cache with the given number of entries.
.macro DEFINE_INTERFACE_DISPATCH_STUB entries
LEAF_ENTRY RhpInterfaceDispatch\entries, _TEXT
// r12 currently contains the indirection cell address. But we need more scratch registers and
// we may A/V on a null this. Both of these suggest we need a real prolog and epilog.
PROLOG_PUSH {r1-r2}
// r12 currently holds the indirection cell address. We need to get the cache structure instead.
ldr r2, [r12, #OFFSETOF__InterfaceDispatchCell__m_pCache]
// Load the EEType from the object instance in r0.
ldr r1, [r0]
CurrentOffset = OFFSETOF__InterfaceDispatchCache__m_rgEntries
// For each entry in the cache, see if its EEType type matches the EEType in r1.
// If so, call the second cache entry. If not, skip the InterfaceDispatchCacheEntry.
// R1 : Instance EEType*
// R2: Cache data structure
// R12 : Trashed. On succesful check, set to the target address to jump to.
.rept \entries
ldr r12, [r2, #CurrentOffset]
cmp r1, r12
bne 0f
ldr r12, [r2, #(CurrentOffset + 4)]
b LOCAL_LABEL(99_\entries)
0:
CurrentOffset = CurrentOffset + 8
.endr
// Point r12 to the indirection cell using the back pointer in the cache block
ldr r12, [r2, #OFFSETOF__InterfaceDispatchCache__m_pCell]
EPILOG_POP {r1-r2}
b C_FUNC(RhpInterfaceDispatchSlow)
// Common epilog for cache hits. Have to out of line it here due to limitation on the number of
// epilogs imposed by the unwind code macros.
LOCAL_LABEL(99_\entries):
// R2 contains address of the cache block. We store it in the red zone in case the target we jump
// to needs it. Currently the RhpCastableObjectDispatchHelper is the only such target.
// R12 contains the target address to jump to
EPILOG_POP {r1}
// The red zone is only 8 bytes long, so we have to store r2 into it between the pops.
str r2, [sp, #-4]
EPILOG_POP {r2}
EPILOG_BRANCH_REG r12
LEAF_END RhpInterfaceDispatch\entries, _TEXT
.endm // DEFINE_INTERFACE_DISPATCH_STUB
// Define all the stub routines we currently need.
//
// The mrt100dbi requires these be exported to identify mrt100 code that dispatches back into managed.
// If you change or add any new dispatch stubs, please also change slr.def and dbi\process.cpp CordbProcess::GetExportStepInfo
//
DEFINE_INTERFACE_DISPATCH_STUB 1
DEFINE_INTERFACE_DISPATCH_STUB 2
DEFINE_INTERFACE_DISPATCH_STUB 4
DEFINE_INTERFACE_DISPATCH_STUB 8
DEFINE_INTERFACE_DISPATCH_STUB 16
DEFINE_INTERFACE_DISPATCH_STUB 32
DEFINE_INTERFACE_DISPATCH_STUB 64
// Stub dispatch routine for dispatch to a vtable slot
LEAF_ENTRY RhpVTableOffsetDispatch, _TEXT
// On input we have the indirection cell data structure in r12. But we need more scratch registers and
// we may A/V on a null this. Both of these suggest we need a real prolog and epilog.
PROLOG_PUSH {r1}
// r12 currently holds the indirection cell address. We need to update it to point to the vtable
// offset instead.
ldr r12, [r12, #OFFSETOF__InterfaceDispatchCell__m_pCache]
// Load the EEType from the object instance in r0.
ldr r1, [r0]
// add the vtable offset to the EEType pointer
add r12, r1, r12
// Load the target address of the vtable into r12
ldr r12, [r12]
EPILOG_POP {r1}
EPILOG_BRANCH_REG r12
LEAF_END RhpVTableOffsetDispatch, _TEXT
// Initial dispatch on an interface when we don't have a cache yet.
LEAF_ENTRY RhpInitialInterfaceDispatch, _TEXT
// The stub that jumped here pushed r12, which contains the interface dispatch cell
// we need to pop it here
pop { r12 }
// Just tail call to the cache miss helper.
b C_FUNC(RhpInterfaceDispatchSlow)
LEAF_END RhpInitialInterfaceDispatch, _TEXT
// No as alternate entry due to missed thumb bit in this case
// See https://github.com/dotnet/coreclr/issues/12953
LEAF_ENTRY RhpInitialDynamicInterfaceDispatch, _TEXT
// Just tail call to the cache miss helper.
b C_FUNC(RhpInterfaceDispatchSlow)
LEAF_END RhpInitialDynamicInterfaceDispatch, _TEXT
// Cache miss case, call the runtime to resolve the target and update the cache.
// Use universal transition helper to allow an exception to flow out of resolution
LEAF_ENTRY RhpInterfaceDispatchSlow, _TEXT
// r12 has the interface dispatch cell address in it.
// The calling convention of the universal thunk is that the parameter
// for the universal thunk target is to be placed in sp-8
// and the universal thunk target address is to be placed in sp-4
str r12, [sp, #-8]
ldr r12, =C_FUNC(RhpCidResolve)
str r12, [sp, #-4]
// jump to universal transition thunk
b C_FUNC(RhpUniversalTransition_DebugStepTailCall)
LEAF_END RhpInterfaceDispatchSlow, _TEXT
#endif // FEATURE_CACHED_INTERFACE_DISPATCH
|