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