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