-
Notifications
You must be signed in to change notification settings - Fork 4.6k
/
StubDispatch.S
135 lines (109 loc) · 5.65 KB
/
StubDispatch.S
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
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
.syntax unified
.thumb
#include <AsmOffsets.inc> // generated by the build from AsmOffsets.cpp
#include <unixasmmacros.inc>
#ifdef FEATURE_CACHED_INTERFACE_DISPATCH
// Macro that generates a stub consuming a cache with the given number of entries.
.macro DEFINE_INTERFACE_DISPATCH_STUB entries
NESTED_ENTRY RhpInterfaceDispatch\entries, _TEXT, NoHandler
// r12 currently contains the indirection cell address. But we need more scratch registers and
// we may A/V on a null this. Store r1 and r2 in red zone.
str r1, [sp, #-8]
str r2, [sp, #-4]
// r12 currently holds the indirection cell address. We need to get the cache structure instead.
ldr r2, [r12, #OFFSETOF__InterfaceDispatchCell__m_pCache]
// Load the MethodTable from the object instance in r0.
ALTERNATE_ENTRY RhpInterfaceDispatchAVLocation\entries
ldr r1, [r0]
CurrentOffset = OFFSETOF__InterfaceDispatchCache__m_rgEntries
// For each entry in the cache, see if its MethodTable type matches the MethodTable in r1.
// If so, call the second cache entry. If not, skip the InterfaceDispatchCacheEntry.
// R1 : Instance MethodTable*
// R2: Cache data structure
// R12 : Trashed. On successful 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]
ldr r1, [sp, #-8]
ldr r2, [sp, #-4]
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.
// R12 contains the target address to jump to
ldr r1, [sp, #-8]
// We have to store R2 with address of the cache block into red zone before restoring original r2.
str r2, [sp, #-8]
ldr r2, [sp, #-4]
EPILOG_BRANCH_REG r12
NESTED_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 MethodTable from the object instance in r0.
ldr r1, [r0]
// add the vtable offset to the MethodTable 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/runtime/issues/8608
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