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