1/* 2 * Copyright (c) 1999-2007 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 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#include <TargetConditionals.h> 25#if defined(__i386__) && !TARGET_IPHONE_SIMULATOR 26 27/******************************************************************** 28 ******************************************************************** 29 ** 30 ** objc-msg-i386.s - i386 code to support objc messaging. 31 ** 32 ******************************************************************** 33 ********************************************************************/ 34 35// for kIgnore 36#include "objc-config.h" 37 38 39/******************************************************************** 40* Data used by the ObjC runtime. 41* 42********************************************************************/ 43 44.data 45// Substitute receiver for messages sent to nil (usually also nil) 46// id _objc_nilReceiver 47.align 4 48.private_extern __objc_nilReceiver 49__objc_nilReceiver: 50 .long 0 51 52// _objc_entryPoints and _objc_exitPoints are used by objc 53// to get the critical regions for which method caches 54// cannot be garbage collected. 55 56.private_extern _objc_entryPoints 57_objc_entryPoints: 58 .long __cache_getImp 59 .long __cache_getMethod 60 .long _objc_msgSend 61 .long _objc_msgSend_fpret 62 .long _objc_msgSend_stret 63 .long _objc_msgSendSuper 64 .long _objc_msgSendSuper_stret 65 .long 0 66 67.private_extern _objc_exitPoints 68_objc_exitPoints: 69 .long LGetImpExit 70 .long LGetMethodExit 71 .long LMsgSendExit 72 .long LMsgSendFpretExit 73 .long LMsgSendStretExit 74 .long LMsgSendSuperExit 75 .long LMsgSendSuperStretExit 76 .long 0 77 78 79/******************************************************************** 80* List every exit insn from every messenger for debugger use. 81* Format: 82* ( 83* 1 word instruction's address 84* 1 word type (ENTER or FAST_EXIT or SLOW_EXIT or NIL_EXIT) 85* ) 86* 1 word zero 87* 88* ENTER is the start of a dispatcher 89* FAST_EXIT is method dispatch 90* SLOW_EXIT is uncached method lookup 91* NIL_EXIT is returning zero from a message sent to nil 92* These must match objc-gdb.h. 93********************************************************************/ 94 95#define ENTER 1 96#define FAST_EXIT 2 97#define SLOW_EXIT 3 98#define NIL_EXIT 4 99 100.section __DATA,__objc_msg_break 101.globl _gdb_objc_messenger_breakpoints 102_gdb_objc_messenger_breakpoints: 103// contents populated by the macros below 104 105.macro MESSENGER_START 1064: 107 .section __DATA,__objc_msg_break 108 .long 4b 109 .long ENTER 110 .text 111.endmacro 112.macro MESSENGER_END_FAST 1134: 114 .section __DATA,__objc_msg_break 115 .long 4b 116 .long FAST_EXIT 117 .text 118.endmacro 119.macro MESSENGER_END_SLOW 1204: 121 .section __DATA,__objc_msg_break 122 .long 4b 123 .long SLOW_EXIT 124 .text 125.endmacro 126.macro MESSENGER_END_NIL 1274: 128 .section __DATA,__objc_msg_break 129 .long 4b 130 .long NIL_EXIT 131 .text 132.endmacro 133 134 135/******************************************************************** 136 * 137 * Common offsets. 138 * 139 ********************************************************************/ 140 141 self = 4 142 super = 4 143 selector = 8 144 marg_size = 12 145 marg_list = 16 146 first_arg = 12 147 148 struct_addr = 4 149 150 self_stret = 8 151 super_stret = 8 152 selector_stret = 12 153 marg_size_stret = 16 154 marg_list_stret = 20 155 156 157/******************************************************************** 158 * 159 * Structure definitions. 160 * 161 ********************************************************************/ 162 163// objc_super parameter to sendSuper 164 receiver = 0 165 class = 4 166 167// Selected field offsets in class structure 168 isa = 0 169 cache = 32 170 171// Method descriptor 172 method_name = 0 173 method_imp = 8 174 175// Cache header 176 mask = 0 177 occupied = 4 178 buckets = 8 // variable length array 179 180#if defined(OBJC_INSTRUMENTED) 181// Cache instrumentation data, follows buckets 182 hitCount = 0 183 hitProbes = hitCount + 4 184 maxHitProbes = hitProbes + 4 185 missCount = maxHitProbes + 4 186 missProbes = missCount + 4 187 maxMissProbes = missProbes + 4 188 flushCount = maxMissProbes + 4 189 flushedEntries = flushCount + 4 190 191// Buckets in CacheHitHistogram and CacheMissHistogram 192 CACHE_HISTOGRAM_SIZE = 512 193#endif 194 195 196////////////////////////////////////////////////////////////////////// 197// 198// LOAD_STATIC_WORD targetReg, symbolName, LOCAL_SYMBOL | EXTERNAL_SYMBOL 199// 200// Load the value of the named static data word. 201// 202// Takes: targetReg - the register, other than r0, to load 203// symbolName - the name of the symbol 204// LOCAL_SYMBOL - symbol name used as-is 205// EXTERNAL_SYMBOL - symbol name gets nonlazy treatment 206// 207// Eats: edx and targetReg 208////////////////////////////////////////////////////////////////////// 209 210// Values to specify whether the symbol is plain or nonlazy 211LOCAL_SYMBOL = 0 212EXTERNAL_SYMBOL = 1 213 214.macro LOAD_STATIC_WORD 215 216#if defined(__DYNAMIC__) 217 call 1f 2181: popl %edx 219.if $2 == EXTERNAL_SYMBOL 220 movl L$1-1b(%edx),$0 221 movl 0($0),$0 222.elseif $2 == LOCAL_SYMBOL 223 movl $1-1b(%edx),$0 224.else 225 !!! Unknown symbol type !!! 226.endif 227#else 228 movl $1,$0 229#endif 230 231.endmacro 232 233////////////////////////////////////////////////////////////////////// 234// 235// LEA_STATIC_DATA targetReg, symbolName, LOCAL_SYMBOL | EXTERNAL_SYMBOL 236// 237// Load the address of the named static data. 238// 239// Takes: targetReg - the register, other than edx, to load 240// symbolName - the name of the symbol 241// LOCAL_SYMBOL - symbol is local to this module 242// EXTERNAL_SYMBOL - symbol is imported from another module 243// 244// Eats: edx and targetReg 245////////////////////////////////////////////////////////////////////// 246 247.macro LEA_STATIC_DATA 248#if defined(__DYNAMIC__) 249 call 1f 2501: popl %edx 251.if $2 == EXTERNAL_SYMBOL 252 movl L$1-1b(%edx),$0 253.elseif $2 == LOCAL_SYMBOL 254 leal $1-1b(%edx),$0 255.else 256 !!! Unknown symbol type !!! 257.endif 258#else 259 leal $1,$0 260#endif 261 262.endmacro 263 264////////////////////////////////////////////////////////////////////// 265// 266// ENTRY functionName 267// 268// Assembly directives to begin an exported function. 269// 270// Takes: functionName - name of the exported function 271////////////////////////////////////////////////////////////////////// 272 273.macro ENTRY 274 .text 275 .globl $0 276 .align 4, 0x90 277$0: 278.endmacro 279 280.macro STATIC_ENTRY 281 .text 282 .private_extern $0 283 .align 4, 0x90 284$0: 285.endmacro 286 287////////////////////////////////////////////////////////////////////// 288// 289// END_ENTRY functionName 290// 291// Assembly directives to end an exported function. Just a placeholder, 292// a close-parenthesis for ENTRY, until it is needed for something. 293// 294// Takes: functionName - name of the exported function 295////////////////////////////////////////////////////////////////////// 296 297.macro END_ENTRY 298.endmacro 299 300////////////////////////////////////////////////////////////////////// 301// 302// CALL_MCOUNTER 303// 304// Calls mcount() profiling routine. Must be called immediately on 305// function entry, before any prologue executes. 306// 307////////////////////////////////////////////////////////////////////// 308 309.macro CALL_MCOUNTER 310#ifdef PROFILE 311 // Current stack contents: ret 312 pushl %ebp 313 movl %esp,%ebp 314 subl $$8,%esp 315 // Current stack contents: ret, ebp, pad, pad 316 call mcount 317 movl %ebp,%esp 318 popl %ebp 319#endif 320.endmacro 321 322 323///////////////////////////////////////////////////////////////////// 324// 325// 326// CacheLookup WORD_RETURN | STRUCT_RETURN, MSG_SEND | MSG_SENDSUPER | CACHE_GET, cacheMissLabel 327// 328// Locate the implementation for a selector in a class method cache. 329// 330// Takes: WORD_RETURN (first parameter is at sp+4) 331// STRUCT_RETURN (struct address is at sp+4, first parameter at sp+8) 332// MSG_SEND (first parameter is receiver) 333// MSG_SENDSUPER (first parameter is address of objc_super structure) 334// CACHE_GET (first parameter is class; return method triplet) 335// selector in %ecx 336// class to search in %edx 337// 338// cacheMissLabel = label to branch to iff method is not cached 339// 340// On exit: (found) MSG_SEND and MSG_SENDSUPER: return imp in eax 341// (found) CACHE_GET: return method triplet in eax 342// (not found) jumps to cacheMissLabel 343// 344///////////////////////////////////////////////////////////////////// 345 346 347// Values to specify to method lookup macros whether the return type of 348// the method is word or structure. 349WORD_RETURN = 0 350STRUCT_RETURN = 1 351 352// Values to specify to method lookup macros whether the first argument 353// is an object/class reference or a 'objc_super' structure. 354MSG_SEND = 0 // first argument is receiver, search the isa 355MSG_SENDSUPER = 1 // first argument is objc_super, search the class 356CACHE_GET = 2 // first argument is class, search that class 357 358.macro CacheLookup 359 360// load variables and save caller registers. 361 362 pushl %edi // save scratch register 363 movl cache(%edx), %edi // cache = class->cache 364 pushl %esi // save scratch register 365 366#if defined(OBJC_INSTRUMENTED) 367 pushl %ebx // save non-volatile register 368 pushl %eax // save cache pointer 369 xorl %ebx, %ebx // probeCount = 0 370#endif 371 movl mask(%edi), %esi // mask = cache->mask 372 movl %ecx, %edx // index = selector 373 shrl $$2, %edx // index = selector >> 2 374 375// search the receiver's cache 376// ecx = selector 377// edi = cache 378// esi = mask 379// edx = index 380// eax = method (soon) 381LMsgSendProbeCache_$0_$1_$2: 382#if defined(OBJC_INSTRUMENTED) 383 addl $$1, %ebx // probeCount += 1 384#endif 385 andl %esi, %edx // index &= mask 386 movl buckets(%edi, %edx, 4), %eax // meth = cache->buckets[index] 387 388 testl %eax, %eax // check for end of bucket 389 je LMsgSendCacheMiss_$0_$1_$2 // go to cache miss code 390 cmpl method_name(%eax), %ecx // check for method name match 391 je LMsgSendCacheHit_$0_$1_$2 // go handle cache hit 392 addl $$1, %edx // bump index ... 393 jmp LMsgSendProbeCache_$0_$1_$2 // ... and loop 394 395// not found in cache: restore state and go to callers handler 396LMsgSendCacheMiss_$0_$1_$2: 397#if defined(OBJC_INSTRUMENTED) 398 popl %edx // retrieve cache pointer 399 movl mask(%edx), %esi // mask = cache->mask 400 testl %esi, %esi // a mask of zero is only for the... 401 je LMsgSendMissInstrumentDone_$0_$1_$2 // ... emptyCache, do not record anything 402 403 // locate and update the CacheInstrumentation structure 404 addl $$1, %esi // entryCount = mask + 1 405 shll $$2, %esi // tableSize = entryCount * sizeof(entry) 406 addl $buckets, %esi // offset = buckets + tableSize 407 addl %edx, %esi // cacheData = &cache->buckets[mask+1] 408 409 movl missCount(%esi), %edi // 410 addl $$1, %edi // 411 movl %edi, missCount(%esi) // cacheData->missCount += 1 412 movl missProbes(%esi), %edi // 413 addl %ebx, %edi // 414 movl %edi, missProbes(%esi) // cacheData->missProbes += probeCount 415 movl maxMissProbes(%esi), %edi// if (cacheData->maxMissProbes < probeCount) 416 cmpl %ebx, %edi // 417 jge LMsgSendMaxMissProbeOK_$0_$1_$2 // 418 movl %ebx, maxMissProbes(%esi)// cacheData->maxMissProbes = probeCount 419LMsgSendMaxMissProbeOK_$0_$1_$2: 420 421 // update cache miss probe histogram 422 cmpl $CACHE_HISTOGRAM_SIZE, %ebx // pin probeCount to max index 423 jl LMsgSendMissHistoIndexSet_$0_$1_$2 424 movl $(CACHE_HISTOGRAM_SIZE-1), %ebx 425LMsgSendMissHistoIndexSet_$0_$1_$2: 426 LEA_STATIC_DATA %esi, _CacheMissHistogram, EXTERNAL_SYMBOL 427 shll $$2, %ebx // convert probeCount to histogram index 428 addl %ebx, %esi // calculate &CacheMissHistogram[probeCount<<2] 429 movl 0(%esi), %edi // get current tally 430 addl $$1, %edi // 431 movl %edi, 0(%esi) // tally += 1 432LMsgSendMissInstrumentDone_$0_$1_$2: 433 popl %ebx // restore non-volatile register 434#endif 435 436.if $0 == WORD_RETURN // Regular word return 437.if $1 == MSG_SEND // MSG_SEND 438 popl %esi // restore callers register 439 popl %edi // restore callers register 440 movl self(%esp), %edx // get messaged object 441 movl isa(%edx), %eax // get objects class 442.elseif $1 == MSG_SENDSUPER // MSG_SENDSUPER 443 // replace "super" arg with "receiver" 444 movl super+8(%esp), %edi // get super structure 445 movl receiver(%edi), %edx // get messaged object 446 movl %edx, super+8(%esp) // make it the first argument 447 movl class(%edi), %eax // get messaged class 448 popl %esi // restore callers register 449 popl %edi // restore callers register 450.else // CACHE_GET 451 popl %esi // restore callers register 452 popl %edi // restore callers register 453.endif 454.else // Struct return 455.if $1 == MSG_SEND // MSG_SEND (stret) 456 popl %esi // restore callers register 457 popl %edi // restore callers register 458 movl self_stret(%esp), %edx // get messaged object 459 movl isa(%edx), %eax // get objects class 460.elseif $1 == MSG_SENDSUPER // MSG_SENDSUPER (stret) 461 // replace "super" arg with "receiver" 462 movl super_stret+8(%esp), %edi// get super structure 463 movl receiver(%edi), %edx // get messaged object 464 movl %edx, super_stret+8(%esp)// make it the first argument 465 movl class(%edi), %eax // get messaged class 466 popl %esi // restore callers register 467 popl %edi // restore callers register 468.else // CACHE_GET 469 !! This should not happen. 470.endif 471.endif 472 473 // edx = receiver 474 // ecx = selector 475 // eax = class 476 jmp $2 // go to callers handler 477 478// eax points to matching cache entry 479 .align 4, 0x90 480LMsgSendCacheHit_$0_$1_$2: 481#if defined(OBJC_INSTRUMENTED) 482 popl %edx // retrieve cache pointer 483 movl mask(%edx), %esi // mask = cache->mask 484 testl %esi, %esi // a mask of zero is only for the... 485 je LMsgSendHitInstrumentDone_$0_$1_$2 // ... emptyCache, do not record anything 486 487 // locate and update the CacheInstrumentation structure 488 addl $$1, %esi // entryCount = mask + 1 489 shll $$2, %esi // tableSize = entryCount * sizeof(entry) 490 addl $buckets, %esi // offset = buckets + tableSize 491 addl %edx, %esi // cacheData = &cache->buckets[mask+1] 492 493 movl hitCount(%esi), %edi 494 addl $$1, %edi 495 movl %edi, hitCount(%esi) // cacheData->hitCount += 1 496 movl hitProbes(%esi), %edi 497 addl %ebx, %edi 498 movl %edi, hitProbes(%esi) // cacheData->hitProbes += probeCount 499 movl maxHitProbes(%esi), %edi// if (cacheData->maxHitProbes < probeCount) 500 cmpl %ebx, %edi 501 jge LMsgSendMaxHitProbeOK_$0_$1_$2 502 movl %ebx, maxHitProbes(%esi)// cacheData->maxHitProbes = probeCount 503LMsgSendMaxHitProbeOK_$0_$1_$2: 504 505 // update cache hit probe histogram 506 cmpl $CACHE_HISTOGRAM_SIZE, %ebx // pin probeCount to max index 507 jl LMsgSendHitHistoIndexSet_$0_$1_$2 508 movl $(CACHE_HISTOGRAM_SIZE-1), %ebx 509LMsgSendHitHistoIndexSet_$0_$1_$2: 510 LEA_STATIC_DATA %esi, _CacheHitHistogram, EXTERNAL_SYMBOL 511 shll $$2, %ebx // convert probeCount to histogram index 512 addl %ebx, %esi // calculate &CacheHitHistogram[probeCount<<2] 513 movl 0(%esi), %edi // get current tally 514 addl $$1, %edi // 515 movl %edi, 0(%esi) // tally += 1 516LMsgSendHitInstrumentDone_$0_$1_$2: 517 popl %ebx // restore non-volatile register 518#endif 519 520// load implementation address, restore state, and we're done 521.if $1 == CACHE_GET 522 // method triplet is already in eax 523.else 524 movl method_imp(%eax), %eax // imp = method->method_imp 525.endif 526 527.if $0 == WORD_RETURN // Regular word return 528.if $1 == MSG_SENDSUPER // MSG_SENDSUPER 529 // replace "super" arg with "self" 530 movl super+8(%esp), %edi 531 movl receiver(%edi), %esi 532 movl %esi, super+8(%esp) 533.endif 534.else // Struct return 535.if $1 == MSG_SENDSUPER // MSG_SENDSUPER (stret) 536 // replace "super" arg with "self" 537 movl super_stret+8(%esp), %edi 538 movl receiver(%edi), %esi 539 movl %esi, super_stret+8(%esp) 540.endif 541.endif 542 543 // restore caller registers 544 popl %esi 545 popl %edi 546.endmacro 547 548 549///////////////////////////////////////////////////////////////////// 550// 551// MethodTableLookup WORD_RETURN | STRUCT_RETURN, MSG_SEND | MSG_SENDSUPER 552// 553// Takes: WORD_RETURN (first parameter is at sp+4) 554// STRUCT_RETURN (struct address is at sp+4, first parameter at sp+8) 555// MSG_SEND (first parameter is receiver) 556// MSG_SENDSUPER (first parameter is address of objc_super structure) 557// 558// edx = receiver 559// ecx = selector 560// eax = class 561// (all set by CacheLookup's miss case) 562// 563// Stack must be at 0xXXXXXXXc on entrance. 564// 565// On exit: esp unchanged 566// imp in eax 567// 568///////////////////////////////////////////////////////////////////// 569 570.macro MethodTableLookup 571 MESSENGER_END_SLOW 572 // stack is already aligned 573 pushl %eax // class 574 pushl %ecx // selector 575 pushl %edx // receiver 576 call __class_lookupMethodAndLoadCache3 577 addl $$12, %esp // pop parameters 578.endmacro 579 580 581/******************************************************************** 582 * Method _cache_getMethod(Class cls, SEL sel, IMP msgForward_internal_imp) 583 * 584 * If found, returns method triplet pointer. 585 * If not found, returns NULL. 586 * 587 * NOTE: _cache_getMethod never returns any cache entry whose implementation 588 * is _objc_msgForward_impcache. It returns 1 instead. This prevents thread- 589 * safety and memory management bugs in _class_lookupMethodAndLoadCache. 590 * See _class_lookupMethodAndLoadCache for details. 591 * 592 * _objc_msgForward_impcache is passed as a parameter because it's more 593 * efficient to do the (PIC) lookup once in the caller than repeatedly here. 594 ********************************************************************/ 595 596 STATIC_ENTRY __cache_getMethod 597 598// load the class and selector 599 movl selector(%esp), %ecx 600 movl self(%esp), %edx 601 602// do lookup 603 CacheLookup WORD_RETURN, CACHE_GET, LGetMethodMiss 604 605// cache hit, method triplet in %eax 606 movl first_arg(%esp), %ecx // check for _objc_msgForward_impcache 607 cmpl method_imp(%eax), %ecx // if (imp==_objc_msgForward_impcache) 608 je 1f // return (Method)1 609 ret // else return method triplet address 6101: movl $1, %eax 611 ret 612 613LGetMethodMiss: 614// cache miss, return nil 615 xorl %eax, %eax // zero %eax 616 ret 617 618LGetMethodExit: 619 END_ENTRY __cache_getMethod 620 621 622/******************************************************************** 623 * IMP _cache_getImp(Class cls, SEL sel) 624 * 625 * If found, returns method implementation. 626 * If not found, returns NULL. 627 ********************************************************************/ 628 629 STATIC_ENTRY __cache_getImp 630 631// load the class and selector 632 movl selector(%esp), %ecx 633 movl self(%esp), %edx 634 635// do lookup 636 CacheLookup WORD_RETURN, CACHE_GET, LGetImpMiss 637 638// cache hit, method triplet in %eax 639 movl method_imp(%eax), %eax // return method imp 640 ret 641 642LGetImpMiss: 643// cache miss, return nil 644 xorl %eax, %eax // zero %eax 645 ret 646 647LGetImpExit: 648 END_ENTRY __cache_getImp 649 650 651/******************************************************************** 652 * 653 * id objc_msgSend(id self, SEL _cmd,...); 654 * 655 ********************************************************************/ 656 657 ENTRY _objc_msgSend 658 MESSENGER_START 659 CALL_MCOUNTER 660 661// load receiver and selector 662 movl selector(%esp), %ecx 663 movl self(%esp), %eax 664 665// check whether selector is ignored 666 cmpl $ kIgnore, %ecx 667 je LMsgSendDone // return self from %eax 668 669// check whether receiver is nil 670 testl %eax, %eax 671 je LMsgSendNilSelf 672 673// receiver (in %eax) is non-nil: search the cache 674LMsgSendReceiverOk: 675 movl isa(%eax), %edx // class = self->isa 676 CacheLookup WORD_RETURN, MSG_SEND, LMsgSendCacheMiss 677 xor %edx, %edx // set nonstret for msgForward_internal 678 MESSENGER_END_FAST 679 jmp *%eax 680 681// cache miss: go search the method lists 682LMsgSendCacheMiss: 683 MethodTableLookup WORD_RETURN, MSG_SEND 684 xor %edx, %edx // set nonstret for msgForward_internal 685 jmp *%eax // goto *imp 686 687// message sent to nil: redirect to nil receiver, if any 688LMsgSendNilSelf: 689 call 1f // load new receiver 6901: popl %edx 691 movl __objc_nilReceiver-1b(%edx),%eax 692 testl %eax, %eax // return nil if no new receiver 693 je LMsgSendReturnZero 694 movl %eax, self(%esp) // send to new receiver 695 jmp LMsgSendReceiverOk // receiver must be in %eax 696LMsgSendReturnZero: 697 // %eax is already zero 698 movl $0,%edx 699LMsgSendDone: 700 MESSENGER_END_NIL 701 ret 702 703// guaranteed non-nil entry point (disabled for now) 704// .globl _objc_msgSendNonNil 705// _objc_msgSendNonNil: 706// movl self(%esp), %eax 707// jmp LMsgSendReceiverOk 708 709LMsgSendExit: 710 END_ENTRY _objc_msgSend 711 712/******************************************************************** 713 * 714 * id objc_msgSendSuper(struct objc_super *super, SEL _cmd,...); 715 * 716 * struct objc_super { 717 * id receiver; 718 * Class class; 719 * }; 720 ********************************************************************/ 721 722 ENTRY _objc_msgSendSuper 723 MESSENGER_START 724 CALL_MCOUNTER 725 726// load selector and class to search 727 movl super(%esp), %eax // struct objc_super 728 movl selector(%esp), %ecx 729 movl class(%eax), %edx // struct objc_super->class 730 731// check whether selector is ignored 732 cmpl $ kIgnore, %ecx 733 je LMsgSendSuperIgnored // return self from %eax 734 735// search the cache (class in %edx) 736 CacheLookup WORD_RETURN, MSG_SENDSUPER, LMsgSendSuperCacheMiss 737 xor %edx, %edx // set nonstret for msgForward_internal 738 MESSENGER_END_FAST 739 jmp *%eax // goto *imp 740 741// cache miss: go search the method lists 742LMsgSendSuperCacheMiss: 743 MethodTableLookup WORD_RETURN, MSG_SENDSUPER 744 xor %edx, %edx // set nonstret for msgForward_internal 745 jmp *%eax // goto *imp 746 747// ignored selector: return self 748LMsgSendSuperIgnored: 749 movl super(%esp), %eax 750 movl receiver(%eax), %eax 751 MESSENGER_END_NIL 752 ret 753 754LMsgSendSuperExit: 755 END_ENTRY _objc_msgSendSuper 756 757/******************************************************************** 758 * id objc_msgSendv(id self, SEL _cmd, unsigned size, marg_list frame); 759 * 760 * On entry: 761 * (sp+4) is the message receiver, 762 * (sp+8) is the selector, 763 * (sp+12) is the size of the marg_list, in bytes, 764 * (sp+16) is the address of the marg_list 765 * 766 ********************************************************************/ 767 768 ENTRY _objc_msgSendv 769 770#if defined(KERNEL) 771 trap // _objc_msgSendv is not for the kernel 772#else 773 pushl %ebp 774 movl %esp, %ebp 775 // stack is currently aligned assuming no extra arguments 776 movl (marg_list+4)(%ebp), %edx 777 addl $8, %edx // skip self & selector 778 movl (marg_size+4)(%ebp), %ecx 779 subl $8, %ecx // skip self & selector 780 shrl $2, %ecx 781 je LMsgSendvArgsOK 782 783 // %esp = %esp - (16 - ((numVariableArguments & 3) << 2)) 784 movl %ecx, %eax // 16-byte align stack 785 andl $3, %eax 786 shll $2, %eax 787 subl $16, %esp 788 addl %eax, %esp 789 790LMsgSendvArgLoop: 791 decl %ecx 792 movl 0(%edx, %ecx, 4), %eax 793 pushl %eax 794 jg LMsgSendvArgLoop 795 796LMsgSendvArgsOK: 797 movl (selector+4)(%ebp), %ecx 798 pushl %ecx 799 movl (self+4)(%ebp),%ecx 800 pushl %ecx 801 call _objc_msgSend 802 movl %ebp,%esp 803 popl %ebp 804 805 ret 806#endif 807 END_ENTRY _objc_msgSendv 808 809/******************************************************************** 810 * 811 * double objc_msgSend_fpret(id self, SEL _cmd,...); 812 * 813 ********************************************************************/ 814 815 ENTRY _objc_msgSend_fpret 816 MESSENGER_START 817 CALL_MCOUNTER 818 819// load receiver and selector 820 movl selector(%esp), %ecx 821 movl self(%esp), %eax 822 823// check whether selector is ignored 824 cmpl $ kIgnore, %ecx 825 je LMsgSendFpretDone // return self from %eax 826 827// check whether receiver is nil 828 testl %eax, %eax 829 je LMsgSendFpretNilSelf 830 831// receiver (in %eax) is non-nil: search the cache 832LMsgSendFpretReceiverOk: 833 movl isa(%eax), %edx // class = self->isa 834 CacheLookup WORD_RETURN, MSG_SEND, LMsgSendFpretCacheMiss 835 xor %edx, %edx // set nonstret for msgForward_internal 836 MESSENGER_END_FAST 837 jmp *%eax // goto *imp 838 839// cache miss: go search the method lists 840LMsgSendFpretCacheMiss: 841 MethodTableLookup WORD_RETURN, MSG_SEND 842 xor %edx, %edx // set nonstret for msgForward_internal 843 jmp *%eax // goto *imp 844 845// message sent to nil: redirect to nil receiver, if any 846LMsgSendFpretNilSelf: 847 call 1f // load new receiver 8481: popl %edx 849 movl __objc_nilReceiver-1b(%edx),%eax 850 testl %eax, %eax // return zero if no new receiver 851 je LMsgSendFpretReturnZero 852 movl %eax, self(%esp) // send to new receiver 853 jmp LMsgSendFpretReceiverOk // receiver must be in %eax 854LMsgSendFpretReturnZero: 855 fldz 856LMsgSendFpretDone: 857 MESSENGER_END_NIL 858 ret 859 860LMsgSendFpretExit: 861 END_ENTRY _objc_msgSend_fpret 862 863/******************************************************************** 864 * double objc_msgSendv_fpret(id self, SEL _cmd, unsigned size, marg_list frame); 865 * 866 * On entry: 867 * (sp+4) is the message receiver, 868 * (sp+8) is the selector, 869 * (sp+12) is the size of the marg_list, in bytes, 870 * (sp+16) is the address of the marg_list 871 * 872 ********************************************************************/ 873 874 ENTRY _objc_msgSendv_fpret 875 876#if defined(KERNEL) 877 trap // _objc_msgSendv is not for the kernel 878#else 879 pushl %ebp 880 movl %esp, %ebp 881 // stack is currently aligned assuming no extra arguments 882 movl (marg_list+4)(%ebp), %edx 883 addl $8, %edx // skip self & selector 884 movl (marg_size+4)(%ebp), %ecx 885 subl $8, %ecx // skip self & selector 886 shrl $2, %ecx 887 je LMsgSendvFpretArgsOK 888 889 // %esp = %esp - (16 - ((numVariableArguments & 3) << 2)) 890 movl %ecx, %eax // 16-byte align stack 891 andl $3, %eax 892 shll $2, %eax 893 subl $16, %esp 894 addl %eax, %esp 895 896LMsgSendvFpretArgLoop: 897 decl %ecx 898 movl 0(%edx, %ecx, 4), %eax 899 pushl %eax 900 jg LMsgSendvFpretArgLoop 901 902LMsgSendvFpretArgsOK: 903 movl (selector+4)(%ebp), %ecx 904 pushl %ecx 905 movl (self+4)(%ebp),%ecx 906 pushl %ecx 907 call _objc_msgSend_fpret 908 movl %ebp,%esp 909 popl %ebp 910 911 ret 912#endif 913 END_ENTRY _objc_msgSendv_fpret 914 915/******************************************************************** 916 * 917 * void objc_msgSend_stret(void *st_addr , id self, SEL _cmd, ...); 918 * 919 * 920 * objc_msgSend_stret is the struct-return form of msgSend. 921 * The ABI calls for (sp+4) to be used as the address of the structure 922 * being returned, with the parameters in the succeeding locations. 923 * 924 * On entry: (sp+4)is the address where the structure is returned, 925 * (sp+8) is the message receiver, 926 * (sp+12) is the selector 927 ********************************************************************/ 928 929 ENTRY _objc_msgSend_stret 930 MESSENGER_START 931 CALL_MCOUNTER 932 933// load receiver and selector 934 movl self_stret(%esp), %eax 935 movl (selector_stret)(%esp), %ecx 936 937// check whether receiver is nil 938 testl %eax, %eax 939 je LMsgSendStretNilSelf 940 941// receiver (in %eax) is non-nil: search the cache 942LMsgSendStretReceiverOk: 943 movl isa(%eax), %edx // class = self->isa 944 CacheLookup STRUCT_RETURN, MSG_SEND, LMsgSendStretCacheMiss 945 movl $1, %edx // set stret for objc_msgForward 946 MESSENGER_END_FAST 947 jmp *%eax // goto *imp 948 949// cache miss: go search the method lists 950LMsgSendStretCacheMiss: 951 MethodTableLookup STRUCT_RETURN, MSG_SEND 952 movl $1, %edx // set stret for objc_msgForward 953 jmp *%eax // goto *imp 954 955// message sent to nil: redirect to nil receiver, if any 956LMsgSendStretNilSelf: 957 call 1f // load new receiver 9581: popl %edx 959 movl __objc_nilReceiver-1b(%edx),%eax 960 testl %eax, %eax // return nil if no new receiver 961 je LMsgSendStretDone 962 movl %eax, self_stret(%esp) // send to new receiver 963 jmp LMsgSendStretReceiverOk // receiver must be in %eax 964LMsgSendStretDone: 965 MESSENGER_END_NIL 966 ret $4 // pop struct return address (#2995932) 967 968// guaranteed non-nil entry point (disabled for now) 969// .globl _objc_msgSendNonNil_stret 970// _objc_msgSendNonNil_stret: 971// CALL_MCOUNTER 972// movl self_stret(%esp), %eax 973// jmp LMsgSendStretReceiverOk 974 975LMsgSendStretExit: 976 END_ENTRY _objc_msgSend_stret 977 978/******************************************************************** 979 * 980 * void objc_msgSendSuper_stret(void *st_addr, struct objc_super *super, SEL _cmd, ...); 981 * 982 * struct objc_super { 983 * id receiver; 984 * Class class; 985 * }; 986 * 987 * objc_msgSendSuper_stret is the struct-return form of msgSendSuper. 988 * The ABI calls for (sp+4) to be used as the address of the structure 989 * being returned, with the parameters in the succeeding registers. 990 * 991 * On entry: (sp+4)is the address where the structure is returned, 992 * (sp+8) is the address of the objc_super structure, 993 * (sp+12) is the selector 994 * 995 ********************************************************************/ 996 997 ENTRY _objc_msgSendSuper_stret 998 MESSENGER_START 999 CALL_MCOUNTER 1000 1001// load selector and class to search 1002 movl super_stret(%esp), %eax // struct objc_super 1003 movl (selector_stret)(%esp), %ecx // get selector 1004 movl class(%eax), %edx // struct objc_super->class 1005 1006// search the cache (class in %edx) 1007 CacheLookup STRUCT_RETURN, MSG_SENDSUPER, LMsgSendSuperStretCacheMiss 1008 movl $1, %edx // set stret for objc_msgForward 1009 MESSENGER_END_FAST 1010 jmp *%eax // goto *imp 1011 1012// cache miss: go search the method lists 1013LMsgSendSuperStretCacheMiss: 1014 MethodTableLookup STRUCT_RETURN, MSG_SENDSUPER 1015 movl $1, %edx // set stret for objc_msgForward 1016 jmp *%eax // goto *imp 1017 1018LMsgSendSuperStretExit: 1019 END_ENTRY _objc_msgSendSuper_stret 1020 1021 1022/******************************************************************** 1023 * void objc_msgSendv_stret(void *st_addr, id self, SEL _cmd, unsigned size, marg_list frame); 1024 * 1025 * objc_msgSendv_stret is the struct-return form of msgSendv. 1026 * This function does not use the struct-return ABI; instead, the 1027 * structure return address is passed as a normal parameter. 1028 * 1029 * On entry: (sp+4) is the address in which the returned struct is put, 1030 * (sp+8) is the message receiver, 1031 * (sp+12) is the selector, 1032 * (sp+16) is the size of the marg_list, in bytes, 1033 * (sp+20) is the address of the marg_list 1034 * 1035 ********************************************************************/ 1036 1037 ENTRY _objc_msgSendv_stret 1038 1039#if defined(KERNEL) 1040 trap // _objc_msgSendv_stret is not for the kernel 1041#else 1042 pushl %ebp 1043 movl %esp, %ebp 1044 subl $12, %esp // align stack assuming no extra arguments 1045 movl (marg_list_stret+4)(%ebp), %edx 1046 addl $8, %edx // skip self & selector 1047 movl (marg_size_stret+4)(%ebp), %ecx 1048 subl $5, %ecx // skip self & selector 1049 shrl $2, %ecx 1050 jle LMsgSendvStretArgsOK 1051 1052 // %esp = %esp - (16 - ((numVariableArguments & 3) << 2)) 1053 movl %ecx, %eax // 16-byte align stack 1054 andl $3, %eax 1055 shll $2, %eax 1056 subl $16, %esp 1057 addl %eax, %esp 1058 1059LMsgSendvStretArgLoop: 1060 decl %ecx 1061 movl 0(%edx, %ecx, 4), %eax 1062 pushl %eax 1063 jg LMsgSendvStretArgLoop 1064 1065LMsgSendvStretArgsOK: 1066 movl (selector_stret+4)(%ebp), %ecx 1067 pushl %ecx 1068 movl (self_stret+4)(%ebp),%ecx 1069 pushl %ecx 1070 movl (struct_addr+4)(%ebp),%ecx 1071 pushl %ecx 1072 call _objc_msgSend_stret 1073 movl %ebp,%esp 1074 popl %ebp 1075 1076 ret 1077#endif 1078 END_ENTRY _objc_msgSendv_stret 1079 1080 1081/******************************************************************** 1082 * 1083 * id _objc_msgForward(id self, SEL _cmd,...); 1084 * 1085 ********************************************************************/ 1086 1087// _FwdSel is @selector(forward::), set up in map_images(). 1088// ALWAYS dereference _FwdSel to get to "forward::" !! 1089 .data 1090 .align 2 1091 .private_extern _FwdSel 1092_FwdSel: .long 0 1093 1094 .cstring 1095 .align 2 1096LUnkSelStr: .ascii "Does not recognize selector %s (while forwarding %s)\0" 1097 1098 .data 1099 .align 2 1100 .private_extern __objc_forward_handler 1101__objc_forward_handler: .long 0 1102 1103 .data 1104 .align 2 1105 .private_extern __objc_forward_stret_handler 1106__objc_forward_stret_handler: .long 0 1107 1108 STATIC_ENTRY __objc_msgForward_impcache 1109 // Method cache version 1110 1111 // THIS IS NOT A CALLABLE C FUNCTION 1112 // Out-of-band register %edx is nonzero for stret, zero otherwise 1113 1114 MESSENGER_START 1115 nop 1116 MESSENGER_END_SLOW 1117 1118 // Check return type (stret or not) 1119 testl %edx, %edx 1120 jnz __objc_msgForward_stret 1121 jmp __objc_msgForward 1122 1123 END_ENTRY _objc_msgForward_impcache 1124 1125 1126 ENTRY __objc_msgForward 1127 // Non-struct return version 1128 1129 // Get PIC base into %edx 1130 call L__objc_msgForward$pic_base 1131L__objc_msgForward$pic_base: 1132 popl %edx 1133 1134 // Call user handler, if any 1135 movl __objc_forward_handler-L__objc_msgForward$pic_base(%edx),%ecx 1136 testl %ecx, %ecx // if not NULL 1137 je 1f // skip to default handler 1138 jmp *%ecx // call __objc_forward_handler 11391: 1140 // No user handler 1141 // Push stack frame 1142 pushl %ebp 1143 movl %esp, %ebp 1144 1145 // Die if forwarding "forward::" 1146 movl (selector+4)(%ebp), %eax 1147 movl _FwdSel-L__objc_msgForward$pic_base(%edx),%ecx 1148 cmpl %ecx, %eax 1149 je LMsgForwardError 1150 1151 // Call [receiver forward:sel :margs] 1152 subl $8, %esp // 16-byte align the stack 1153 leal (self+4)(%ebp), %ecx 1154 pushl %ecx // &margs 1155 pushl %eax // sel 1156 movl _FwdSel-L__objc_msgForward$pic_base(%edx),%ecx 1157 pushl %ecx // forward:: 1158 pushl (self+4)(%ebp) // receiver 1159 1160 call _objc_msgSend 1161 1162 movl %ebp, %esp 1163 popl %ebp 1164 ret 1165 1166LMsgForwardError: 1167 // Call __objc_error(receiver, "unknown selector %s %s", "forward::", forwardedSel) 1168 subl $8, %esp // 16-byte align the stack 1169 pushl (selector+4+4)(%ebp) // the forwarded selector 1170 movl _FwdSel-L__objc_msgForward$pic_base(%edx),%eax 1171 pushl %eax 1172 leal LUnkSelStr-L__objc_msgForward$pic_base(%edx),%eax 1173 pushl %eax 1174 pushl (self+4)(%ebp) 1175 call ___objc_error // never returns 1176 1177 END_ENTRY __objc_msgForward 1178 1179 1180 ENTRY __objc_msgForward_stret 1181 // Struct return version 1182 1183 // Get PIC base into %edx 1184 call L__objc_msgForwardStret$pic_base 1185L__objc_msgForwardStret$pic_base: 1186 popl %edx 1187 1188 // Call user handler, if any 1189 movl __objc_forward_stret_handler-L__objc_msgForwardStret$pic_base(%edx), %ecx 1190 testl %ecx, %ecx // if not NULL 1191 je 1f // skip to default handler 1192 jmp *%ecx // call __objc_forward_stret_handler 11931: 1194 // No user handler 1195 // Push stack frame 1196 pushl %ebp 1197 movl %esp, %ebp 1198 1199 // Die if forwarding "forward::" 1200 movl (selector_stret+4)(%ebp), %eax 1201 movl _FwdSel-L__objc_msgForwardStret$pic_base(%edx), %ecx 1202 cmpl %ecx, %eax 1203 je LMsgForwardStretError 1204 1205 // Call [receiver forward:sel :margs] 1206 subl $8, %esp // 16-byte align the stack 1207 leal (self_stret+4)(%ebp), %ecx 1208 pushl %ecx // &margs 1209 pushl %eax // sel 1210 movl _FwdSel-L__objc_msgForwardStret$pic_base(%edx),%ecx 1211 pushl %ecx // forward:: 1212 pushl (self_stret+4)(%ebp) // receiver 1213 1214 call _objc_msgSend 1215 1216 movl %ebp, %esp 1217 popl %ebp 1218 ret $4 // pop struct return address (#2995932) 1219 1220LMsgForwardStretError: 1221 // Call __objc_error(receiver, "unknown selector %s %s", "forward::", forwardedSelector) 1222 subl $8, %esp // 16-byte align the stack 1223 pushl (selector_stret+4+4)(%ebp) // the forwarded selector 1224 leal _FwdSel-L__objc_msgForwardStret$pic_base(%edx),%eax 1225 pushl %eax 1226 leal LUnkSelStr-L__objc_msgForwardStret$pic_base(%edx),%eax 1227 pushl %eax 1228 pushl (self_stret+4)(%ebp) 1229 call ___objc_error // never returns 1230 1231 END_ENTRY __objc_msgForward_stret 1232 1233 1234 ENTRY _method_invoke 1235 1236 movl selector(%esp), %ecx 1237 movl method_name(%ecx), %edx 1238 movl method_imp(%ecx), %eax 1239 movl %edx, selector(%esp) 1240 jmp *%eax 1241 1242 END_ENTRY _method_invoke 1243 1244 1245 ENTRY _method_invoke_stret 1246 1247 movl selector_stret(%esp), %ecx 1248 movl method_name(%ecx), %edx 1249 movl method_imp(%ecx), %eax 1250 movl %edx, selector_stret(%esp) 1251 jmp *%eax 1252 1253 END_ENTRY _method_invoke_stret 1254 1255 1256 STATIC_ENTRY __objc_ignored_method 1257 1258 movl self(%esp), %eax 1259 ret 1260 1261 END_ENTRY __objc_ignored_method 1262 1263 1264.section __DATA,__objc_msg_break 1265.long 0 1266.long 0 1267 1268#endif 1269