]> git.saurik.com Git - apple/objc4.git/blob - runtime/Messengers.subproj/objc-msg-i386.s
objc4-551.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 #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
106 4:
107 .section __DATA,__objc_msg_break
108 .long 4b
109 .long ENTER
110 .text
111 .endmacro
112 .macro MESSENGER_END_FAST
113 4:
114 .section __DATA,__objc_msg_break
115 .long 4b
116 .long FAST_EXIT
117 .text
118 .endmacro
119 .macro MESSENGER_END_SLOW
120 4:
121 .section __DATA,__objc_msg_break
122 .long 4b
123 .long SLOW_EXIT
124 .text
125 .endmacro
126 .macro MESSENGER_END_NIL
127 4:
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
211 LOCAL_SYMBOL = 0
212 EXTERNAL_SYMBOL = 1
213
214 .macro LOAD_STATIC_WORD
215
216 #if defined(__DYNAMIC__)
217 call 1f
218 1: 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
250 1: 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.
349 WORD_RETURN = 0
350 STRUCT_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.
354 MSG_SEND = 0 // first argument is receiver, search the isa
355 MSG_SENDSUPER = 1 // first argument is objc_super, search the class
356 CACHE_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)
381 LMsgSendProbeCache_$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
396 LMsgSendCacheMiss_$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
419 LMsgSendMaxMissProbeOK_$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
425 LMsgSendMissHistoIndexSet_$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
432 LMsgSendMissInstrumentDone_$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
480 LMsgSendCacheHit_$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
503 LMsgSendMaxHitProbeOK_$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
509 LMsgSendHitHistoIndexSet_$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
516 LMsgSendHitInstrumentDone_$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
610 1: movl $1, %eax
611 ret
612
613 LGetMethodMiss:
614 // cache miss, return nil
615 xorl %eax, %eax // zero %eax
616 ret
617
618 LGetMethodExit:
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
642 LGetImpMiss:
643 // cache miss, return nil
644 xorl %eax, %eax // zero %eax
645 ret
646
647 LGetImpExit:
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
674 LMsgSendReceiverOk:
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
682 LMsgSendCacheMiss:
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
688 LMsgSendNilSelf:
689 call 1f // load new receiver
690 1: 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
696 LMsgSendReturnZero:
697 // %eax is already zero
698 movl $0,%edx
699 LMsgSendDone:
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
709 LMsgSendExit:
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
742 LMsgSendSuperCacheMiss:
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
748 LMsgSendSuperIgnored:
749 movl super(%esp), %eax
750 movl receiver(%eax), %eax
751 MESSENGER_END_NIL
752 ret
753
754 LMsgSendSuperExit:
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
790 LMsgSendvArgLoop:
791 decl %ecx
792 movl 0(%edx, %ecx, 4), %eax
793 pushl %eax
794 jg LMsgSendvArgLoop
795
796 LMsgSendvArgsOK:
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
832 LMsgSendFpretReceiverOk:
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
840 LMsgSendFpretCacheMiss:
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
846 LMsgSendFpretNilSelf:
847 call 1f // load new receiver
848 1: 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
854 LMsgSendFpretReturnZero:
855 fldz
856 LMsgSendFpretDone:
857 MESSENGER_END_NIL
858 ret
859
860 LMsgSendFpretExit:
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
896 LMsgSendvFpretArgLoop:
897 decl %ecx
898 movl 0(%edx, %ecx, 4), %eax
899 pushl %eax
900 jg LMsgSendvFpretArgLoop
901
902 LMsgSendvFpretArgsOK:
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
942 LMsgSendStretReceiverOk:
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
950 LMsgSendStretCacheMiss:
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
956 LMsgSendStretNilSelf:
957 call 1f // load new receiver
958 1: 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
964 LMsgSendStretDone:
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
975 LMsgSendStretExit:
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
1013 LMsgSendSuperStretCacheMiss:
1014 MethodTableLookup STRUCT_RETURN, MSG_SENDSUPER
1015 movl $1, %edx // set stret for objc_msgForward
1016 jmp *%eax // goto *imp
1017
1018 LMsgSendSuperStretExit:
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
1059 LMsgSendvStretArgLoop:
1060 decl %ecx
1061 movl 0(%edx, %ecx, 4), %eax
1062 pushl %eax
1063 jg LMsgSendvStretArgLoop
1064
1065 LMsgSendvStretArgsOK:
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
1096 LUnkSelStr: .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
1131 L__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
1139 1:
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
1166 LMsgForwardError:
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
1185 L__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
1193 1:
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
1220 LMsgForwardStretError:
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