-
Notifications
You must be signed in to change notification settings - Fork 10.5k
/
Copy pathFastEntryPoints.s
220 lines (204 loc) · 5.17 KB
/
FastEntryPoints.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
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
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
//===--- FastEntryPoints.s - Swift Language Assembly Entry Points ABI -----===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// Swift Language Assembly Entry Points ABI
//
//===----------------------------------------------------------------------===//
#include "swift/Runtime/FastEntryPoints.h"
#ifdef __x86_64__
// The custom swift runtime ABI for x86_64 is as follows.
//
// Like normal function calls:
// 1) Arguments to the runtime are in the same registers as normal functions
// 2) Return values are in the same registers as normal functions
// 3) Non-integer registers are NOT preserved: floating point, MMX, SSE, AVX...
// 4) The direction bit is in the forward direction
// 5) %r11 may be trashed by the callee
// 6) Condition flags may be trashed upon completion
//
// Unlike normal function calls:
// 1) The stack need not be aligned
// 2) No stack frame is needed in the caller
// 3) All integer registers other than %r11 and optional return registers are
// preserved. In other words, if the entry point returns void, then %rax
// and %rdx are preserved.
//
// This ABI has many advantages. In particular, it helps avoid many register
// spills and even makes unusual tail calls possible:
//
// convertStringToNSSwiftString:
// mov %rdi, %rcx // backup %rdi without spilling
// mov $5, %rdi
// call swift_rawAlloc
// lea NSSwiftStringClass(%rip), %r8
// mov %r8, (%rax) // vtable/isa
// mov $1, 8(%rax) // ref count
// mov %rcx, 16(%rax) // owner
// mov %rsi, 24(%rax) // base -- NOTE: it didn't need to get spilled
// mov %rdx, 32(%rax) // len -- NOTE: it didn't need to get spilled
// mov %rcx, %rdi // prepare to retain the Swift string
// jmp swift_retain // swift_retain returns void therefore it preserves
// // %rax and therefore we can tail call
// // NOTE: %rdi and %rax are NOT the same here
//
//
// MISC NOTES AND BUGS
//
// 11565357 ld should rewrite JMPs into fall-through NOPs when possible
.macro BEGIN_FUNC
.text
.globl $0
.align 4
$0:
.endmacro
.macro STATIC_FUNC
.text
.private_extern $0
.align 4
$0:
.endmacro
.macro END_FUNC
.endmacro
.macro SaveRegisters
.cfi_startproc
push %rbp
.cfi_def_cfa_offset 16
.cfi_offset %rbp, -16
mov %rsp, %rbp
.cfi_def_cfa_register %rbp
// potentially align the stack
and $-16, %rsp
push %rax
push %rcx
push %rdx
push %rsi
push %rdi
push %r8
push %r9
push %r10
.endmacro
.macro RestoreRegisters
pop %r10
pop %r9
pop %r8
pop %rdi
pop %rsi
pop %rdx
pop %rcx
pop %rax
// the stack may have been aligned, therefore LEAVE instead of POP %rbp
leave
.cfi_endproc
.endmacro
// XXX FIXME -- We need to change this to return "void"
BEGIN_FUNC _swift_retain
mov %rdi, %rsi
jmp _swift_retainAndReturnThree
END_FUNC
// XXX FIXME -- hack until we have tinycc
// func swift_retainAndReturnThree(obj,(rsi,rdx,rcx)) -> (rax,rdx,rcx)
BEGIN_FUNC _swift_retainAndReturnThree
test %rdi, %rdi
jz 1f
testb $RC_ATOMIC_BIT, RC_OFFSET(%rdi)
jnz 3f
addl $RC_INTERVAL, RC_OFFSET(%rdi)
jc 2f
1:
mov %rsi, %rax
ret
2:
int3
3:
lock
addl $RC_INTERVAL, RC_OFFSET(%rdi)
jc 2b
mov %rsi, %rax
ret
END_FUNC
BEGIN_FUNC _swift_release
test %rdi, %rdi
jz 1f
testb $RC_ATOMIC_BIT, RC_OFFSET(%rdi)
jnz 2f
subl $RC_INTERVAL, RC_OFFSET(%rdi)
jz 4f
jc 3f
1:
ret
2:
// workaround lack of "xsub" instruction via xadd then sub
movl $-RC_INTERVAL, %r11d
lock
xaddl %r11d, RC_OFFSET(%rdi)
sub $RC_INTERVAL, %r11d
jc 3f
andl $RC_MASK, %r11d
jz 4f
ret
3:
int3
4:
SaveRegisters
call __swift_release_slow
RestoreRegisters
ret
END_FUNC
BEGIN_FUNC _swift_dealloc
mov %gs:SWIFT_TSD_ALLOC_BASE(,%rsi,8), %r11
mov %r11, (%rdi)
mov %rdi, %gs:SWIFT_TSD_ALLOC_BASE(,%rsi,8)
ret
END_FUNC
BEGIN_FUNC _swift_rawDealloc
mov %gs:SWIFT_TSD_RAW_ALLOC_BASE(,%rsi,8), %r11
mov %r11, (%rdi)
mov %rdi, %gs:SWIFT_TSD_RAW_ALLOC_BASE(,%rsi,8)
ret
END_FUNC
.macro ALLOC_FUNC
BEGIN_FUNC $0
1:
mov %gs:$1(,%rdi,8), %rax
test %rax, %rax
je 2f
mov (%rax), %r11
mov %r11, %gs:$1(,%rdi,8)
ret
2:
SaveRegisters
.if $2 == 0
xor %esi, %esi
.else
mov $$$2, %esi
.endif
call __swift_refillThreadAllocCache
RestoreRegisters
.if $2 == SWIFT_TRYALLOC
cmpq $$0, %gs:$1(,%rdi,8)
jnz 1b
ret
.elseif $2 == SWIFT_TRYRAWALLOC
cmpq $$0, %gs:$1(,%rdi,8)
jnz 1b
ret
.else
jmp 1b
.endif
END_FUNC
.endmacro
ALLOC_FUNC _swift_alloc, SWIFT_TSD_ALLOC_BASE, 0
ALLOC_FUNC _swift_tryAlloc, SWIFT_TSD_ALLOC_BASE, SWIFT_TRYALLOC
ALLOC_FUNC _swift_rawAlloc, SWIFT_TSD_RAW_ALLOC_BASE, SWIFT_RAWALLOC
ALLOC_FUNC _swift_tryRawAlloc, SWIFT_TSD_RAW_ALLOC_BASE, SWIFT_TRYRAWALLOC
#endif
.subsections_via_symbols