objc-msg-arm64.s 13 KB

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