]> git.saurik.com Git - apple/objc4.git/blob - runtime/Messengers.subproj/objc-msg-arm64.s
objc4-750.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 #include "isa.h"
33 #include "arm64-asm.h"
34
35 .data
36
37 // _objc_entryPoints and _objc_exitPoints are used by method dispatch
38 // caching code to figure out whether any threads are actively
39 // in the cache for dispatching. The labels surround the asm code
40 // that do cache lookups. The tables are zero-terminated.
41
42 .align 4
43 .private_extern _objc_entryPoints
44 _objc_entryPoints:
45 PTR _cache_getImp
46 PTR _objc_msgSend
47 PTR _objc_msgSendSuper
48 PTR _objc_msgSendSuper2
49 PTR _objc_msgLookup
50 PTR _objc_msgLookupSuper2
51 PTR 0
52
53 .private_extern _objc_exitPoints
54 _objc_exitPoints:
55 PTR LExit_cache_getImp
56 PTR LExit_objc_msgSend
57 PTR LExit_objc_msgSendSuper
58 PTR LExit_objc_msgSendSuper2
59 PTR LExit_objc_msgLookup
60 PTR LExit_objc_msgLookupSuper2
61 PTR 0
62
63
64 /* objc_super parameter to sendSuper */
65 #define RECEIVER 0
66 #define CLASS __SIZEOF_POINTER__
67
68 /* Selected field offsets in class structure */
69 #define SUPERCLASS __SIZEOF_POINTER__
70 #define CACHE (2 * __SIZEOF_POINTER__)
71
72 /* Selected field offsets in method structure */
73 #define METHOD_NAME 0
74 #define METHOD_TYPES __SIZEOF_POINTER__
75 #define METHOD_IMP (2 * __SIZEOF_POINTER__)
76
77 #define BUCKET_SIZE (2 * __SIZEOF_POINTER__)
78
79
80 /********************************************************************
81 * GetClassFromIsa_p16 src
82 * src is a raw isa field. Sets p16 to the corresponding class pointer.
83 * The raw isa might be an indexed isa to be decoded, or a
84 * packed isa that needs to be masked.
85 *
86 * On exit:
87 * $0 is unchanged
88 * p16 is a class pointer
89 * x10 is clobbered
90 ********************************************************************/
91
92 #if SUPPORT_INDEXED_ISA
93 .align 3
94 .globl _objc_indexed_classes
95 _objc_indexed_classes:
96 .fill ISA_INDEX_COUNT, PTRSIZE, 0
97 #endif
98
99 .macro GetClassFromIsa_p16 /* src */
100
101 #if SUPPORT_INDEXED_ISA
102 // Indexed isa
103 mov p16, $0 // optimistically set dst = src
104 tbz p16, #ISA_INDEX_IS_NPI_BIT, 1f // done if not non-pointer isa
105 // isa in p16 is indexed
106 adrp x10, _objc_indexed_classes@PAGE
107 add x10, x10, _objc_indexed_classes@PAGEOFF
108 ubfx p16, p16, #ISA_INDEX_SHIFT, #ISA_INDEX_BITS // extract index
109 ldr p16, [x10, p16, UXTP #PTRSHIFT] // load class from array
110 1:
111
112 #elif __LP64__
113 // 64-bit packed isa
114 and p16, $0, #ISA_MASK
115
116 #else
117 // 32-bit raw isa
118 mov p16, $0
119
120 #endif
121
122 .endmacro
123
124
125 /********************************************************************
126 * ENTRY functionName
127 * STATIC_ENTRY functionName
128 * END_ENTRY functionName
129 ********************************************************************/
130
131 .macro ENTRY /* name */
132 .text
133 .align 5
134 .globl $0
135 $0:
136 .endmacro
137
138 .macro STATIC_ENTRY /*name*/
139 .text
140 .align 5
141 .private_extern $0
142 $0:
143 .endmacro
144
145 .macro END_ENTRY /* name */
146 LExit$0:
147 .endmacro
148
149
150 /********************************************************************
151 * UNWIND name, flags
152 * Unwind info generation
153 ********************************************************************/
154 .macro UNWIND
155 .section __LD,__compact_unwind,regular,debug
156 PTR $0
157 .set LUnwind$0, LExit$0 - $0
158 .long LUnwind$0
159 .long $1
160 PTR 0 /* no personality */
161 PTR 0 /* no LSDA */
162 .text
163 .endmacro
164
165 #define NoFrame 0x02000000 // no frame, no SP adjustment
166 #define FrameWithNoSaves 0x04000000 // frame, no non-volatile saves
167
168
169 /********************************************************************
170 *
171 * CacheLookup NORMAL|GETIMP|LOOKUP
172 *
173 * Locate the implementation for a selector in a class method cache.
174 *
175 * Takes:
176 * x1 = selector
177 * x16 = class to be searched
178 *
179 * Kills:
180 * x9,x10,x11,x12, x17
181 *
182 * On exit: (found) calls or returns IMP
183 * with x16 = class, x17 = IMP
184 * (not found) jumps to LCacheMiss
185 *
186 ********************************************************************/
187
188 #define NORMAL 0
189 #define GETIMP 1
190 #define LOOKUP 2
191
192 // CacheHit: x17 = cached IMP, x12 = address of cached IMP
193 .macro CacheHit
194 .if $0 == NORMAL
195 TailCallCachedImp x17, x12 // authenticate and call imp
196 .elseif $0 == GETIMP
197 mov p0, p17
198 AuthAndResignAsIMP x0, x12 // authenticate imp and re-sign as IMP
199 ret // return IMP
200 .elseif $0 == LOOKUP
201 AuthAndResignAsIMP x17, x12 // authenticate imp and re-sign as IMP
202 ret // return imp via x17
203 .else
204 .abort oops
205 .endif
206 .endmacro
207
208 .macro CheckMiss
209 // miss if bucket->sel == 0
210 .if $0 == GETIMP
211 cbz p9, LGetImpMiss
212 .elseif $0 == NORMAL
213 cbz p9, __objc_msgSend_uncached
214 .elseif $0 == LOOKUP
215 cbz p9, __objc_msgLookup_uncached
216 .else
217 .abort oops
218 .endif
219 .endmacro
220
221 .macro JumpMiss
222 .if $0 == GETIMP
223 b LGetImpMiss
224 .elseif $0 == NORMAL
225 b __objc_msgSend_uncached
226 .elseif $0 == LOOKUP
227 b __objc_msgLookup_uncached
228 .else
229 .abort oops
230 .endif
231 .endmacro
232
233 .macro CacheLookup
234 // p1 = SEL, p16 = isa
235 ldp p10, p11, [x16, #CACHE] // p10 = buckets, p11 = occupied|mask
236 #if !__LP64__
237 and w11, w11, 0xffff // p11 = mask
238 #endif
239 and w12, w1, w11 // x12 = _cmd & mask
240 add p12, p10, p12, LSL #(1+PTRSHIFT)
241 // p12 = buckets + ((_cmd & mask) << (1+PTRSHIFT))
242
243 ldp p17, p9, [x12] // {imp, sel} = *bucket
244 1: cmp p9, p1 // if (bucket->sel != _cmd)
245 b.ne 2f // scan more
246 CacheHit $0 // call or return imp
247
248 2: // not hit: p12 = not-hit bucket
249 CheckMiss $0 // miss if bucket->sel == 0
250 cmp p12, p10 // wrap if bucket == buckets
251 b.eq 3f
252 ldp p17, p9, [x12, #-BUCKET_SIZE]! // {imp, sel} = *--bucket
253 b 1b // loop
254
255 3: // wrap: p12 = first bucket, w11 = mask
256 add p12, p12, w11, UXTW #(1+PTRSHIFT)
257 // p12 = buckets + (mask << 1+PTRSHIFT)
258
259 // Clone scanning loop to miss instead of hang when cache is corrupt.
260 // The slow path may detect any corruption and halt later.
261
262 ldp p17, p9, [x12] // {imp, sel} = *bucket
263 1: cmp p9, p1 // if (bucket->sel != _cmd)
264 b.ne 2f // scan more
265 CacheHit $0 // call or return imp
266
267 2: // not hit: p12 = not-hit bucket
268 CheckMiss $0 // miss if bucket->sel == 0
269 cmp p12, p10 // wrap if bucket == buckets
270 b.eq 3f
271 ldp p17, p9, [x12, #-BUCKET_SIZE]! // {imp, sel} = *--bucket
272 b 1b // loop
273
274 3: // double wrap
275 JumpMiss $0
276
277 .endmacro
278
279
280 /********************************************************************
281 *
282 * id objc_msgSend(id self, SEL _cmd, ...);
283 * IMP objc_msgLookup(id self, SEL _cmd, ...);
284 *
285 * objc_msgLookup ABI:
286 * IMP returned in x17
287 * x16 reserved for our use but not used
288 *
289 ********************************************************************/
290
291 #if SUPPORT_TAGGED_POINTERS
292 .data
293 .align 3
294 .globl _objc_debug_taggedpointer_classes
295 _objc_debug_taggedpointer_classes:
296 .fill 16, 8, 0
297 .globl _objc_debug_taggedpointer_ext_classes
298 _objc_debug_taggedpointer_ext_classes:
299 .fill 256, 8, 0
300 #endif
301
302 ENTRY _objc_msgSend
303 UNWIND _objc_msgSend, NoFrame
304
305 cmp p0, #0 // nil check and tagged pointer check
306 #if SUPPORT_TAGGED_POINTERS
307 b.le LNilOrTagged // (MSB tagged pointer looks negative)
308 #else
309 b.eq LReturnZero
310 #endif
311 ldr p13, [x0] // p13 = isa
312 GetClassFromIsa_p16 p13 // p16 = class
313 LGetIsaDone:
314 CacheLookup NORMAL // calls imp or objc_msgSend_uncached
315
316 #if SUPPORT_TAGGED_POINTERS
317 LNilOrTagged:
318 b.eq LReturnZero // nil check
319
320 // tagged
321 adrp x10, _objc_debug_taggedpointer_classes@PAGE
322 add x10, x10, _objc_debug_taggedpointer_classes@PAGEOFF
323 ubfx x11, x0, #60, #4
324 ldr x16, [x10, x11, LSL #3]
325 adrp x10, _OBJC_CLASS_$___NSUnrecognizedTaggedPointer@PAGE
326 add x10, x10, _OBJC_CLASS_$___NSUnrecognizedTaggedPointer@PAGEOFF
327 cmp x10, x16
328 b.ne LGetIsaDone
329
330 // ext tagged
331 adrp x10, _objc_debug_taggedpointer_ext_classes@PAGE
332 add x10, x10, _objc_debug_taggedpointer_ext_classes@PAGEOFF
333 ubfx x11, x0, #52, #8
334 ldr x16, [x10, x11, LSL #3]
335 b LGetIsaDone
336 // SUPPORT_TAGGED_POINTERS
337 #endif
338
339 LReturnZero:
340 // x0 is already zero
341 mov x1, #0
342 movi d0, #0
343 movi d1, #0
344 movi d2, #0
345 movi d3, #0
346 ret
347
348 END_ENTRY _objc_msgSend
349
350
351 ENTRY _objc_msgLookup
352 UNWIND _objc_msgLookup, NoFrame
353 cmp p0, #0 // nil check and tagged pointer check
354 #if SUPPORT_TAGGED_POINTERS
355 b.le LLookup_NilOrTagged // (MSB tagged pointer looks negative)
356 #else
357 b.eq LLookup_Nil
358 #endif
359 ldr p13, [x0] // p13 = isa
360 GetClassFromIsa_p16 p13 // p16 = class
361 LLookup_GetIsaDone:
362 CacheLookup LOOKUP // returns imp
363
364 #if SUPPORT_TAGGED_POINTERS
365 LLookup_NilOrTagged:
366 b.eq LLookup_Nil // nil check
367
368 // tagged
369 mov x10, #0xf000000000000000
370 cmp x0, x10
371 b.hs LLookup_ExtTag
372 adrp x10, _objc_debug_taggedpointer_classes@PAGE
373 add x10, x10, _objc_debug_taggedpointer_classes@PAGEOFF
374 ubfx x11, x0, #60, #4
375 ldr x16, [x10, x11, LSL #3]
376 b LLookup_GetIsaDone
377
378 LLookup_ExtTag:
379 adrp x10, _objc_debug_taggedpointer_ext_classes@PAGE
380 add x10, x10, _objc_debug_taggedpointer_ext_classes@PAGEOFF
381 ubfx x11, x0, #52, #8
382 ldr x16, [x10, x11, LSL #3]
383 b LLookup_GetIsaDone
384 // SUPPORT_TAGGED_POINTERS
385 #endif
386
387 LLookup_Nil:
388 adrp x17, __objc_msgNil@PAGE
389 add x17, x17, __objc_msgNil@PAGEOFF
390 ret
391
392 END_ENTRY _objc_msgLookup
393
394
395 STATIC_ENTRY __objc_msgNil
396
397 // x0 is already zero
398 mov x1, #0
399 movi d0, #0
400 movi d1, #0
401 movi d2, #0
402 movi d3, #0
403 ret
404
405 END_ENTRY __objc_msgNil
406
407
408 ENTRY _objc_msgSendSuper
409 UNWIND _objc_msgSendSuper, NoFrame
410
411 ldp p0, p16, [x0] // p0 = real receiver, p16 = class
412 CacheLookup NORMAL // calls imp or objc_msgSend_uncached
413
414 END_ENTRY _objc_msgSendSuper
415
416 // no _objc_msgLookupSuper
417
418 ENTRY _objc_msgSendSuper2
419 UNWIND _objc_msgSendSuper2, NoFrame
420
421 ldp p0, p16, [x0] // p0 = real receiver, p16 = class
422 ldr p16, [x16, #SUPERCLASS] // p16 = class->superclass
423 CacheLookup NORMAL
424
425 END_ENTRY _objc_msgSendSuper2
426
427
428 ENTRY _objc_msgLookupSuper2
429 UNWIND _objc_msgLookupSuper2, NoFrame
430
431 ldp p0, p16, [x0] // p0 = real receiver, p16 = class
432 ldr p16, [x16, #SUPERCLASS] // p16 = class->superclass
433 CacheLookup LOOKUP
434
435 END_ENTRY _objc_msgLookupSuper2
436
437
438 .macro MethodTableLookup
439
440 // push frame
441 SignLR
442 stp fp, lr, [sp, #-16]!
443 mov fp, sp
444
445 // save parameter registers: x0..x8, q0..q7
446 sub sp, sp, #(10*8 + 8*16)
447 stp q0, q1, [sp, #(0*16)]
448 stp q2, q3, [sp, #(2*16)]
449 stp q4, q5, [sp, #(4*16)]
450 stp q6, q7, [sp, #(6*16)]
451 stp x0, x1, [sp, #(8*16+0*8)]
452 stp x2, x3, [sp, #(8*16+2*8)]
453 stp x4, x5, [sp, #(8*16+4*8)]
454 stp x6, x7, [sp, #(8*16+6*8)]
455 str x8, [sp, #(8*16+8*8)]
456
457 // receiver and selector already in x0 and x1
458 mov x2, x16
459 bl __class_lookupMethodAndLoadCache3
460
461 // IMP in x0
462 mov x17, x0
463
464 // restore registers and return
465 ldp q0, q1, [sp, #(0*16)]
466 ldp q2, q3, [sp, #(2*16)]
467 ldp q4, q5, [sp, #(4*16)]
468 ldp q6, q7, [sp, #(6*16)]
469 ldp x0, x1, [sp, #(8*16+0*8)]
470 ldp x2, x3, [sp, #(8*16+2*8)]
471 ldp x4, x5, [sp, #(8*16+4*8)]
472 ldp x6, x7, [sp, #(8*16+6*8)]
473 ldr x8, [sp, #(8*16+8*8)]
474
475 mov sp, fp
476 ldp fp, lr, [sp], #16
477 AuthenticateLR
478
479 .endmacro
480
481 STATIC_ENTRY __objc_msgSend_uncached
482 UNWIND __objc_msgSend_uncached, FrameWithNoSaves
483
484 // THIS IS NOT A CALLABLE C FUNCTION
485 // Out-of-band p16 is the class to search
486
487 MethodTableLookup
488 TailCallFunctionPointer x17
489
490 END_ENTRY __objc_msgSend_uncached
491
492
493 STATIC_ENTRY __objc_msgLookup_uncached
494 UNWIND __objc_msgLookup_uncached, FrameWithNoSaves
495
496 // THIS IS NOT A CALLABLE C FUNCTION
497 // Out-of-band p16 is the class to search
498
499 MethodTableLookup
500 ret
501
502 END_ENTRY __objc_msgLookup_uncached
503
504
505 STATIC_ENTRY _cache_getImp
506
507 GetClassFromIsa_p16 p0
508 CacheLookup GETIMP
509
510 LGetImpMiss:
511 mov p0, #0
512 ret
513
514 END_ENTRY _cache_getImp
515
516
517 /********************************************************************
518 *
519 * id _objc_msgForward(id self, SEL _cmd,...);
520 *
521 * _objc_msgForward is the externally-callable
522 * function returned by things like method_getImplementation().
523 * _objc_msgForward_impcache is the function pointer actually stored in
524 * method caches.
525 *
526 ********************************************************************/
527
528 STATIC_ENTRY __objc_msgForward_impcache
529
530 // No stret specialization.
531 b __objc_msgForward
532
533 END_ENTRY __objc_msgForward_impcache
534
535
536 ENTRY __objc_msgForward
537
538 adrp x17, __objc_forward_handler@PAGE
539 ldr p17, [x17, __objc_forward_handler@PAGEOFF]
540 TailCallFunctionPointer x17
541
542 END_ENTRY __objc_msgForward
543
544
545 ENTRY _objc_msgSend_noarg
546 b _objc_msgSend
547 END_ENTRY _objc_msgSend_noarg
548
549 ENTRY _objc_msgSend_debug
550 b _objc_msgSend
551 END_ENTRY _objc_msgSend_debug
552
553 ENTRY _objc_msgSendSuper2_debug
554 b _objc_msgSendSuper2
555 END_ENTRY _objc_msgSendSuper2_debug
556
557
558 ENTRY _method_invoke
559 // x1 is method triplet instead of SEL
560 add p16, p1, #METHOD_IMP
561 ldr p17, [x16]
562 ldr p1, [x1, #METHOD_NAME]
563 TailCallMethodListImp x17, x16
564 END_ENTRY _method_invoke
565
566 #endif