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