-
Notifications
You must be signed in to change notification settings - Fork 118
/
objc_msgSend.arm.S
146 lines (130 loc) · 4.7 KB
/
objc_msgSend.arm.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
136
137
138
139
140
141
142
143
144
145
.syntax unified
.fpu neon
#if ((__ARM_ARCH >= 7) || defined (__ARM_ARCH_6T2__))
#define RELOC_OFFSET 4
// If we're using a CPU that supports Thumb-2, use it. This makes the
// objc_msgSend function 130 bytes instead of 176. The fast path drops from 108
// bytes to 82, meaning that it will fit in 3 32-byte i-cache lines, rather
// than 4. For comparison, the i386 version is 119 for objc_msgSend and
// another 117 for objc_msgSend_fpret (the two are the same on ARM), with 70
// bytes for the fast path..
.thumb
.macro byte1 dst, src
uxtb \dst, \src
.endm
.macro byte2 dst, src
ubfx \dst, \src, #8, #8
.endm
.macro byte3 dst, src
ubfx \dst, \src, #16, #8
.endm
#else
#define RELOC_OFFSET 8
.macro byte1 dst, src
and \dst, \src, #0xff
.endm
.macro byte2 dst, src
and \dst, \src, #0xff00
lsr \dst, \dst, 8
.endm
.macro byte3 dst, src
and \dst, \src, #0xff00
lsr \dst, \dst, 16
.endm
#endif
// Macro for testing: logs a register value to standard error
.macro LOG reg
push {r0-r3, ip,lr}
mov r0, \reg
bl logInt(PLT)
pop {r0-r3, ip,lr}
.endm
.macro MSGSEND receiver, sel
.fnstart
teq \receiver, 0
beq 4f // Skip everything if the receiver is nil
push {r4-r6} // We're going to use these three as
.save {r4-r6}
// scratch registers, so save them now.
// These are callee-save, so the unwind library
// must be able to restore them, so we need CFI
// directives for them, but not for any other pushes
tst \receiver, SMALLOBJ_MASK // Sets Z if this is not a small int
ldr r4, 7f
6:
add r4, pc
itte ne
ldrne r4, [r4]
ldrne r4, [r4] // Small Int class -> r4 if this is a small int
ldreq r4, [\receiver] // Load class to r4 if not a small int
ldr r4, [r4, #DTABLE_OFFSET] // Dtable -> r4
ldr r5, [\sel] // selector->index -> r5
ldr r6, [r4, #SHIFT_OFFSET] // dtable->shift -> r6
teq r6, #8 // If this is a small dtable, jump to the small dtable handlers
beq 1f
teq r6, #0
beq 2f
byte3 r6, r5 // Put byte 3 of the sel id in r6
add r6, r4, r6, lsl #2 // r6 = dtable address + dtable data offset
ldr r4, [r6, #DATA_OFFSET] // Load, adding in the data offset
1: // dtable16
byte2 r6, r5 // Put byte 2 of the sel id in r6
add r6, r4, r6, lsl #2 // r6 = dtable address + dtable data offset
ldr r4, [r6, #DATA_OFFSET] // Load, adding in the data offset
2: // dtable8
byte1 r6, r5 // Low byte of sel id into r5
add r6, r4, r6, lsl #2 // r6 = dtable address + dtable data offset
ldr ip, [r6, #DATA_OFFSET] // Load, adding in the data offset
cmp ip, #0 // If the slot is nil
ittt ne
ldrne ip, [ip, #SLOT_OFFSET] // Load the method from the slot
popne {r4-r6} // Restore the saved callee-save registers
bxne ip
5: // Slow lookup
push {r0-r4, lr} // Save anything that will be clobbered by the call
.save {r0-r4, lr}
#ifndef __SOFTFP__
vpush {q0-q3}
.vsave {q0-q3}
#endif
push {\receiver} // &self, _cmd in arguments
.save {\receiver}
mov r0, sp
mov r1, \sel
bl CDECL(slowMsgLookup)(PLT) // This is the only place where the CFI directives have to be accurate...
mov ip, r0 // IMP -> ip
pop {r5} // restore (modified) self to r5
#ifndef __SOFTFP__
vpop {q0-q3}
#endif
pop {r0-r4, lr} // Load clobbered registers
mov \receiver, r5
pop {r4-r6} // Restore the saved callee-save registers
bx ip
4: // Nil receiver
mov r0, 0
mov r1, 0
#ifndef __SOFTFP__
# ifdef __ARM_NEON__
vmov.i64 d0, #0 // Return 0 as a float / double
# else
fmdrr d0, r0, r1
# endif
#endif
bx lr
7:
.long SmallObjectClasses(GOT_PREL)-((6b+RELOC_OFFSET)-7b)
.align 2
.fnend
.endm
.globl CDECL(objc_msgSend_fpret)
TYPE_DIRECTIVE(CDECL(objc_msgSend_fpret), %function)
.globl CDECL(objc_msgSend)
TYPE_DIRECTIVE(CDECL(objc_msgSend), %function)
CDECL(objc_msgSend):
CDECL(objc_msgSend_fpret):
MSGSEND r0, r1
.globl CDECL(objc_msgSend_stret)
TYPE_DIRECTIVE(CDECL(objc_msgSend_stret), %function)
CDECL(objc_msgSend_stret):
MSGSEND r1, r2