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