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
195 TailCallCachedImp x17, x12 // authenticate and call imp
198 AuthAndResignAsIMP x0, x12 // authenticate imp and re-sign as IMP
201 AuthAndResignAsIMP x17, x12 // authenticate imp and re-sign as IMP
202 ret // return imp via x17
209 // miss if bucket->sel == 0
213 cbz p9, __objc_msgSend_uncached
215 cbz p9, __objc_msgLookup_uncached
225 b __objc_msgSend_uncached
227 b __objc_msgLookup_uncached
234 // p1 = SEL, p16 = isa
235 ldp p10, p11, [x16, #CACHE] // p10 = buckets, p11 = occupied|mask
237 and w11, w11, 0xffff // p11 = mask
239 and w12, w1, w11 // x12 = _cmd & mask
240 add p12, p10, p12, LSL #(1+PTRSHIFT)
241 // p12 = buckets + ((_cmd & mask) << (1+PTRSHIFT))
243 ldp p17, p9, [x12] // {imp, sel} = *bucket
244 1: cmp p9, p1 // if (bucket->sel != _cmd)
246 CacheHit $0 // call or return imp
248 2: // not hit: p12 = not-hit bucket
249 CheckMiss $0 // miss if bucket->sel == 0
250 cmp p12, p10 // wrap if bucket == buckets
252 ldp p17, p9, [x12, #-BUCKET_SIZE]! // {imp, sel} = *--bucket
255 3: // wrap: p12 = first bucket, w11 = mask
256 add p12, p12, w11, UXTW #(1+PTRSHIFT)
257 // p12 = buckets + (mask << 1+PTRSHIFT)
259 // Clone scanning loop to miss instead of hang when cache is corrupt.
260 // The slow path may detect any corruption and halt later.
262 ldp p17, p9, [x12] // {imp, sel} = *bucket
263 1: cmp p9, p1 // if (bucket->sel != _cmd)
265 CacheHit $0 // call or return imp
267 2: // not hit: p12 = not-hit bucket
268 CheckMiss $0 // miss if bucket->sel == 0
269 cmp p12, p10 // wrap if bucket == buckets
271 ldp p17, p9, [x12, #-BUCKET_SIZE]! // {imp, sel} = *--bucket
280 /********************************************************************
282 * id objc_msgSend(id self, SEL _cmd, ...);
283 * IMP objc_msgLookup(id self, SEL _cmd, ...);
285 * objc_msgLookup ABI:
286 * IMP returned in x17
287 * x16 reserved for our use but not used
289 ********************************************************************/
291 #if SUPPORT_TAGGED_POINTERS
294 .globl _objc_debug_taggedpointer_classes
295 _objc_debug_taggedpointer_classes:
297 .globl _objc_debug_taggedpointer_ext_classes
298 _objc_debug_taggedpointer_ext_classes:
303 UNWIND _objc_msgSend, NoFrame
305 cmp p0, #0 // nil check and tagged pointer check
306 #if SUPPORT_TAGGED_POINTERS
307 b.le LNilOrTagged // (MSB tagged pointer looks negative)
311 ldr p13, [x0] // p13 = isa
312 GetClassFromIsa_p16 p13 // p16 = class
314 CacheLookup NORMAL // calls imp or objc_msgSend_uncached
316 #if SUPPORT_TAGGED_POINTERS
318 b.eq LReturnZero // nil check
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
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]
336 // SUPPORT_TAGGED_POINTERS
340 // x0 is already zero
348 END_ENTRY _objc_msgSend
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)
359 ldr p13, [x0] // p13 = isa
360 GetClassFromIsa_p16 p13 // p16 = class
362 CacheLookup LOOKUP // returns imp
364 #if SUPPORT_TAGGED_POINTERS
366 b.eq LLookup_Nil // nil check
369 mov x10, #0xf000000000000000
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]
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]
384 // SUPPORT_TAGGED_POINTERS
388 adrp x17, __objc_msgNil@PAGE
389 add x17, x17, __objc_msgNil@PAGEOFF
392 END_ENTRY _objc_msgLookup
395 STATIC_ENTRY __objc_msgNil
397 // x0 is already zero
405 END_ENTRY __objc_msgNil
408 ENTRY _objc_msgSendSuper
409 UNWIND _objc_msgSendSuper, NoFrame
411 ldp p0, p16, [x0] // p0 = real receiver, p16 = class
412 CacheLookup NORMAL // calls imp or objc_msgSend_uncached
414 END_ENTRY _objc_msgSendSuper
416 // no _objc_msgLookupSuper
418 ENTRY _objc_msgSendSuper2
419 UNWIND _objc_msgSendSuper2, NoFrame
421 ldp p0, p16, [x0] // p0 = real receiver, p16 = class
422 ldr p16, [x16, #SUPERCLASS] // p16 = class->superclass
425 END_ENTRY _objc_msgSendSuper2
428 ENTRY _objc_msgLookupSuper2
429 UNWIND _objc_msgLookupSuper2, NoFrame
431 ldp p0, p16, [x0] // p0 = real receiver, p16 = class
432 ldr p16, [x16, #SUPERCLASS] // p16 = class->superclass
435 END_ENTRY _objc_msgLookupSuper2
438 .macro MethodTableLookup
442 stp fp, lr, [sp, #-16]!
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)]
457 // receiver and selector already in x0 and x1
459 bl __class_lookupMethodAndLoadCache3
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)]
476 ldp fp, lr, [sp], #16
481 STATIC_ENTRY __objc_msgSend_uncached
482 UNWIND __objc_msgSend_uncached, FrameWithNoSaves
484 // THIS IS NOT A CALLABLE C FUNCTION
485 // Out-of-band p16 is the class to search
488 TailCallFunctionPointer x17
490 END_ENTRY __objc_msgSend_uncached
493 STATIC_ENTRY __objc_msgLookup_uncached
494 UNWIND __objc_msgLookup_uncached, FrameWithNoSaves
496 // THIS IS NOT A CALLABLE C FUNCTION
497 // Out-of-band p16 is the class to search
502 END_ENTRY __objc_msgLookup_uncached
505 STATIC_ENTRY _cache_getImp
507 GetClassFromIsa_p16 p0
514 END_ENTRY _cache_getImp
517 /********************************************************************
519 * id _objc_msgForward(id self, SEL _cmd,...);
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
526 ********************************************************************/
528 STATIC_ENTRY __objc_msgForward_impcache
530 // No stret specialization.
533 END_ENTRY __objc_msgForward_impcache
536 ENTRY __objc_msgForward
538 adrp x17, __objc_forward_handler@PAGE
539 ldr p17, [x17, __objc_forward_handler@PAGEOFF]
540 TailCallFunctionPointer x17
542 END_ENTRY __objc_msgForward
545 ENTRY _objc_msgSend_noarg
547 END_ENTRY _objc_msgSend_noarg
549 ENTRY _objc_msgSend_debug
551 END_ENTRY _objc_msgSend_debug
553 ENTRY _objc_msgSendSuper2_debug
554 b _objc_msgSendSuper2
555 END_ENTRY _objc_msgSendSuper2_debug
559 // x1 is method triplet instead of SEL
560 add p16, p1, #METHOD_IMP
562 ldr p1, [x1, #METHOD_NAME]
563 TailCallMethodListImp x17, x16
564 END_ENTRY _method_invoke