1/* 2 * @APPLE_LICENSE_HEADER_START@ 3 * 4 * Copyright (c) 1999-2007 Apple Computer, 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-arm.s - ARM code to support objc messaging 26 * 27 ********************************************************************/ 28 29#ifdef __arm__ 30 31#include <arm/arch.h> 32 33#ifndef _ARM_ARCH_7 34# error requires armv7 35#endif 36 37.syntax unified 38 39#define MI_EXTERN(var) \ 40 .non_lazy_symbol_pointer ;\ 41L ## var ## $$non_lazy_ptr: ;\ 42 .indirect_symbol var ;\ 43 .long 0 44 45#define MI_GET_EXTERN(reg,var) \ 46 movw reg, :lower16:(L##var##$$non_lazy_ptr-4f-4) ;\ 47 movt reg, :upper16:(L##var##$$non_lazy_ptr-4f-4) ;\ 484: add reg, pc ;\ 49 ldr reg, [reg] 50 51#define MI_CALL_EXTERNAL(var) \ 52 MI_GET_EXTERN(r12,var) ;\ 53 blx r12 54 55 56#define MI_GET_ADDRESS(reg,var) \ 57 movw reg, :lower16:(var-4f-4) ;\ 58 movt reg, :upper16:(var-4f-4) ;\ 594: add reg, pc ;\ 60 61 62MI_EXTERN(__class_lookupMethodAndLoadCache3) 63MI_EXTERN(___objc_error) 64 65 66// _objc_entryPoints and _objc_exitPoints are used by method dispatch 67// caching code to figure out whether any threads are actively 68// in the cache for dispatching. The labels surround the asm code 69// that do cache lookups. The tables are zero-terminated. 70.data 71.private_extern _objc_entryPoints 72_objc_entryPoints: 73 .long _cache_getImp 74 .long _objc_msgSend 75 .long _objc_msgSend_stret 76 .long _objc_msgSendSuper 77 .long _objc_msgSendSuper_stret 78 .long _objc_msgSendSuper2 79 .long _objc_msgSendSuper2_stret 80 .long 0 81 82.data 83.private_extern _objc_exitPoints 84_objc_exitPoints: 85 .long LGetImpExit 86 .long LMsgSendExit 87 .long LMsgSendStretExit 88 .long LMsgSendSuperExit 89 .long LMsgSendSuperStretExit 90 .long LMsgSendSuper2Exit 91 .long LMsgSendSuper2StretExit 92 .long 0 93 94 95/******************************************************************** 96* List every exit insn from every messenger for debugger use. 97* Format: 98* ( 99* 1 word instruction's address 100* 1 word type (ENTER or FAST_EXIT or SLOW_EXIT or NIL_EXIT) 101* ) 102* 1 word zero 103* 104* ENTER is the start of a dispatcher 105* FAST_EXIT is method dispatch 106* SLOW_EXIT is uncached method lookup 107* NIL_EXIT is returning zero from a message sent to nil 108* These must match objc-gdb.h. 109********************************************************************/ 110 111#define ENTER 1 112#define FAST_EXIT 2 113#define SLOW_EXIT 3 114#define NIL_EXIT 4 115 116.section __DATA,__objc_msg_break 117.globl _gdb_objc_messenger_breakpoints 118_gdb_objc_messenger_breakpoints: 119// contents populated by the macros below 120 121.macro MESSENGER_START 1224: 123 .section __DATA,__objc_msg_break 124 .long 4b 125 .long ENTER 126 .text 127.endmacro 128.macro MESSENGER_END_FAST 1294: 130 .section __DATA,__objc_msg_break 131 .long 4b 132 .long FAST_EXIT 133 .text 134.endmacro 135.macro MESSENGER_END_SLOW 1364: 137 .section __DATA,__objc_msg_break 138 .long 4b 139 .long SLOW_EXIT 140 .text 141.endmacro 142.macro MESSENGER_END_NIL 1434: 144 .section __DATA,__objc_msg_break 145 .long 4b 146 .long NIL_EXIT 147 .text 148.endmacro 149 150 151/******************************************************************** 152 * Names for relative labels 153 * DO NOT USE THESE LABELS ELSEWHERE 154 * Reserved labels: 8: 9: 155 ********************************************************************/ 156#define LCacheMiss 8 157#define LCacheMiss_f 8f 158#define LCacheMiss_b 8b 159#define LNilReceiver 9 160#define LNilReceiver_f 9f 161#define LNilReceiver_b 9b 162 163 164/******************************************************************** 165 * Macro parameters 166 ********************************************************************/ 167 168#define NORMAL 0 169#define FPRET 1 170#define FP2RET 2 171#define GETIMP 3 172#define STRET 4 173#define SUPER 5 174#define SUPER2 6 175#define SUPER_STRET 7 176#define SUPER2_STRET 8 177 178 179/******************************************************************** 180 * 181 * Structure definitions. 182 * 183 ********************************************************************/ 184 185/* objc_super parameter to sendSuper */ 186#define RECEIVER 0 187#define CLASS 4 188 189/* Selected field offsets in class structure */ 190#define ISA 0 191#define SUPERCLASS 4 192#define CACHE 8 193#define CACHE_MASK 12 194 195/* Selected field offsets in method structure */ 196#define METHOD_NAME 0 197#define METHOD_TYPES 4 198#define METHOD_IMP 8 199 200 201////////////////////////////////////////////////////////////////////// 202// 203// ENTRY functionName 204// 205// Assembly directives to begin an exported function. 206// 207// Takes: functionName - name of the exported function 208////////////////////////////////////////////////////////////////////// 209 210.macro ENTRY /* name */ 211 .text 212 .thumb 213 .align 5 214 .globl _$0 215 .thumb_func 216_$0: 217.endmacro 218 219.macro STATIC_ENTRY /*name*/ 220 .text 221 .thumb 222 .align 5 223 .private_extern _$0 224 .thumb_func 225_$0: 226.endmacro 227 228 229////////////////////////////////////////////////////////////////////// 230// 231// END_ENTRY functionName 232// 233// Assembly directives to end an exported function. Just a placeholder, 234// a close-parenthesis for ENTRY, until it is needed for something. 235// 236// Takes: functionName - name of the exported function 237////////////////////////////////////////////////////////////////////// 238 239.macro END_ENTRY /* name */ 240.endmacro 241 242 243///////////////////////////////////////////////////////////////////// 244// 245// CacheLookup return-type 246// 247// Locate the implementation for a selector in a class's method cache. 248// 249// Takes: 250// $0 = NORMAL, STRET, SUPER, SUPER_STRET, SUPER2, SUPER2_STRET, GETIMP 251// r0 or r1 (STRET) = receiver 252// r1 or r2 (STRET) = selector 253// r9 = class to search in 254// 255// On exit: r9 and r12 clobbered 256// (found) calls or returns IMP, eq/ne/r9 set for forwarding 257// (not found) jumps to LCacheMiss 258// 259///////////////////////////////////////////////////////////////////// 260 261.macro CacheHit 262 263.if $0 == GETIMP 264 ldr r0, [r9, #4] // r0 = bucket->imp 265 MI_GET_ADDRESS(r1, __objc_msgSend_uncached_impcache) 266 teq r0, r1 267 it eq 268 moveq r0, #0 // don't return msgSend_uncached 269 bx lr // return imp 270.elseif $0 == NORMAL 271 ldr r12, [r9, #4] // r12 = bucket->imp 272 // eq already set for nonstret forward 273 MESSENGER_END_FAST 274 bx r12 // call imp 275.elseif $0 == STRET 276 ldr r12, [r9, #4] // r12 = bucket->imp 277 movs r9, #1 // r9=1, Z=0 for stret forwarding 278 MESSENGER_END_FAST 279 bx r12 // call imp 280.elseif $0 == SUPER 281 ldr r12, [r9, #4] // r12 = bucket->imp 282 ldr r9, [r0, #CLASS] // r9 = class to search for forwarding 283 ldr r0, [r0, #RECEIVER] // fetch real receiver 284 tst r12, r12 // set ne for forwarding (r12!=0) 285 MESSENGER_END_FAST 286 bx r12 // call imp 287.elseif $0 == SUPER2 288 ldr r12, [r9, #4] // r12 = bucket->imp 289 ldr r9, [r0, #CLASS] 290 ldr r9, [r9, #SUPERCLASS] // r9 = class to search for forwarding 291 ldr r0, [r0, #RECEIVER] // fetch real receiver 292 tst r12, r12 // set ne for forwarding (r12!=0) 293 MESSENGER_END_FAST 294 bx r12 // call imp 295.elseif $0 == SUPER_STRET 296 ldr r12, [r9, #4] // r12 = bucket->imp 297 ldr r9, [r1, #CLASS] // r9 = class to search for forwarding 298 orr r9, r9, #1 // r9 = class|1 for super_stret forward 299 ldr r1, [r1, #RECEIVER] // fetch real receiver 300 tst r12, r12 // set ne for forwarding (r12!=0) 301 MESSENGER_END_FAST 302 bx r12 // call imp 303.elseif $0 == SUPER2_STRET 304 ldr r12, [r9, #4] // r12 = bucket->imp 305 ldr r9, [r1, #CLASS] // r9 = class to search for forwarding 306 ldr r9, [r9, #SUPERCLASS] // r9 = class to search for forwarding 307 orr r9, r9, #1 // r9 = class|1 for super_stret forward 308 ldr r1, [r1, #RECEIVER] // fetch real receiver 309 tst r12, r12 // set ne for forwarding (r12!=0) 310 MESSENGER_END_FAST 311 bx r12 // call imp 312.else 313.abort oops 314.endif 315 316.endmacro 317 318.macro CacheLookup 319 320 ldrh r12, [r9, #CACHE_MASK] // r12 = mask 321 ldr r9, [r9, #CACHE] // r9 = buckets 322.if $0 == STRET || $0 == SUPER_STRET 323 and r12, r12, r2 // r12 = index = SEL & mask 324.else 325 and r12, r12, r1 // r12 = index = SEL & mask 326.endif 327 add r9, r9, r12, LSL #3 // r9 = bucket = buckets+index*8 328 ldr r12, [r9] // r12 = bucket->sel 3292: 330.if $0 == STRET || $0 == SUPER_STRET 331 teq r12, r2 332.else 333 teq r12, r1 334.endif 335 bne 1f 336 CacheHit $0 3371: 338 cmp r12, #1 339 blo LCacheMiss_f // if (bucket->sel == 0) cache miss 340 it eq // if (bucket->sel == 1) cache wrap 341 ldreq r9, [r9, #4] // bucket->imp is before first bucket 342 ldr r12, [r9, #8]! // r12 = (++bucket)->sel 343 b 2b 344 345.endmacro 346 347 348/******************************************************************** 349 * IMP cache_getImp(Class cls, SEL sel) 350 * 351 * On entry: r0 = class whose cache is to be searched 352 * r1 = selector to search for 353 * 354 * If found, returns method implementation. 355 * If not found, returns NULL. 356 ********************************************************************/ 357 358 STATIC_ENTRY cache_getImp 359 360 mov r9, r0 361 CacheLookup GETIMP // returns IMP on success 362 363LCacheMiss: 364 mov r0, #0 // return nil if cache miss 365 bx lr 366 367LGetImpExit: 368 END_ENTRY cache_getImp 369 370 371/******************************************************************** 372 * 373 * id objc_msgSend(id self, SEL _cmd,...); 374 * 375 ********************************************************************/ 376 377 ENTRY objc_msgSend 378 MESSENGER_START 379 380 cbz r0, LNilReceiver_f 381 382 ldr r9, [r0] // r9 = self->isa 383 CacheLookup NORMAL 384 // calls IMP or LCacheMiss 385 386LCacheMiss: 387 MESSENGER_END_SLOW 388 ldr r9, [r0, #ISA] // class = receiver->isa 389 b __objc_msgSend_uncached 390 391LNilReceiver: 392 mov r1, #0 393 MESSENGER_END_NIL 394 bx lr 395 396LMsgSendExit: 397 END_ENTRY objc_msgSend 398 399 400/******************************************************************** 401 * id objc_msgSend_noarg(id self, SEL op) 402 * 403 * On entry: r0 is the message receiver, 404 * r1 is the selector 405 ********************************************************************/ 406 407 ENTRY objc_msgSend_noarg 408 b _objc_msgSend 409 END_ENTRY objc_msgSend_noarg 410 411 412/******************************************************************** 413 * void objc_msgSend_stret(void *st_addr, id self, SEL op, ...); 414 * 415 * objc_msgSend_stret is the struct-return form of msgSend. 416 * The ABI calls for r0 to be used as the address of the structure 417 * being returned, with the parameters in the succeeding registers. 418 * 419 * On entry: r0 is the address where the structure is returned, 420 * r1 is the message receiver, 421 * r2 is the selector 422 ********************************************************************/ 423 424 ENTRY objc_msgSend_stret 425 MESSENGER_START 426 427 cbz r1, LNilReceiver_f 428 429 ldr r9, [r1] // r9 = self->isa 430 CacheLookup STRET 431 // calls IMP or LCacheMiss 432 433LCacheMiss: 434 MESSENGER_END_SLOW 435 ldr r9, [r1] // r9 = self->isa 436 b __objc_msgSend_stret_uncached 437 438LNilReceiver: 439 MESSENGER_END_NIL 440 bx lr 441 442LMsgSendStretExit: 443 END_ENTRY objc_msgSend_stret 444 445 446/******************************************************************** 447 * id objc_msgSendSuper(struct objc_super *super, SEL op, ...) 448 * 449 * struct objc_super { 450 * id receiver; 451 * Class cls; // the class to search 452 * } 453 ********************************************************************/ 454 455 ENTRY objc_msgSendSuper 456 MESSENGER_START 457 458 ldr r9, [r0, #CLASS] // r9 = struct super->class 459 CacheLookup SUPER 460 // calls IMP or LCacheMiss 461 462LCacheMiss: 463 MESSENGER_END_SLOW 464 ldr r9, [r0, #CLASS] // r9 = struct super->class 465 ldr r0, [r0, #RECEIVER] // load real receiver 466 b __objc_msgSend_uncached 467 468LMsgSendSuperExit: 469 END_ENTRY objc_msgSendSuper 470 471 472/******************************************************************** 473 * id objc_msgSendSuper2(struct objc_super *super, SEL op, ...) 474 * 475 * struct objc_super { 476 * id receiver; 477 * Class cls; // SUBCLASS of the class to search 478 * } 479 ********************************************************************/ 480 481 ENTRY objc_msgSendSuper2 482 MESSENGER_START 483 484 ldr r9, [r0, #CLASS] // class = struct super->class 485 ldr r9, [r9, #SUPERCLASS] // class = class->superclass 486 CacheLookup SUPER2 487 // calls IMP or LCacheMiss 488 489LCacheMiss: 490 MESSENGER_END_SLOW 491 ldr r9, [r0, #CLASS] // class = struct super->class 492 ldr r9, [r9, #SUPERCLASS] // class = class->superclass 493 ldr r0, [r0, #RECEIVER] // load real receiver 494 b __objc_msgSend_uncached 495 496LMsgSendSuper2Exit: 497 END_ENTRY objc_msgSendSuper2 498 499 500/******************************************************************** 501 * void objc_msgSendSuper_stret(void *st_addr, objc_super *self, SEL op, ...); 502 * 503 * objc_msgSendSuper_stret is the struct-return form of msgSendSuper. 504 * The ABI calls for r0 to be used as the address of the structure 505 * being returned, with the parameters in the succeeding registers. 506 * 507 * On entry: r0 is the address where the structure is returned, 508 * r1 is the address of the objc_super structure, 509 * r2 is the selector 510 ********************************************************************/ 511 512 ENTRY objc_msgSendSuper_stret 513 MESSENGER_START 514 515 ldr r9, [r1, #CLASS] // r9 = struct super->class 516 CacheLookup SUPER_STRET 517 // calls IMP or LCacheMiss 518 519LCacheMiss: 520 MESSENGER_END_SLOW 521 ldr r9, [r1, #CLASS] // r9 = struct super->class 522 ldr r1, [r1, #RECEIVER] // load real receiver 523 b __objc_msgSend_stret_uncached 524 525LMsgSendSuperStretExit: 526 END_ENTRY objc_msgSendSuper_stret 527 528 529/******************************************************************** 530 * id objc_msgSendSuper2_stret 531 ********************************************************************/ 532 533 ENTRY objc_msgSendSuper2_stret 534 MESSENGER_START 535 536 ldr r9, [r1, #CLASS] // class = struct super->class 537 ldr r9, [r9, #SUPERCLASS] // class = class->superclass 538 CacheLookup SUPER2_STRET 539 540LCacheMiss: 541 MESSENGER_END_SLOW 542 ldr r9, [r1, #CLASS] // class = struct super->class 543 ldr r9, [r9, #SUPERCLASS] // class = class->superclass 544 ldr r1, [r1, #RECEIVER] // load real receiver 545 b __objc_msgSend_stret_uncached 546 547LMsgSendSuper2StretExit: 548 END_ENTRY objc_msgSendSuper2_stret 549 550 551/******************************************************************** 552 * 553 * _objc_msgSend_uncached_impcache 554 * Used to erase method cache entries in-place by 555 * bouncing them to the uncached lookup. 556 * 557 * _objc_msgSend_uncached 558 * _objc_msgSend_stret_uncached 559 * The uncached lookup. 560 * 561 ********************************************************************/ 562 563 STATIC_ENTRY _objc_msgSend_uncached_impcache 564 // Method cache version 565 566 // THIS IS NOT A CALLABLE C FUNCTION 567 // Out-of-band Z is 0 (EQ) for normal, 1 (NE) for stret and/or super 568 // Out-of-band r9 is 1 for stret, cls for super, cls|1 for super_stret 569 // Note objc_msgForward_impcache uses the same parameters 570 571 MESSENGER_START 572 nop 573 MESSENGER_END_SLOW 574 575 ite eq 576 ldreq r9, [r0] // normal: r9 = class = self->isa 577 tstne r9, #1 // low bit clear? 578 beq __objc_msgSend_uncached // super: r9 is already the class 579 // stret or super_stret 580 eors r9, r9, #1 // clear low bit 581 it eq // r9 now zero? 582 ldreq r9, [r1] // stret: r9 = class = self->isa 583 // super_stret: r9 is already the class 584 b __objc_msgSend_stret_uncached 585 586 END_ENTRY _objc_msgSend_uncached_impcache 587 588 589 STATIC_ENTRY _objc_msgSend_uncached 590 591 // THIS IS NOT A CALLABLE C FUNCTION 592 // Out-of-band r9 is the class to search 593 594 stmfd sp!, {r0-r3,r7,lr} 595 add r7, sp, #16 596 597 // receiver already in r0 598 // selector already in r1 599 mov r2, r9 // class to search 600 601 MI_CALL_EXTERNAL(__class_lookupMethodAndLoadCache3) 602 mov r12, r0 // r12 = IMP 603 604 movs r9, #0 // r9=0, Z=1 for nonstret forwarding 605 ldmfd sp!, {r0-r3,r7,lr} 606 bx r12 607 608 END_ENTRY _objc_msgSend_uncached 609 610 611 STATIC_ENTRY _objc_msgSend_stret_uncached 612 613 // THIS IS NOT A CALLABLE C FUNCTION 614 // Out-of-band r9 is the class to search 615 616 stmfd sp!, {r0-r3,r7,lr} 617 add r7, sp, #16 618 619 mov r0, r1 // receiver 620 mov r1, r2 // selector 621 mov r2, r9 // class to search 622 623 MI_CALL_EXTERNAL(__class_lookupMethodAndLoadCache3) 624 mov r12, r0 // r12 = IMP 625 626 movs r9, #1 // r9=1, Z=0 for stret forwarding 627 ldmfd sp!, {r0-r3,r7,lr} 628 bx r12 629 630 END_ENTRY _objc_msgSend_stret_uncached 631 632 633/******************************************************************** 634* 635* id _objc_msgForward(id self, SEL _cmd,...); 636* 637* _objc_msgForward and _objc_msgForward_stret are the externally-callable 638* functions returned by things like method_getImplementation(). 639* _objc_msgForward_impcache is the function pointer actually stored in 640* method caches. 641* 642********************************************************************/ 643 644 MI_EXTERN(__objc_forward_handler) 645 MI_EXTERN(__objc_forward_stret_handler) 646 647 STATIC_ENTRY _objc_msgForward_impcache 648 // Method cache version 649 650 // THIS IS NOT A CALLABLE C FUNCTION 651 // Out-of-band Z is 0 (EQ) for normal, 1 (NE) for stret and/or super 652 // Out-of-band r9 is 1 for stret, cls for super, cls|1 for super_stret 653 // Note _objc_msgSend_uncached_impcache uses the same parameters 654 655 MESSENGER_START 656 nop 657 MESSENGER_END_SLOW 658 659 it ne 660 tstne r9, #1 661 beq __objc_msgForward 662 b __objc_msgForward_stret 663 664 END_ENTRY _objc_msgForward_impcache 665 666 667 ENTRY _objc_msgForward 668 // Non-stret version 669 670 MI_GET_EXTERN(r12, __objc_forward_handler) 671 ldr r12, [r12] 672 bx r12 673 674 END_ENTRY _objc_msgForward 675 676 677 ENTRY _objc_msgForward_stret 678 // Struct-return version 679 680 MI_GET_EXTERN(r12, __objc_forward_stret_handler) 681 ldr r12, [r12] 682 bx r12 683 684 END_ENTRY _objc_msgForward_stret 685 686 687 ENTRY objc_msgSend_debug 688 b _objc_msgSend 689 END_ENTRY objc_msgSend_debug 690 691 ENTRY objc_msgSendSuper2_debug 692 b _objc_msgSendSuper2 693 END_ENTRY objc_msgSendSuper2_debug 694 695 ENTRY objc_msgSend_stret_debug 696 b _objc_msgSend_stret 697 END_ENTRY objc_msgSend_stret_debug 698 699 ENTRY objc_msgSendSuper2_stret_debug 700 b _objc_msgSendSuper2_stret 701 END_ENTRY objc_msgSendSuper2_stret_debug 702 703 704 ENTRY method_invoke 705 // r1 is method triplet instead of SEL 706 ldr r12, [r1, #METHOD_IMP] 707 ldr r1, [r1, #METHOD_NAME] 708 bx r12 709 END_ENTRY method_invoke 710 711 712 ENTRY method_invoke_stret 713 // r2 is method triplet instead of SEL 714 ldr r12, [r2, #METHOD_IMP] 715 ldr r2, [r2, #METHOD_NAME] 716 bx r12 717 END_ENTRY method_invoke_stret 718 719 720 STATIC_ENTRY _objc_ignored_method 721 722 // self is already in a0 723 bx lr 724 725 END_ENTRY _objc_ignored_method 726 727 728.section __DATA,__objc_msg_break 729.long 0 730.long 0 731 732#endif 733