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// _objc_entryPoints and _objc_exitPoints are used by method dispatch 35// caching code to figure out whether any threads are actively 36// in the cache for dispatching. The labels surround the asm code 37// that do cache lookups. The tables are zero-terminated. 38.data 39.private_extern _objc_entryPoints 40_objc_entryPoints: 41 .quad _cache_getImp 42 .quad _objc_msgSend 43 .quad _objc_msgSendSuper 44 .quad _objc_msgSendSuper2 45 .quad 0 46 47.data 48.private_extern _objc_exitPoints 49_objc_exitPoints: 50 .quad LExit_cache_getImp 51 .quad LExit_objc_msgSend 52 .quad LExit_objc_msgSendSuper 53 .quad LExit_objc_msgSendSuper2 54 .quad 0 55 56 57/******************************************************************** 58* List every exit insn from every messenger for debugger use. 59* Format: 60* ( 61* 1 word instruction's address 62* 1 word type (ENTER or FAST_EXIT or SLOW_EXIT or NIL_EXIT) 63* ) 64* 1 word zero 65* 66* ENTER is the start of a dispatcher 67* FAST_EXIT is method dispatch 68* SLOW_EXIT is uncached method lookup 69* NIL_EXIT is returning zero from a message sent to nil 70* These must match objc-gdb.h. 71********************************************************************/ 72 73#define ENTER 1 74#define FAST_EXIT 2 75#define SLOW_EXIT 3 76#define NIL_EXIT 4 77 78.section __DATA,__objc_msg_break 79.globl _gdb_objc_messenger_breakpoints 80_gdb_objc_messenger_breakpoints: 81// contents populated by the macros below 82 83.macro MESSENGER_START 844: 85 .section __DATA,__objc_msg_break 86 .quad 4b 87 .quad ENTER 88 .text 89.endmacro 90.macro MESSENGER_END_FAST 914: 92 .section __DATA,__objc_msg_break 93 .quad 4b 94 .quad FAST_EXIT 95 .text 96.endmacro 97.macro MESSENGER_END_SLOW 984: 99 .section __DATA,__objc_msg_break 100 .quad 4b 101 .quad SLOW_EXIT 102 .text 103.endmacro 104.macro MESSENGER_END_NIL 1054: 106 .section __DATA,__objc_msg_break 107 .quad 4b 108 .quad NIL_EXIT 109 .text 110.endmacro 111 112 113/* objc_super parameter to sendSuper */ 114#define RECEIVER 0 115#define CLASS 8 116 117/* Selected field offsets in class structure */ 118#define SUPERCLASS 8 119#define CACHE 16 120 121/* Selected field offsets in isa field */ 122#define ISA_MASK 0x00000001fffffff8 123 124/* Selected field offsets in method structure */ 125#define METHOD_NAME 0 126#define METHOD_TYPES 8 127#define METHOD_IMP 16 128 129 130/******************************************************************** 131 * ENTRY functionName 132 * STATIC_ENTRY functionName 133 * END_ENTRY functionName 134 ********************************************************************/ 135 136.macro ENTRY /* name */ 137 .text 138 .align 5 139 .globl $0 140$0: 141.endmacro 142 143.macro STATIC_ENTRY /*name*/ 144 .text 145 .align 5 146 .private_extern $0 147$0: 148.endmacro 149 150.macro END_ENTRY /* name */ 151LExit$0: 152.endmacro 153 154 155/******************************************************************** 156 * 157 * CacheLookup NORMAL|GETIMP 158 * 159 * Locate the implementation for a selector in a class method cache. 160 * 161 * Takes: 162 * x1 = selector 163 * x9 = class to be searched 164 * 165 * Kills: 166 * x10,x11,x12, x16,x17 167 * 168 * On exit: (found) exits CacheLookup 169 * with x9 = class, x17 = IMP 170 * (not found) jumps to LCacheMiss 171 * 172 ********************************************************************/ 173 174#define NORMAL 0 175#define GETIMP 1 176 177.macro CacheHit 178 MESSENGER_END_FAST 179.if $0 == NORMAL 180 br x17 // call imp 181.else 182 b LGetImpHit 183.endif 184.endmacro 185 186.macro CheckMiss 187.if $0 == NORMAL // miss if bucket->cls == 0 188 cbz x16, __objc_msgSend_uncached_impcache 189.else 190 cbz x16, LGetImpMiss 191.endif 192.endmacro 193 194.macro CacheLookup 195 // x1 = SEL, x9 = isa 196 ldp x10, x11, [x9, #CACHE] // x10 = buckets, x11 = occupied|mask 197 and w12, w1, w11 // x12 = _cmd & mask 198 add x12, x10, x12, LSL #4 // x12 = buckets + ((_cmd & mask)<<4) 199 200 ldp x16, x17, [x12] // {x16, x17} = *bucket 2011: cmp x16, x1 // if (bucket->sel != _cmd) 202 b.ne 2f // scan more 203 CacheHit $0 // call or return imp 204 2052: // not hit: x12 = not-hit bucket 206 CheckMiss $0 // miss if bucket->cls == 0 207 cmp x12, x10 // wrap if bucket == buckets 208 b.eq 3f 209 ldp x16, x17, [x12, #-16]! // {x16, x17} = *--bucket 210 b 1b // loop 211 2123: // wrap: x12 = first bucket, w11 = mask 213 add x12, x12, w11, UXTW #4 // x12 = buckets+(mask<<4) 214 215 // clone scanning loop to crash instead of hang when cache is corrupt 216 217 ldp x16, x17, [x12] // {x16, x17} = *bucket 2181: cmp x16, x1 // if (bucket->sel != _cmd) 219 b.ne 2f // scan more 220 CacheHit $0 // call or return imp 221 2222: // not hit: x12 = not-hit bucket 223 CheckMiss $0 // miss if bucket->cls == 0 224 cmp x12, x10 // wrap if bucket == buckets 225 b.eq 3f 226 ldp x16, x17, [x12, #-16]! // {x16, x17} = *--bucket 227 b 1b // loop 228 2293: // double wrap - busted 230 // x0 = receiver 231 // x1 = SEL 232 mov x2, x9 // x2 = isa 233 234.if $0 == GETIMP 235 mov x0, #0 236 b _cache_getImp_corrupt_cache_error 237.else 238 b _objc_msgSend_corrupt_cache_error 239.endif 240 241.endmacro 242 243 244 .data 245 .align 3 246 .globl _objc_debug_taggedpointer_classes 247_objc_debug_taggedpointer_classes: 248 .fill 16, 8, 0 249 250 ENTRY _objc_msgSend 251 MESSENGER_START 252 253 cmp x0, #0 // nil check and tagged pointer check 254 b.le LNilOrTagged // (MSB tagged pointer looks negative) 255 ldr x13, [x0] // x13 = isa 256 and x9, x13, #ISA_MASK // x9 = class 257LGetIsaDone: 258 CacheLookup NORMAL // calls imp or objc_msgSend_uncached 259 260LNilOrTagged: 261 b.eq LReturnZero // nil check 262 263 // tagged 264 adrp x10, _objc_debug_taggedpointer_classes@PAGE 265 add x10, x10, _objc_debug_taggedpointer_classes@PAGEOFF 266 ubfx x11, x0, #60, #4 267 ldr x9, [x10, x11, LSL #3] 268 b LGetIsaDone 269 270LReturnZero: 271 // x0 is already zero 272 mov x1, #0 273 movi d0, #0 274 movi d1, #0 275 movi d2, #0 276 movi d3, #0 277 MESSENGER_END_NIL 278 ret 279 280 END_ENTRY _objc_msgSend 281 282 283 ENTRY _objc_msgSendSuper 284 MESSENGER_START 285 286 ldr x9, [x0, #CLASS] // load class to search 287 ldr x0, [x0, #RECEIVER] // load real receiver 288 CacheLookup NORMAL // calls imp or objc_msgSend_uncached 289 290 END_ENTRY _objc_msgSendSuper 291 292 293 ENTRY _objc_msgSendSuper2 294 MESSENGER_START 295 296 ldr x9, [x0, #CLASS] 297 ldr x9, [x9, #SUPERCLASS] // load class to search 298 ldr x0, [x0, #RECEIVER] // load real receiver 299 CacheLookup NORMAL 300 301 END_ENTRY _objc_msgSendSuper2 302 303 304 ENTRY _objc_msgSend_noarg 305 b _objc_msgSend 306 END_ENTRY _objc_msgSend_noarg 307 308 309 STATIC_ENTRY __objc_msgSend_uncached_impcache 310 311 // THIS IS NOT A CALLABLE C FUNCTION 312 // Out-of-band x9 is the class to search 313 314 MESSENGER_START 315 316 // push frame 317 stp fp, lr, [sp, #-16]! 318 mov fp, sp 319 320 MESSENGER_END_SLOW 321 322 // save parameter registers: x0..x8, q0..q7 323 sub sp, sp, #(10*8 + 8*16) 324 stp q0, q1, [sp, #(0*16)] 325 stp q2, q3, [sp, #(2*16)] 326 stp q4, q5, [sp, #(4*16)] 327 stp q6, q7, [sp, #(6*16)] 328 stp x0, x1, [sp, #(8*16+0*8)] 329 stp x2, x3, [sp, #(8*16+2*8)] 330 stp x4, x5, [sp, #(8*16+4*8)] 331 stp x6, x7, [sp, #(8*16+6*8)] 332 str x8, [sp, #(8*16+8*8)] 333 334 // receiver and selector already in x0 and x1 335 mov x2, x9 336 bl __class_lookupMethodAndLoadCache3 337 338 // imp in x0 339 mov x17, x0 340 341 // restore registers and return 342 ldp q0, q1, [sp, #(0*16)] 343 ldp q2, q3, [sp, #(2*16)] 344 ldp q4, q5, [sp, #(4*16)] 345 ldp q6, q7, [sp, #(6*16)] 346 ldp x0, x1, [sp, #(8*16+0*8)] 347 ldp x2, x3, [sp, #(8*16+2*8)] 348 ldp x4, x5, [sp, #(8*16+4*8)] 349 ldp x6, x7, [sp, #(8*16+6*8)] 350 ldr x8, [sp, #(8*16+8*8)] 351 352 mov sp, fp 353 ldp fp, lr, [sp], #16 354 355 br x17 356 357 END_ENTRY __objc_msgSend_uncached_impcache 358 359 360.section __LD,__compact_unwind,regular,debug 361 .quad _objc_msgSend 362 .set LUnwind_objc_msgSend, LExit_objc_msgSend-_objc_msgSend 363 .long LUnwind_objc_msgSend 364 .long 0x02000000 // no frame, no SP adjustment 365 .quad 0 // no personality 366 .quad 0 // no LSDA 367 368.section __LD,__compact_unwind,regular,debug 369 .quad _objc_msgSendSuper 370 .set LUnwind_objc_msgSendSuper, LExit_objc_msgSendSuper-_objc_msgSendSuper 371 .long LUnwind_objc_msgSendSuper 372 .long 0x02000000 // no frame, no SP adjustment 373 .quad 0 // no personality 374 .quad 0 // no LSDA 375 376.section __LD,__compact_unwind,regular,debug 377 .quad _objc_msgSendSuper2 378 .set LUnwind_objc_msgSendSuper2, LExit_objc_msgSendSuper2-_objc_msgSendSuper2 379 .long LUnwind_objc_msgSendSuper2 380 .long 0x02000000 // no frame, no SP adjustment 381 .quad 0 // no personality 382 .quad 0 // no LSDA 383 384.section __LD,__compact_unwind,regular,debug 385 .quad __objc_msgSend_uncached_impcache 386 .set LUnwind__objc_msgSend_uncached_impcache, LExit__objc_msgSend_uncached_impcache-__objc_msgSend_uncached_impcache 387 .long LUnwind__objc_msgSend_uncached_impcache 388 .long 0x04000000 // frame, no non-volatile registers saved 389 .quad 0 // no personality 390 .quad 0 // no LSDA 391 392 393 STATIC_ENTRY _cache_getImp 394 395 and x9, x0, #ISA_MASK 396 CacheLookup GETIMP 397 398LGetImpHit: 399 // imp in x17 400 // don't return msgSend_uncached 401 adrp x16, __objc_msgSend_uncached_impcache@PAGE 402 add x16, x16, __objc_msgSend_uncached_impcache@PAGEOFF 403 cmp x16, x17 404 csel x0, x17, xzr, ne // if imp!=uncached then imp else 0 405 ret 406 407LGetImpMiss: 408 mov x0, #0 409 ret 410 411 END_ENTRY _cache_getImp 412 413 414/******************************************************************** 415* 416* id _objc_msgForward(id self, SEL _cmd,...); 417* 418* _objc_msgForward is the externally-callable 419* function returned by things like method_getImplementation(). 420* _objc_msgForward_impcache is the function pointer actually stored in 421* method caches. 422* 423********************************************************************/ 424 425 STATIC_ENTRY __objc_msgForward_impcache 426 427 MESSENGER_START 428 nop 429 MESSENGER_END_SLOW 430 431 // No stret specialization. 432 b __objc_msgForward 433 434 END_ENTRY __objc_msgForward_impcache 435 436 437 ENTRY __objc_msgForward 438 439 adrp x17, __objc_forward_handler@PAGE 440 ldr x17, [x17, __objc_forward_handler@PAGEOFF] 441 br x17 442 443 END_ENTRY __objc_msgForward 444 445 446 ENTRY _objc_msgSend_debug 447 b _objc_msgSend 448 END_ENTRY _objc_msgSend_debug 449 450 ENTRY _objc_msgSendSuper2_debug 451 b _objc_msgSendSuper2 452 END_ENTRY _objc_msgSendSuper2_debug 453 454 455 ENTRY _method_invoke 456 // x1 is method triplet instead of SEL 457 ldr x17, [x1, #METHOD_IMP] 458 ldr x1, [x1, #METHOD_NAME] 459 br x17 460 END_ENTRY _method_invoke 461 462 463 STATIC_ENTRY __objc_ignored_method 464 465 // self is already in x0 466 ret 467 468 END_ENTRY __objc_ignored_method 469 470#endif 471