2 * @APPLE_LICENSE_HEADER_START@
4 * Copyright (c) 2011 Apple Inc. All Rights Reserved.
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
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.
21 * @APPLE_LICENSE_HEADER_END@
23 /********************************************************************
25 * objc-msg-arm64.s - ARM64 code to support objc messaging
27 ********************************************************************/
33 #include "arm64-asm.h"
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.
43 .private_extern _objc_entryPoints
47 PTR _objc_msgSendSuper
48 PTR _objc_msgSendSuper2
50 PTR _objc_msgLookupSuper2
53 .private_extern _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
64 /* objc_super parameter to sendSuper */
66 #define CLASS __SIZEOF_POINTER__
68 /* Selected field offsets in class structure */
69 #define SUPERCLASS __SIZEOF_POINTER__
70 #define CACHE (2 * __SIZEOF_POINTER__)
72 /* Selected field offsets in method structure */
74 #define METHOD_TYPES __SIZEOF_POINTER__
75 #define METHOD_IMP (2 * __SIZEOF_POINTER__)
77 #define BUCKET_SIZE (2 * __SIZEOF_POINTER__)
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.
88 * p16 is a class pointer
90 ********************************************************************/
92 #if SUPPORT_INDEXED_ISA
94 .globl _objc_indexed_classes
95 _objc_indexed_classes:
96 .fill ISA_INDEX_COUNT, PTRSIZE, 0
99 .macro GetClassFromIsa_p16 /* src */
101 #if SUPPORT_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
114 and p16, $0, #ISA_MASK
125 /********************************************************************
127 * STATIC_ENTRY functionName
128 * END_ENTRY functionName
129 ********************************************************************/
131 .macro ENTRY /* name */
138 .macro STATIC_ENTRY /*name*/
145 .macro END_ENTRY /* name */
150 /********************************************************************
152 * Unwind info generation
153 ********************************************************************/
155 .section __LD,__compact_unwind,regular,debug
157 .set LUnwind$0, LExit$0 - $0
160 PTR 0 /* no personality */
165 #define NoFrame 0x02000000 // no frame, no SP adjustment
166 #define FrameWithNoSaves 0x04000000 // frame, no non-volatile saves
169 /********************************************************************
171 * CacheLookup NORMAL|GETIMP|LOOKUP
173 * Locate the implementation for a selector in a class method cache.
177 * x16 = class to be searched
180 * x9,x10,x11,x12, x17
182 * On exit: (found) calls or returns IMP
183 * with x16 = class, x17 = IMP
184 * (not found) jumps to LCacheMiss
186 ********************************************************************/
192 // CacheHit: x17 = cached IMP, x12 = address of cached IMP, x1 = SEL
195 TailCallCachedImp x17, x12, x1 // authenticate and call imp
198 cbz p0, 9f // don't ptrauth a nil imp
199 AuthAndResignAsIMP x0, x12, x1 // authenticate imp and re-sign as IMP
202 // No nil check for ptrauth: the caller would crash anyway when they
203 // jump to a nil IMP. We don't care if that jump also fails ptrauth.
204 AuthAndResignAsIMP x17, x12, x1 // authenticate imp and re-sign as IMP
205 ret // return imp via x17
212 // miss if bucket->sel == 0
216 cbz p9, __objc_msgSend_uncached
218 cbz p9, __objc_msgLookup_uncached
228 b __objc_msgSend_uncached
230 b __objc_msgLookup_uncached
237 // p1 = SEL, p16 = isa
238 ldp p10, p11, [x16, #CACHE] // p10 = buckets, p11 = occupied|mask
240 and w11, w11, 0xffff // p11 = mask
242 and w12, w1, w11 // x12 = _cmd & mask
243 add p12, p10, p12, LSL #(1+PTRSHIFT)
244 // p12 = buckets + ((_cmd & mask) << (1+PTRSHIFT))
246 ldp p17, p9, [x12] // {imp, sel} = *bucket
247 1: cmp p9, p1 // if (bucket->sel != _cmd)
249 CacheHit $0 // call or return imp
251 2: // not hit: p12 = not-hit bucket
252 CheckMiss $0 // miss if bucket->sel == 0
253 cmp p12, p10 // wrap if bucket == buckets
255 ldp p17, p9, [x12, #-BUCKET_SIZE]! // {imp, sel} = *--bucket
258 3: // wrap: p12 = first bucket, w11 = mask
259 add p12, p12, w11, UXTW #(1+PTRSHIFT)
260 // p12 = buckets + (mask << 1+PTRSHIFT)
262 // Clone scanning loop to miss instead of hang when cache is corrupt.
263 // The slow path may detect any corruption and halt later.
265 ldp p17, p9, [x12] // {imp, sel} = *bucket
266 1: cmp p9, p1 // if (bucket->sel != _cmd)
268 CacheHit $0 // call or return imp
270 2: // not hit: p12 = not-hit bucket
271 CheckMiss $0 // miss if bucket->sel == 0
272 cmp p12, p10 // wrap if bucket == buckets
274 ldp p17, p9, [x12, #-BUCKET_SIZE]! // {imp, sel} = *--bucket
283 /********************************************************************
285 * id objc_msgSend(id self, SEL _cmd, ...);
286 * IMP objc_msgLookup(id self, SEL _cmd, ...);
288 * objc_msgLookup ABI:
289 * IMP returned in x17
290 * x16 reserved for our use but not used
292 ********************************************************************/
294 #if SUPPORT_TAGGED_POINTERS
297 .globl _objc_debug_taggedpointer_classes
298 _objc_debug_taggedpointer_classes:
300 .globl _objc_debug_taggedpointer_ext_classes
301 _objc_debug_taggedpointer_ext_classes:
306 UNWIND _objc_msgSend, NoFrame
308 cmp p0, #0 // nil check and tagged pointer check
309 #if SUPPORT_TAGGED_POINTERS
310 b.le LNilOrTagged // (MSB tagged pointer looks negative)
314 ldr p13, [x0] // p13 = isa
315 GetClassFromIsa_p16 p13 // p16 = class
317 CacheLookup NORMAL // calls imp or objc_msgSend_uncached
319 #if SUPPORT_TAGGED_POINTERS
321 b.eq LReturnZero // nil check
324 adrp x10, _objc_debug_taggedpointer_classes@PAGE
325 add x10, x10, _objc_debug_taggedpointer_classes@PAGEOFF
326 ubfx x11, x0, #60, #4
327 ldr x16, [x10, x11, LSL #3]
328 adrp x10, _OBJC_CLASS_$___NSUnrecognizedTaggedPointer@PAGE
329 add x10, x10, _OBJC_CLASS_$___NSUnrecognizedTaggedPointer@PAGEOFF
334 adrp x10, _objc_debug_taggedpointer_ext_classes@PAGE
335 add x10, x10, _objc_debug_taggedpointer_ext_classes@PAGEOFF
336 ubfx x11, x0, #52, #8
337 ldr x16, [x10, x11, LSL #3]
339 // SUPPORT_TAGGED_POINTERS
343 // x0 is already zero
351 END_ENTRY _objc_msgSend
354 ENTRY _objc_msgLookup
355 UNWIND _objc_msgLookup, NoFrame
356 cmp p0, #0 // nil check and tagged pointer check
357 #if SUPPORT_TAGGED_POINTERS
358 b.le LLookup_NilOrTagged // (MSB tagged pointer looks negative)
362 ldr p13, [x0] // p13 = isa
363 GetClassFromIsa_p16 p13 // p16 = class
365 CacheLookup LOOKUP // returns imp
367 #if SUPPORT_TAGGED_POINTERS
369 b.eq LLookup_Nil // nil check
372 mov x10, #0xf000000000000000
375 adrp x10, _objc_debug_taggedpointer_classes@PAGE
376 add x10, x10, _objc_debug_taggedpointer_classes@PAGEOFF
377 ubfx x11, x0, #60, #4
378 ldr x16, [x10, x11, LSL #3]
382 adrp x10, _objc_debug_taggedpointer_ext_classes@PAGE
383 add x10, x10, _objc_debug_taggedpointer_ext_classes@PAGEOFF
384 ubfx x11, x0, #52, #8
385 ldr x16, [x10, x11, LSL #3]
387 // SUPPORT_TAGGED_POINTERS
391 adrp x17, __objc_msgNil@PAGE
392 add x17, x17, __objc_msgNil@PAGEOFF
395 END_ENTRY _objc_msgLookup
398 STATIC_ENTRY __objc_msgNil
400 // x0 is already zero
408 END_ENTRY __objc_msgNil
411 ENTRY _objc_msgSendSuper
412 UNWIND _objc_msgSendSuper, NoFrame
414 ldp p0, p16, [x0] // p0 = real receiver, p16 = class
415 CacheLookup NORMAL // calls imp or objc_msgSend_uncached
417 END_ENTRY _objc_msgSendSuper
419 // no _objc_msgLookupSuper
421 ENTRY _objc_msgSendSuper2
422 UNWIND _objc_msgSendSuper2, NoFrame
424 ldp p0, p16, [x0] // p0 = real receiver, p16 = class
425 ldr p16, [x16, #SUPERCLASS] // p16 = class->superclass
428 END_ENTRY _objc_msgSendSuper2
431 ENTRY _objc_msgLookupSuper2
432 UNWIND _objc_msgLookupSuper2, NoFrame
434 ldp p0, p16, [x0] // p0 = real receiver, p16 = class
435 ldr p16, [x16, #SUPERCLASS] // p16 = class->superclass
438 END_ENTRY _objc_msgLookupSuper2
441 .macro MethodTableLookup
445 stp fp, lr, [sp, #-16]!
448 // save parameter registers: x0..x8, q0..q7
449 sub sp, sp, #(10*8 + 8*16)
450 stp q0, q1, [sp, #(0*16)]
451 stp q2, q3, [sp, #(2*16)]
452 stp q4, q5, [sp, #(4*16)]
453 stp q6, q7, [sp, #(6*16)]
454 stp x0, x1, [sp, #(8*16+0*8)]
455 stp x2, x3, [sp, #(8*16+2*8)]
456 stp x4, x5, [sp, #(8*16+4*8)]
457 stp x6, x7, [sp, #(8*16+6*8)]
458 str x8, [sp, #(8*16+8*8)]
460 // receiver and selector already in x0 and x1
462 bl __class_lookupMethodAndLoadCache3
467 // restore registers and return
468 ldp q0, q1, [sp, #(0*16)]
469 ldp q2, q3, [sp, #(2*16)]
470 ldp q4, q5, [sp, #(4*16)]
471 ldp q6, q7, [sp, #(6*16)]
472 ldp x0, x1, [sp, #(8*16+0*8)]
473 ldp x2, x3, [sp, #(8*16+2*8)]
474 ldp x4, x5, [sp, #(8*16+4*8)]
475 ldp x6, x7, [sp, #(8*16+6*8)]
476 ldr x8, [sp, #(8*16+8*8)]
479 ldp fp, lr, [sp], #16
484 STATIC_ENTRY __objc_msgSend_uncached
485 UNWIND __objc_msgSend_uncached, FrameWithNoSaves
487 // THIS IS NOT A CALLABLE C FUNCTION
488 // Out-of-band p16 is the class to search
491 TailCallFunctionPointer x17
493 END_ENTRY __objc_msgSend_uncached
496 STATIC_ENTRY __objc_msgLookup_uncached
497 UNWIND __objc_msgLookup_uncached, FrameWithNoSaves
499 // THIS IS NOT A CALLABLE C FUNCTION
500 // Out-of-band p16 is the class to search
505 END_ENTRY __objc_msgLookup_uncached
508 STATIC_ENTRY _cache_getImp
510 GetClassFromIsa_p16 p0
517 END_ENTRY _cache_getImp
520 /********************************************************************
522 * id _objc_msgForward(id self, SEL _cmd,...);
524 * _objc_msgForward is the externally-callable
525 * function returned by things like method_getImplementation().
526 * _objc_msgForward_impcache is the function pointer actually stored in
529 ********************************************************************/
531 STATIC_ENTRY __objc_msgForward_impcache
533 // No stret specialization.
536 END_ENTRY __objc_msgForward_impcache
539 ENTRY __objc_msgForward
541 adrp x17, __objc_forward_handler@PAGE
542 ldr p17, [x17, __objc_forward_handler@PAGEOFF]
543 TailCallFunctionPointer x17
545 END_ENTRY __objc_msgForward
548 ENTRY _objc_msgSend_noarg
550 END_ENTRY _objc_msgSend_noarg
552 ENTRY _objc_msgSend_debug
554 END_ENTRY _objc_msgSend_debug
556 ENTRY _objc_msgSendSuper2_debug
557 b _objc_msgSendSuper2
558 END_ENTRY _objc_msgSendSuper2_debug
562 // x1 is method triplet instead of SEL
563 add p16, p1, #METHOD_IMP
565 ldr p1, [x1, #METHOD_NAME]
566 TailCallMethodListImp x17, x16
567 END_ENTRY _method_invoke