]> git.saurik.com Git - apple/objc4.git/blob - runtime/Messengers.subproj/objc-msg-arm64.s
objc4-706.tar.gz
[apple/objc4.git] / runtime / Messengers.subproj / objc-msg-arm64.s
1 /*
2 * @APPLE_LICENSE_HEADER_START@
3 *
4 * Copyright (c) 2011 Apple Inc. All Rights Reserved.
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23 /********************************************************************
24 *
25 * objc-msg-arm64.s - ARM64 code to support objc messaging
26 *
27 ********************************************************************/
28
29 #ifdef __arm64__
30
31 #include <arm/arch.h>
32
33
34 .data
35
36 // _objc_entryPoints and _objc_exitPoints are used by method dispatch
37 // caching code to figure out whether any threads are actively
38 // in the cache for dispatching. The labels surround the asm code
39 // that do cache lookups. The tables are zero-terminated.
40
41 .align 4
42 .private_extern _objc_entryPoints
43 _objc_entryPoints:
44 .quad _cache_getImp
45 .quad _objc_msgSend
46 .quad _objc_msgSendSuper
47 .quad _objc_msgSendSuper2
48 .quad _objc_msgLookup
49 .quad _objc_msgLookupSuper2
50 .quad 0
51
52 .private_extern _objc_exitPoints
53 _objc_exitPoints:
54 .quad LExit_cache_getImp
55 .quad LExit_objc_msgSend
56 .quad LExit_objc_msgSendSuper
57 .quad LExit_objc_msgSendSuper2
58 .quad LExit_objc_msgLookup
59 .quad LExit_objc_msgLookupSuper2
60 .quad 0
61
62
63 /********************************************************************
64 * List every exit insn from every messenger for debugger use.
65 * Format:
66 * (
67 * 1 word instruction's address
68 * 1 word type (ENTER or FAST_EXIT or SLOW_EXIT or NIL_EXIT)
69 * )
70 * 1 word zero
71 *
72 * ENTER is the start of a dispatcher
73 * FAST_EXIT is method dispatch
74 * SLOW_EXIT is uncached method lookup
75 * NIL_EXIT is returning zero from a message sent to nil
76 * These must match objc-gdb.h.
77 ********************************************************************/
78
79 #define ENTER 1
80 #define FAST_EXIT 2
81 #define SLOW_EXIT 3
82 #define NIL_EXIT 4
83
84 .section __DATA,__objc_msg_break
85 .globl _gdb_objc_messenger_breakpoints
86 _gdb_objc_messenger_breakpoints:
87 // contents populated by the macros below
88
89 .macro MESSENGER_START
90 4:
91 .section __DATA,__objc_msg_break
92 .quad 4b
93 .quad ENTER
94 .text
95 .endmacro
96 .macro MESSENGER_END_FAST
97 4:
98 .section __DATA,__objc_msg_break
99 .quad 4b
100 .quad FAST_EXIT
101 .text
102 .endmacro
103 .macro MESSENGER_END_SLOW
104 4:
105 .section __DATA,__objc_msg_break
106 .quad 4b
107 .quad SLOW_EXIT
108 .text
109 .endmacro
110 .macro MESSENGER_END_NIL
111 4:
112 .section __DATA,__objc_msg_break
113 .quad 4b
114 .quad NIL_EXIT
115 .text
116 .endmacro
117
118
119 /* objc_super parameter to sendSuper */
120 #define RECEIVER 0
121 #define CLASS 8
122
123 /* Selected field offsets in class structure */
124 #define SUPERCLASS 8
125 #define CACHE 16
126
127 /* Selected field offsets in isa field */
128 #define ISA_MASK 0x0000000ffffffff8
129
130 /* Selected field offsets in method structure */
131 #define METHOD_NAME 0
132 #define METHOD_TYPES 8
133 #define METHOD_IMP 16
134
135
136 /********************************************************************
137 * ENTRY functionName
138 * STATIC_ENTRY functionName
139 * END_ENTRY functionName
140 ********************************************************************/
141
142 .macro ENTRY /* name */
143 .text
144 .align 5
145 .globl $0
146 $0:
147 .endmacro
148
149 .macro STATIC_ENTRY /*name*/
150 .text
151 .align 5
152 .private_extern $0
153 $0:
154 .endmacro
155
156 .macro END_ENTRY /* name */
157 LExit$0:
158 .endmacro
159
160
161 /********************************************************************
162 * UNWIND name, flags
163 * Unwind info generation
164 ********************************************************************/
165 .macro UNWIND
166 .section __LD,__compact_unwind,regular,debug
167 .quad $0
168 .set LUnwind$0, LExit$0 - $0
169 .long LUnwind$0
170 .long $1
171 .quad 0 /* no personality */
172 .quad 0 /* no LSDA */
173 .text
174 .endmacro
175
176 #define NoFrame 0x02000000 // no frame, no SP adjustment
177 #define FrameWithNoSaves 0x04000000 // frame, no non-volatile saves
178
179
180 /********************************************************************
181 *
182 * CacheLookup NORMAL|GETIMP|LOOKUP
183 *
184 * Locate the implementation for a selector in a class method cache.
185 *
186 * Takes:
187 * x1 = selector
188 * x16 = class to be searched
189 *
190 * Kills:
191 * x9,x10,x11,x12, x17
192 *
193 * On exit: (found) calls or returns IMP
194 * with x16 = class, x17 = IMP
195 * (not found) jumps to LCacheMiss
196 *
197 ********************************************************************/
198
199 #define NORMAL 0
200 #define GETIMP 1
201 #define LOOKUP 2
202
203 .macro CacheHit
204 .if $0 == NORMAL
205 MESSENGER_END_FAST
206 br x17 // call imp
207 .elseif $0 == GETIMP
208 mov x0, x17 // return imp
209 ret
210 .elseif $0 == LOOKUP
211 ret // return imp via x17
212 .else
213 .abort oops
214 .endif
215 .endmacro
216
217 .macro CheckMiss
218 // miss if bucket->sel == 0
219 .if $0 == GETIMP
220 cbz x9, LGetImpMiss
221 .elseif $0 == NORMAL
222 cbz x9, __objc_msgSend_uncached
223 .elseif $0 == LOOKUP
224 cbz x9, __objc_msgLookup_uncached
225 .else
226 .abort oops
227 .endif
228 .endmacro
229
230 .macro JumpMiss
231 .if $0 == GETIMP
232 b LGetImpMiss
233 .elseif $0 == NORMAL
234 b __objc_msgSend_uncached
235 .elseif $0 == LOOKUP
236 b __objc_msgLookup_uncached
237 .else
238 .abort oops
239 .endif
240 .endmacro
241
242 .macro CacheLookup
243 // x1 = SEL, x16 = isa
244 ldp x10, x11, [x16, #CACHE] // x10 = buckets, x11 = occupied|mask
245 and w12, w1, w11 // x12 = _cmd & mask
246 add x12, x10, x12, LSL #4 // x12 = buckets + ((_cmd & mask)<<4)
247
248 ldp x9, x17, [x12] // {x9, x17} = *bucket
249 1: cmp x9, x1 // if (bucket->sel != _cmd)
250 b.ne 2f // scan more
251 CacheHit $0 // call or return imp
252
253 2: // not hit: x12 = not-hit bucket
254 CheckMiss $0 // miss if bucket->sel == 0
255 cmp x12, x10 // wrap if bucket == buckets
256 b.eq 3f
257 ldp x9, x17, [x12, #-16]! // {x9, x17} = *--bucket
258 b 1b // loop
259
260 3: // wrap: x12 = first bucket, w11 = mask
261 add x12, x12, w11, UXTW #4 // x12 = buckets+(mask<<4)
262
263 // Clone scanning loop to miss instead of hang when cache is corrupt.
264 // The slow path may detect any corruption and halt later.
265
266 ldp x9, x17, [x12] // {x9, x17} = *bucket
267 1: cmp x9, x1 // if (bucket->sel != _cmd)
268 b.ne 2f // scan more
269 CacheHit $0 // call or return imp
270
271 2: // not hit: x12 = not-hit bucket
272 CheckMiss $0 // miss if bucket->sel == 0
273 cmp x12, x10 // wrap if bucket == buckets
274 b.eq 3f
275 ldp x9, x17, [x12, #-16]! // {x9, x17} = *--bucket
276 b 1b // loop
277
278 3: // double wrap
279 JumpMiss $0
280
281 .endmacro
282
283
284 /********************************************************************
285 *
286 * id objc_msgSend(id self, SEL _cmd, ...);
287 * IMP objc_msgLookup(id self, SEL _cmd, ...);
288 *
289 * objc_msgLookup ABI:
290 * IMP returned in x17
291 * x16 reserved for our use but not used
292 *
293 ********************************************************************/
294
295 .data
296 .align 3
297 .globl _objc_debug_taggedpointer_classes
298 _objc_debug_taggedpointer_classes:
299 .fill 16, 8, 0
300 .globl _objc_debug_taggedpointer_ext_classes
301 _objc_debug_taggedpointer_ext_classes:
302 .fill 256, 8, 0
303
304 ENTRY _objc_msgSend
305 UNWIND _objc_msgSend, NoFrame
306 MESSENGER_START
307
308 cmp x0, #0 // nil check and tagged pointer check
309 b.le LNilOrTagged // (MSB tagged pointer looks negative)
310 ldr x13, [x0] // x13 = isa
311 and x16, x13, #ISA_MASK // x16 = class
312 LGetIsaDone:
313 CacheLookup NORMAL // calls imp or objc_msgSend_uncached
314
315 LNilOrTagged:
316 b.eq LReturnZero // nil check
317
318 // tagged
319 mov x10, #0xf000000000000000
320 cmp x0, x10
321 b.hs LExtTag
322 adrp x10, _objc_debug_taggedpointer_classes@PAGE
323 add x10, x10, _objc_debug_taggedpointer_classes@PAGEOFF
324 ubfx x11, x0, #60, #4
325 ldr x16, [x10, x11, LSL #3]
326 b LGetIsaDone
327
328 LExtTag:
329 // ext tagged
330 adrp x10, _objc_debug_taggedpointer_ext_classes@PAGE
331 add x10, x10, _objc_debug_taggedpointer_ext_classes@PAGEOFF
332 ubfx x11, x0, #52, #8
333 ldr x16, [x10, x11, LSL #3]
334 b LGetIsaDone
335
336 LReturnZero:
337 // x0 is already zero
338 mov x1, #0
339 movi d0, #0
340 movi d1, #0
341 movi d2, #0
342 movi d3, #0
343 MESSENGER_END_NIL
344 ret
345
346 END_ENTRY _objc_msgSend
347
348
349 ENTRY _objc_msgLookup
350 UNWIND _objc_msgLookup, NoFrame
351
352 cmp x0, #0 // nil check and tagged pointer check
353 b.le LLookup_NilOrTagged // (MSB tagged pointer looks negative)
354 ldr x13, [x0] // x13 = isa
355 and x16, x13, #ISA_MASK // x16 = class
356 LLookup_GetIsaDone:
357 CacheLookup LOOKUP // returns imp
358
359 LLookup_NilOrTagged:
360 b.eq LLookup_Nil // nil check
361
362 // tagged
363 mov x10, #0xf000000000000000
364 cmp x0, x10
365 b.hs LLookup_ExtTag
366 adrp x10, _objc_debug_taggedpointer_classes@PAGE
367 add x10, x10, _objc_debug_taggedpointer_classes@PAGEOFF
368 ubfx x11, x0, #60, #4
369 ldr x16, [x10, x11, LSL #3]
370 b LLookup_GetIsaDone
371
372 LLookup_ExtTag:
373 adrp x10, _objc_debug_taggedpointer_ext_classes@PAGE
374 add x10, x10, _objc_debug_taggedpointer_ext_classes@PAGEOFF
375 ubfx x11, x0, #52, #8
376 ldr x16, [x10, x11, LSL #3]
377 b LLookup_GetIsaDone
378
379 LLookup_Nil:
380 adrp x17, __objc_msgNil@PAGE
381 add x17, x17, __objc_msgNil@PAGEOFF
382 ret
383
384 END_ENTRY _objc_msgLookup
385
386
387 STATIC_ENTRY __objc_msgNil
388
389 // x0 is already zero
390 mov x1, #0
391 movi d0, #0
392 movi d1, #0
393 movi d2, #0
394 movi d3, #0
395 ret
396
397 END_ENTRY __objc_msgNil
398
399
400 ENTRY _objc_msgSendSuper
401 UNWIND _objc_msgSendSuper, NoFrame
402 MESSENGER_START
403
404 ldp x0, x16, [x0] // x0 = real receiver, x16 = class
405 CacheLookup NORMAL // calls imp or objc_msgSend_uncached
406
407 END_ENTRY _objc_msgSendSuper
408
409 // no _objc_msgLookupSuper
410
411 ENTRY _objc_msgSendSuper2
412 UNWIND _objc_msgSendSuper2, NoFrame
413 MESSENGER_START
414
415 ldp x0, x16, [x0] // x0 = real receiver, x16 = class
416 ldr x16, [x16, #SUPERCLASS] // x16 = class->superclass
417 CacheLookup NORMAL
418
419 END_ENTRY _objc_msgSendSuper2
420
421
422 ENTRY _objc_msgLookupSuper2
423 UNWIND _objc_msgLookupSuper2, NoFrame
424
425 ldp x0, x16, [x0] // x0 = real receiver, x16 = class
426 ldr x16, [x16, #SUPERCLASS] // x16 = class->superclass
427 CacheLookup LOOKUP
428
429 END_ENTRY _objc_msgLookupSuper2
430
431
432 .macro MethodTableLookup
433
434 // push frame
435 stp fp, lr, [sp, #-16]!
436 mov fp, sp
437
438 // save parameter registers: x0..x8, q0..q7
439 sub sp, sp, #(10*8 + 8*16)
440 stp q0, q1, [sp, #(0*16)]
441 stp q2, q3, [sp, #(2*16)]
442 stp q4, q5, [sp, #(4*16)]
443 stp q6, q7, [sp, #(6*16)]
444 stp x0, x1, [sp, #(8*16+0*8)]
445 stp x2, x3, [sp, #(8*16+2*8)]
446 stp x4, x5, [sp, #(8*16+4*8)]
447 stp x6, x7, [sp, #(8*16+6*8)]
448 str x8, [sp, #(8*16+8*8)]
449
450 // receiver and selector already in x0 and x1
451 mov x2, x16
452 bl __class_lookupMethodAndLoadCache3
453
454 // imp in x0
455 mov x17, x0
456
457 // restore registers and return
458 ldp q0, q1, [sp, #(0*16)]
459 ldp q2, q3, [sp, #(2*16)]
460 ldp q4, q5, [sp, #(4*16)]
461 ldp q6, q7, [sp, #(6*16)]
462 ldp x0, x1, [sp, #(8*16+0*8)]
463 ldp x2, x3, [sp, #(8*16+2*8)]
464 ldp x4, x5, [sp, #(8*16+4*8)]
465 ldp x6, x7, [sp, #(8*16+6*8)]
466 ldr x8, [sp, #(8*16+8*8)]
467
468 mov sp, fp
469 ldp fp, lr, [sp], #16
470
471 .endmacro
472
473 STATIC_ENTRY __objc_msgSend_uncached
474 UNWIND __objc_msgSend_uncached, FrameWithNoSaves
475
476 // THIS IS NOT A CALLABLE C FUNCTION
477 // Out-of-band x16 is the class to search
478
479 MethodTableLookup
480 br x17
481
482 END_ENTRY __objc_msgSend_uncached
483
484
485 STATIC_ENTRY __objc_msgLookup_uncached
486 UNWIND __objc_msgLookup_uncached, FrameWithNoSaves
487
488 // THIS IS NOT A CALLABLE C FUNCTION
489 // Out-of-band x16 is the class to search
490
491 MethodTableLookup
492 ret
493
494 END_ENTRY __objc_msgLookup_uncached
495
496
497 STATIC_ENTRY _cache_getImp
498
499 and x16, x0, #ISA_MASK
500 CacheLookup GETIMP
501
502 LGetImpMiss:
503 mov x0, #0
504 ret
505
506 END_ENTRY _cache_getImp
507
508
509 /********************************************************************
510 *
511 * id _objc_msgForward(id self, SEL _cmd,...);
512 *
513 * _objc_msgForward is the externally-callable
514 * function returned by things like method_getImplementation().
515 * _objc_msgForward_impcache is the function pointer actually stored in
516 * method caches.
517 *
518 ********************************************************************/
519
520 STATIC_ENTRY __objc_msgForward_impcache
521
522 MESSENGER_START
523 nop
524 MESSENGER_END_SLOW
525
526 // No stret specialization.
527 b __objc_msgForward
528
529 END_ENTRY __objc_msgForward_impcache
530
531
532 ENTRY __objc_msgForward
533
534 adrp x17, __objc_forward_handler@PAGE
535 ldr x17, [x17, __objc_forward_handler@PAGEOFF]
536 br x17
537
538 END_ENTRY __objc_msgForward
539
540
541 ENTRY _objc_msgSend_noarg
542 b _objc_msgSend
543 END_ENTRY _objc_msgSend_noarg
544
545 ENTRY _objc_msgSend_debug
546 b _objc_msgSend
547 END_ENTRY _objc_msgSend_debug
548
549 ENTRY _objc_msgSendSuper2_debug
550 b _objc_msgSendSuper2
551 END_ENTRY _objc_msgSendSuper2_debug
552
553
554 ENTRY _method_invoke
555 // x1 is method triplet instead of SEL
556 ldr x17, [x1, #METHOD_IMP]
557 ldr x1, [x1, #METHOD_NAME]
558 br x17
559 END_ENTRY _method_invoke
560
561 #endif