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