-
Notifications
You must be signed in to change notification settings - Fork 0
/
objc_msgSend.arm.S
130 lines (110 loc) · 4.05 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
.syntax unified
.fpu neon
#if ((__ARM_ARCH >= 7) || defined (__ARM_ARCH_6T2__))
.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
.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
ldrne r4, LSmallIntClass // Small Int class -> r4 if this is a small int
ldrne r4, [r4]
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
teq ip, #0 // If the slot is nil
beq 5f // Go to the slow path and do the forwarding stuff
ldr ip, [ip, #SLOT_OFFSET] // Load the method from the slot
3:
pop {r4-r6} // Restore the saved callee-save registers
mov pc, ip
4: // Nil receiver
mov r0, 0
mov r1, 0
mov pc, lr
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}
.pad #64
#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
b 3b
.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
LSmallIntClass:
.long SmallObjectClasses
.align 2