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