]> git.saurik.com Git - apple/objc4.git/blob - runtime/Messengers.subproj/objc-msg-i386.s
objc4-235.tar.gz
[apple/objc4.git] / runtime / Messengers.subproj / objc-msg-i386.s
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /********************************************************************
26 ********************************************************************
27 **
28 ** objc-msg-i386.s - i386 code to support objc messaging.
29 **
30 ********************************************************************
31 ********************************************************************/
32
33 // The assembler syntax for an immediate value is the same as the
34 // syntax for a macro argument number (dollar sign followed by the
35 // digits). Argument number wins in this ambiguity. Until the
36 // assembler is fixed we have to find another way.
37 #define NO_MACRO_CONSTS
38 #ifdef NO_MACRO_CONSTS
39 kTwo = 2
40 kEight = 8
41 #endif
42
43 /********************************************************************
44 * Data used by the ObjC runtime.
45 *
46 ********************************************************************/
47
48 .data
49 // Substitute receiver for messages sent to nil (usually also nil)
50 // id _objc_nilReceiver
51 .align 4
52 .globl __objc_nilReceiver
53 __objc_nilReceiver:
54 .long 0
55
56 // _objc_entryPoints and _objc_exitPoints are used by objc
57 // to get the critical regions for which method caches
58 // cannot be garbage collected.
59
60 .globl _objc_entryPoints
61 _objc_entryPoints:
62 .long __cache_getImp
63 .long __cache_getMethod
64 .long _objc_msgSend
65 .long _objc_msgSend_stret
66 .long _objc_msgSendSuper
67 .long _objc_msgSendSuper_stret
68 .long 0
69
70 .globl _objc_exitPoints
71 _objc_exitPoints:
72 .long LGetImpExit
73 .long LGetMethodExit
74 .long LMsgSendExit
75 .long LMsgSendStretExit
76 .long LMsgSendSuperExit
77 .long LMsgSendSuperStretExit
78 .long 0
79
80 /*
81 * Handcrafted dyld stubs for each external call.
82 * They should be converted into a local branch after linking. aB.
83 */
84
85 /* asm_help.h version is not what we want */
86 #undef CALL_EXTERN
87
88 #if defined(__DYNAMIC__)
89
90 #define CALL_EXTERN(name) call L ## name ## $stub
91
92 #define LAZY_PIC_FUNCTION_STUB(name) \
93 .data ;\
94 .picsymbol_stub ;\
95 L ## name ## $stub: ;\
96 .indirect_symbol name ;\
97 call L0$ ## name ;\
98 L0$ ## name: ;\
99 popl %eax ;\
100 movl L ## name ## $lz-L0$ ## name(%eax),%edx ;\
101 jmp %edx ;\
102 L ## name ## $stub_binder: ;\
103 lea L ## name ## $lz-L0$ ## name(%eax),%eax ;\
104 pushl %eax ;\
105 jmp dyld_stub_binding_helper ;\
106 .data ;\
107 .lazy_symbol_pointer ;\
108 L ## name ## $lz: ;\
109 .indirect_symbol name ;\
110 .long L ## name ## $stub_binder
111
112 #else /* __DYNAMIC__ */
113
114 #define CALL_EXTERN(name) call name
115
116 #define LAZY_PIC_FUNCTION_STUB(name)
117
118 #endif /* __DYNAMIC__ */
119
120 // _class_lookupMethodAndLoadCache
121 LAZY_PIC_FUNCTION_STUB(__class_lookupMethodAndLoadCache)
122
123 // __objc_error
124 LAZY_PIC_FUNCTION_STUB(___objc_error) /* No stub needed */
125
126 #if defined(PROFILE)
127 // mcount
128 LAZY_PIC_FUNCTION_STUB(mcount)
129 #endif /* PROFILE */
130
131 /********************************************************************
132 *
133 * Constants.
134 *
135 ********************************************************************/
136
137 // In case the implementation is _objc_msgForward, indicate to it
138 // whether the method was invoked as a word-return or struct-return.
139 // This flag is passed in a register that is caller-saved, and is
140 // not part of the parameter passing convention (i.e. it is "out of
141 // band"). This works because _objc_msgForward is only entered
142 // from here in the messenger.
143 kFwdMsgSend = 1
144 kFwdMsgSendStret = 0
145
146
147 /********************************************************************
148 *
149 * Common offsets.
150 *
151 ********************************************************************/
152
153 self = 4
154 super = 4
155 selector = 8
156 marg_size = 12
157 marg_list = 16
158 first_arg = 12
159
160 struct_addr = 4
161
162 self_stret = 8
163 super_stret = 8
164 selector_stret = 12
165 marg_size_stret = 16
166 marg_list_stret = 20
167
168
169 /********************************************************************
170 *
171 * Structure definitions.
172 *
173 ********************************************************************/
174
175 // objc_super parameter to sendSuper
176 receiver = 0
177 class = 4
178
179 // Selected field offsets in class structure
180 isa = 0
181 cache = 32
182
183 // Method descriptor
184 method_name = 0
185 method_imp = 8
186
187 // Cache header
188 mask = 0
189 occupied = 4
190 buckets = 8 // variable length array
191
192 #if defined(OBJC_INSTRUMENTED)
193 // Cache instrumentation data, follows buckets
194 hitCount = 0
195 hitProbes = hitCount + 4
196 maxHitProbes = hitProbes + 4
197 missCount = maxHitProbes + 4
198 missProbes = missCount + 4
199 maxMissProbes = missProbes + 4
200 flushCount = maxMissProbes + 4
201 flushedEntries = flushCount + 4
202
203 // Buckets in CacheHitHistogram and CacheMissHistogram
204 CACHE_HISTOGRAM_SIZE = 512
205 #endif
206
207
208 //////////////////////////////////////////////////////////////////////
209 //
210 // LOAD_STATIC_WORD targetReg, symbolName, LOCAL_SYMBOL | EXTERNAL_SYMBOL
211 //
212 // Load the value of the named static data word.
213 //
214 // Takes: targetReg - the register, other than r0, to load
215 // symbolName - the name of the symbol
216 // LOCAL_SYMBOL - symbol name used as-is
217 // EXTERNAL_SYMBOL - symbol name gets nonlazy treatment
218 //
219 // Eats: edx and targetReg
220 //////////////////////////////////////////////////////////////////////
221
222 // Values to specify whether the symbol is plain or nonlazy
223 LOCAL_SYMBOL = 0
224 EXTERNAL_SYMBOL = 1
225
226 .macro LOAD_STATIC_WORD
227
228 #if defined(__DYNAMIC__)
229 call 1f
230 1: popl %edx
231 .if $2 == EXTERNAL_SYMBOL
232 movl L$1-1b(%edx),$0
233 movl 0($0),$0
234 .elseif $2 == LOCAL_SYMBOL
235 movl $1-1b(%edx),$0
236 .else
237 !!! Unknown symbol type !!!
238 .endif
239 #else
240 movl $1,$0
241 #endif
242
243 .endmacro
244
245 //////////////////////////////////////////////////////////////////////
246 //
247 // LEA_STATIC_DATA targetReg, symbolName, LOCAL_SYMBOL | EXTERNAL_SYMBOL
248 //
249 // Load the address of the named static data.
250 //
251 // Takes: targetReg - the register, other than edx, to load
252 // symbolName - the name of the symbol
253 // LOCAL_SYMBOL - symbol is local to this module
254 // EXTERNAL_SYMBOL - symbol is imported from another module
255 //
256 // Eats: edx and targetReg
257 //////////////////////////////////////////////////////////////////////
258
259 .macro LEA_STATIC_DATA
260 #if defined(__DYNAMIC__)
261 call 1f
262 1: popl %edx
263 .if $2 == EXTERNAL_SYMBOL
264 movl L$1-1b(%edx),$0
265 .elseif $2 == LOCAL_SYMBOL
266 leal $1-1b(%edx),$0
267 .else
268 !!! Unknown symbol type !!!
269 .endif
270 #else
271 leal $1,$0
272 #endif
273
274 .endmacro
275
276 //////////////////////////////////////////////////////////////////////
277 //
278 // ENTRY functionName
279 //
280 // Assembly directives to begin an exported function.
281 //
282 // Takes: functionName - name of the exported function
283 //////////////////////////////////////////////////////////////////////
284
285 .macro ENTRY
286 .text
287 .globl $0
288 .align 4, 0x90
289 $0:
290 .endmacro
291
292 //////////////////////////////////////////////////////////////////////
293 //
294 // END_ENTRY functionName
295 //
296 // Assembly directives to end an exported function. Just a placeholder,
297 // a close-parenthesis for ENTRY, until it is needed for something.
298 //
299 // Takes: functionName - name of the exported function
300 //////////////////////////////////////////////////////////////////////
301
302 .macro END_ENTRY
303 .endmacro
304
305 //////////////////////////////////////////////////////////////////////
306 //
307 // CALL_MCOUNTER counterName
308 //
309 // Allocate and maintain a counter for the call site.
310 //
311 // Takes: counterName - name of counter.
312 //////////////////////////////////////////////////////////////////////
313
314 .macro CALL_MCOUNTER
315 #ifdef PROFILE
316 pushl %ebp
317 movl %esp,%ebp
318 LOAD_STATIC_WORD %eax, $0, LOCAL_SYMBOL
319 CALL_EXTERN(mcount)
320 .data
321 .align 2
322 $0:
323 .long 0
324 .text
325 movl %ebp,%esp
326 popl %ebp
327 #endif
328 .endmacro
329
330
331 /////////////////////////////////////////////////////////////////////
332 //
333 //
334 // CacheLookup WORD_RETURN | STRUCT_RETURN, MSG_SEND | MSG_SENDSUPER | CACHE_GET, cacheMissLabel
335 //
336 // Locate the implementation for a selector in a class method cache.
337 //
338 // Takes: WORD_RETURN (first parameter is at sp+4)
339 // STRUCT_RETURN (struct address is at sp+4, first parameter at sp+8)
340 // MSG_SEND (first parameter is receiver)
341 // MSG_SENDSUPER (first parameter is address of objc_super structure)
342 // CACHE_GET (first parameter is class; return method triplet)
343 //
344 // cacheMissLabel = label to branch to iff method is not cached
345 //
346 // On exit: (found) MSG_SEND and MSG_SENDSUPER: return imp in eax
347 // (found) CACHE_GET: return method triplet in eax
348 // (not found) jumps to cacheMissLabel
349 //
350 /////////////////////////////////////////////////////////////////////
351
352
353 // Values to specify to method lookup macros whether the return type of
354 // the method is word or structure.
355 WORD_RETURN = 0
356 STRUCT_RETURN = 1
357
358 // Values to specify to method lookup macros whether the first argument
359 // is an object/class reference or a 'objc_super' structure.
360 MSG_SEND = 0 // first argument is receiver, search the isa
361 MSG_SENDSUPER = 1 // first argument is objc_super, search the class
362 CACHE_GET = 2 // first argument is class, search that class
363
364 .macro CacheLookup
365
366 // load variables and save caller registers.
367 // Overlapped to prevent AGI
368 .if $0 == WORD_RETURN // Regular word return
369 .if $1 == MSG_SEND // MSG_SEND
370 movl isa(%eax), %eax // class = self->isa
371 movl selector(%esp), %ecx // get selector
372 .elseif $1 == MSG_SENDSUPER // MSG_SENDSUPER
373 movl super(%esp), %eax // get objc_super address
374 movl class(%eax), %eax // class = caller->class
375 movl selector(%esp), %ecx // get selector
376 .else // CACHE_GET
377 movl selector(%esp), %ecx // get selector - class already in eax
378 .endif
379 .else // Struct return
380 .if $1 == MSG_SEND // MSG_SEND (stret)
381 movl isa(%eax), %eax // class = self->isa
382 movl (selector_stret)(%esp), %ecx // get selector
383 .elseif $1 == MSG_SENDSUPER // MSG_SENDSUPER (stret)
384 movl super_stret(%esp), %eax // get objc_super address
385 movl class(%eax), %eax // class = caller->class
386 movl (selector_stret)(%esp), %ecx // get selector
387 .else // CACHE_GET
388 !! This should not happen.
389 .endif
390 .endif
391
392 pushl %edi // save scratch register
393 movl cache(%eax), %eax // cache = class->cache
394 pushl %esi // save scratch register
395
396 #if defined(OBJC_INSTRUMENTED)
397 pushl %ebx // save non-volatile register
398 pushl %eax // save cache pointer
399 xorl %ebx, %ebx // probeCount = 0
400 #endif
401 leal buckets(%eax), %edi // buckets = &cache->buckets
402 movl mask(%eax), %esi // mask = cache->mask
403 movl %ecx, %edx // index = selector
404 #ifdef NO_MACRO_CONSTS
405 shrl $kTwo, %edx // index = selector >> 2
406 #else
407 shrl $2, %edx // index = selector >> 2
408 #endif
409
410 // search the receiver's cache
411 LMsgSendProbeCache_$0_$1_$2:
412 #if defined(OBJC_INSTRUMENTED)
413 inc %ebx // probeCount += 1
414 #endif
415 andl %esi, %edx // index &= mask
416 movl (%edi, %edx, 4), %eax // method = buckets[index]
417
418 testl %eax, %eax // check for end of bucket
419 je LMsgSendCacheMiss_$0_$1_$2 // go to cache miss code
420 cmpl method_name(%eax), %ecx // check for method name match
421 je LMsgSendCacheHit_$0_$1_$2 // go handle cache hit
422 inc %edx // bump index ...
423 jmp LMsgSendProbeCache_$0_$1_$2 // ... and loop
424
425 // not found in cache: restore state and go to callers handler
426 LMsgSendCacheMiss_$0_$1_$2:
427 #if defined(OBJC_INSTRUMENTED)
428 popl %edx // retrieve cache pointer
429 movl mask(%edx), %esi // mask = cache->mask
430 testl %esi, %esi // a mask of zero is only for the...
431 je LMsgSendMissInstrumentDone_$0_$1_$2 // ... emptyCache, do not record anything
432
433 // locate and update the CacheInstrumentation structure
434 inc %esi // entryCount = mask + 1
435 #ifdef NO_MACRO_CONSTS
436 shll $kTwo, %esi // tableSize = entryCount * sizeof(entry)
437 #else
438 shll $2, %esi // tableSize = entryCount * sizeof(entry)
439 #endif
440 addl $buckets, %esi // offset = buckets + tableSize
441 addl %edx, %esi // cacheData = &cache->buckets[mask+1]
442
443 movl missCount(%esi), %edi //
444 inc %edi //
445 movl %edi, missCount(%esi) // cacheData->missCount += 1
446 movl missProbes(%esi), %edi //
447 addl %ebx, %edi //
448 movl %edi, missProbes(%esi) // cacheData->missProbes += probeCount
449 movl maxMissProbes(%esi), %edi// if (cacheData->maxMissProbes < probeCount)
450 cmpl %ebx, %edi //
451 jge LMsgSendMaxMissProbeOK_$0_$1_$2 //
452 movl %ebx, maxMissProbes(%esi)// cacheData->maxMissProbes = probeCount
453 LMsgSendMaxMissProbeOK_$0_$1_$2:
454
455 // update cache miss probe histogram
456 cmpl $CACHE_HISTOGRAM_SIZE, %ebx // pin probeCount to max index
457 jl LMsgSendMissHistoIndexSet_$0_$1_$2
458 movl $(CACHE_HISTOGRAM_SIZE-1), %ebx
459 LMsgSendMissHistoIndexSet_$0_$1_$2:
460 LEA_STATIC_DATA %esi, _CacheMissHistogram, EXTERNAL_SYMBOL
461 #ifdef NO_MACRO_CONSTS
462 shll $kTwo, %ebx // convert probeCount to histogram index
463 #else
464 shll $2, %ebx // convert probeCount to histogram index
465 #endif
466 addl %ebx, %esi // calculate &CacheMissHistogram[probeCount<<2]
467 movl 0(%esi), %edi // get current tally
468 inc %edi //
469 movl %edi, 0(%esi) // tally += 1
470 LMsgSendMissInstrumentDone_$0_$1_$2:
471 popl %ebx // restore non-volatile register
472 #endif
473
474 .if $0 == WORD_RETURN // Regular word return
475 .if $1 == MSG_SEND // MSG_SEND
476 popl %esi // restore callers register
477 popl %edi // restore callers register
478 movl self(%esp), %eax // get messaged object
479 movl isa(%eax), %eax // get objects class
480 .elseif $1 == MSG_SENDSUPER // MSG_SENDSUPER
481 // replace "super" arg with "receiver"
482 movl super+8(%esp), %edi // get super structure
483 movl receiver(%edi), %esi // get messaged object
484 movl %esi, super+8(%esp) // make it the first argument
485 movl class(%edi), %eax // get messaged class
486 popl %esi // restore callers register
487 popl %edi // restore callers register
488 .else // CACHE_GET
489 popl %esi // restore callers register
490 popl %edi // restore callers register
491 .endif
492 .else // Struct return
493 .if $1 == MSG_SEND // MSG_SEND (stret)
494 popl %esi // restore callers register
495 popl %edi // restore callers register
496 movl self_stret(%esp), %eax // get messaged object
497 movl isa(%eax), %eax // get objects class
498 .elseif $1 == MSG_SENDSUPER // MSG_SENDSUPER (stret)
499 // replace "super" arg with "receiver"
500 movl super_stret+8(%esp), %edi// get super structure
501 movl receiver(%edi), %esi // get messaged object
502 movl %esi, super_stret+8(%esp)// make it the first argument
503 movl class(%edi), %eax // get messaged class
504 popl %esi // restore callers register
505 popl %edi // restore callers register
506 .else // CACHE_GET
507 !! This should not happen.
508 .endif
509 .endif
510
511 jmp $2 // go to callers handler
512
513 // eax points to matching cache entry
514 .align 4, 0x90
515 LMsgSendCacheHit_$0_$1_$2:
516 #if defined(OBJC_INSTRUMENTED)
517 popl %edx // retrieve cache pointer
518 movl mask(%edx), %esi // mask = cache->mask
519 testl %esi, %esi // a mask of zero is only for the...
520 je LMsgSendHitInstrumentDone_$0_$1_$2 // ... emptyCache, do not record anything
521
522 // locate and update the CacheInstrumentation structure
523 inc %esi // entryCount = mask + 1
524 #ifdef NO_MACRO_CONSTS
525 shll $kTwo, %esi // tableSize = entryCount * sizeof(entry)
526 #else
527 shll $2, %esi // tableSize = entryCount * sizeof(entry)
528 #endif
529 addl $buckets, %esi // offset = buckets + tableSize
530 addl %edx, %esi // cacheData = &cache->buckets[mask+1]
531
532 movl hitCount(%esi), %edi
533 inc %edi
534 movl %edi, hitCount(%esi) // cacheData->hitCount += 1
535 movl hitProbes(%esi), %edi
536 addl %ebx, %edi
537 movl %edi, hitProbes(%esi) // cacheData->hitProbes += probeCount
538 movl maxHitProbes(%esi), %edi// if (cacheData->maxHitProbes < probeCount)
539 cmpl %ebx, %edi
540 jge LMsgSendMaxHitProbeOK_$0_$1_$2
541 movl %ebx, maxHitProbes(%esi)// cacheData->maxHitProbes = probeCount
542 LMsgSendMaxHitProbeOK_$0_$1_$2:
543
544 // update cache hit probe histogram
545 cmpl $CACHE_HISTOGRAM_SIZE, %ebx // pin probeCount to max index
546 jl LMsgSendHitHistoIndexSet_$0_$1_$2
547 movl $(CACHE_HISTOGRAM_SIZE-1), %ebx
548 LMsgSendHitHistoIndexSet_$0_$1_$2:
549 LEA_STATIC_DATA %esi, _CacheHitHistogram, EXTERNAL_SYMBOL
550 #ifdef NO_MACRO_CONSTS
551 shll $kTwo, %ebx // convert probeCount to histogram index
552 #else
553 shll $2, %ebx // convert probeCount to histogram index
554 #endif
555 addl %ebx, %esi // calculate &CacheHitHistogram[probeCount<<2]
556 movl 0(%esi), %edi // get current tally
557 inc %edi //
558 movl %edi, 0(%esi) // tally += 1
559 LMsgSendHitInstrumentDone_$0_$1_$2:
560 popl %ebx // restore non-volatile register
561 #endif
562
563 // load implementation address, restore state, and we're done
564 .if $1 == CACHE_GET
565 // method triplet is already in eax
566 .else
567 movl method_imp(%eax), %eax // imp = method->method_imp
568 .endif
569
570 .if $0 == WORD_RETURN // Regular word return
571 .if $1 == MSG_SENDSUPER // MSG_SENDSUPER
572 // replace "super" arg with "self"
573 movl super+8(%esp), %edi
574 movl receiver(%edi), %esi
575 movl %esi, super+8(%esp)
576 .endif
577 .else // Struct return
578 .if $1 == MSG_SENDSUPER // MSG_SENDSUPER (stret)
579 // replace "super" arg with "self"
580 movl super_stret+8(%esp), %edi
581 movl receiver(%edi), %esi
582 movl %esi, super_stret+8(%esp)
583 .endif
584 .endif
585
586 // restore caller registers
587 popl %esi
588 popl %edi
589 .endmacro
590
591
592 /////////////////////////////////////////////////////////////////////
593 //
594 // MethodTableLookup WORD_RETURN | STRUCT_RETURN, MSG_SEND | MSG_SENDSUPER
595 //
596 // Takes: WORD_RETURN (first parameter is at sp+4)
597 // STRUCT_RETURN (struct address is at sp+4, first parameter at sp+8)
598 // MSG_SEND (first parameter is receiver)
599 // MSG_SENDSUPER (first parameter is address of objc_super structure)
600 //
601 // On exit: Register parameters restored from CacheLookup
602 // imp in eax
603 //
604 /////////////////////////////////////////////////////////////////////
605
606 .macro MethodTableLookup
607
608 // push args (class, selector)
609 pushl %ecx
610 pushl %eax
611 CALL_EXTERN(__class_lookupMethodAndLoadCache)
612 #ifdef NO_MACRO_CONSTS
613 addl $kEight, %esp // pop parameters
614 #else
615 addl $8, %esp // pop parameters
616 #endif
617 .endmacro
618
619
620 /********************************************************************
621 * Method _cache_getMethod(Class cls, SEL sel, IMP objc_msgForward_imp)
622 *
623 * If found, returns method triplet pointer.
624 * If not found, returns NULL.
625 *
626 * NOTE: _cache_getMethod never returns any cache entry whose implementation
627 * is _objc_msgForward. It returns NULL instead. This prevents thread-
628 * safety and memory management bugs in _class_lookupMethodAndLoadCache.
629 * See _class_lookupMethodAndLoadCache for details.
630 *
631 * _objc_msgForward is passed as a parameter because it's more efficient
632 * to do the (PIC) lookup once in the caller than repeatedly here.
633 ********************************************************************/
634
635 ENTRY __cache_getMethod
636
637 // load the class into eax
638 movl self(%esp), %eax
639
640 // do lookup
641 CacheLookup WORD_RETURN, CACHE_GET, LGetMethodMiss
642
643 // cache hit, method triplet in %eax
644 movl first_arg(%esp), %ecx // check for _objc_msgForward
645 cmpl method_imp(%eax), %ecx
646 je LGetMethodMiss // if (imp==_objc_msgForward) return nil
647 ret // else return method triplet address
648
649 LGetMethodMiss:
650 // cache miss, return nil
651 xorl %eax, %eax // zero %eax
652 ret
653
654 LGetMethodExit:
655 END_ENTRY __cache_getMethod
656
657
658 /********************************************************************
659 * IMP _cache_getImp(Class cls, SEL sel)
660 *
661 * If found, returns method implementation.
662 * If not found, returns NULL.
663 ********************************************************************/
664
665 ENTRY __cache_getImp
666
667 // load the class into eax
668 movl self(%esp), %eax
669
670 // do lookup
671 CacheLookup WORD_RETURN, CACHE_GET, LGetImpMiss
672
673 // cache hit, method triplet in %eax
674 movl method_imp(%eax), %eax // return method imp
675 ret
676
677 LGetImpMiss:
678 // cache miss, return nil
679 xorl %eax, %eax // zero %eax
680 ret
681
682 LGetImpExit:
683 END_ENTRY __cache_getImp
684
685
686 /********************************************************************
687 *
688 * id objc_msgSend(id self, SEL _cmd,...);
689 *
690 ********************************************************************/
691
692 ENTRY _objc_msgSend
693 CALL_MCOUNTER LP0
694
695 movl self(%esp), %eax
696
697 // check whether receiver is nil
698 testl %eax, %eax
699 je LMsgSendNilSelf
700
701 // receiver is non-nil: search the cache
702 LMsgSendReceiverOk:
703 CacheLookup WORD_RETURN, MSG_SEND, LMsgSendCacheMiss
704 movl $kFwdMsgSend, %edx // flag word-return for _objc_msgForward
705 jmp *%eax // goto *imp
706
707 // cache miss: go search the method lists
708 LMsgSendCacheMiss:
709 MethodTableLookup WORD_RETURN, MSG_SEND
710 movl $kFwdMsgSend, %edx // flag word-return for _objc_msgForward
711 jmp *%eax // goto *imp
712
713 // message sent to nil: redirect to nil receiver, if any
714 LMsgSendNilSelf:
715 call 1f // load new receiver
716 1: popl %edx
717 movl __objc_nilReceiver-1b(%edx),%eax
718 testl %eax, %eax // return nil if no new receiver
719 je LMsgSendDone
720 movl %eax, self(%esp) // send to new receiver
721 jmp LMsgSendReceiverOk
722 LMsgSendDone:
723 ret
724
725 // guaranteed non-nil entry point (disabled for now)
726 // .globl _objc_msgSendNonNil
727 // _objc_msgSendNonNil:
728 // movl self(%esp), %eax
729 // jmp LMsgSendReceiverOk
730
731 LMsgSendExit:
732 END_ENTRY _objc_msgSend
733
734 /********************************************************************
735 *
736 * id objc_msgSendSuper(struct objc_super *super, SEL _cmd,...);
737 *
738 * struct objc_super {
739 * id receiver;
740 * Class class;
741 * };
742 ********************************************************************/
743
744 ENTRY _objc_msgSendSuper
745 CALL_MCOUNTER LP1
746
747 movl super(%esp), %eax
748
749 // receiver is non-nil: search the cache
750 CacheLookup WORD_RETURN, MSG_SENDSUPER, LMsgSendSuperCacheMiss
751 movl $kFwdMsgSend, %edx // flag word-return for _objc_msgForward
752 jmp *%eax // goto *imp
753
754 // cache miss: go search the method lists
755 LMsgSendSuperCacheMiss:
756 MethodTableLookup WORD_RETURN, MSG_SENDSUPER
757 movl $kFwdMsgSend, %edx // flag word-return for _objc_msgForward
758 jmp *%eax // goto *imp
759
760 LMsgSendSuperExit:
761 END_ENTRY _objc_msgSendSuper
762
763 /********************************************************************
764 * id objc_msgSendv(id self, SEL _cmd, unsigned size, marg_list frame);
765 *
766 * On entry:
767 * (sp+4) is the message receiver,
768 * (sp+8) is the selector,
769 * (sp+12) is the size of the marg_list, in bytes,
770 * (sp+16) is the address of the marg_list
771 *
772 ********************************************************************/
773
774 ENTRY _objc_msgSendv
775
776 #if defined(KERNEL)
777 trap // _objc_msgSendv is not for the kernel
778 #else
779 pushl %ebp
780 movl %esp, %ebp
781 movl (marg_list+4)(%ebp), %edx
782 addl $8, %edx // skip self & selector
783 movl (marg_size+4)(%ebp), %ecx
784 subl $5, %ecx // skip self & selector
785 shrl $2, %ecx
786 jle LMsgSendvArgsOK
787 LMsgSendvArgLoop:
788 decl %ecx
789 movl 0(%edx, %ecx, 4), %eax
790 pushl %eax
791 jg LMsgSendvArgLoop
792
793 LMsgSendvArgsOK:
794 movl (selector+4)(%ebp), %ecx
795 pushl %ecx
796 movl (self+4)(%ebp),%ecx
797 pushl %ecx
798 call _objc_msgSend
799 movl %ebp,%esp
800 popl %ebp
801
802 ret
803 #endif
804 END_ENTRY _objc_msgSendv
805
806
807 /********************************************************************
808 *
809 * void objc_msgSend_stret(void *st_addr , id self, SEL _cmd, ...);
810 *
811 *
812 * objc_msgSend_stret is the struct-return form of msgSend.
813 * The ABI calls for (sp+4) to be used as the address of the structure
814 * being returned, with the parameters in the succeeding locations.
815 *
816 * On entry: (sp+4)is the address where the structure is returned,
817 * (sp+8) is the message receiver,
818 * (sp+12) is the selector
819 ********************************************************************/
820
821 ENTRY _objc_msgSend_stret
822 CALL_MCOUNTER LP2
823
824 movl self_stret(%esp), %eax
825
826 // check whether receiver is nil
827 testl %eax, %eax
828 je LMsgSendStretNilSelf
829
830 // receiver is non-nil: search the cache
831 LMsgSendStretReceiverOk:
832 CacheLookup STRUCT_RETURN, MSG_SEND, LMsgSendStretCacheMiss
833 movl $kFwdMsgSendStret, %edx // flag struct-return for _objc_msgForward
834 jmp *%eax // goto *imp
835
836 // cache miss: go search the method lists
837 LMsgSendStretCacheMiss:
838 MethodTableLookup STRUCT_RETURN, MSG_SEND
839 movl $kFwdMsgSendStret, %edx // flag struct-return for _objc_msgForward
840 jmp *%eax // goto *imp
841
842 // message sent to nil: redirect to nil receiver, if any
843 LMsgSendStretNilSelf:
844 call 1f // load new receiver
845 1: popl %edx
846 movl __objc_nilReceiver-1b(%edx),%eax
847 testl %eax, %eax // return nil if no new receiver
848 je LMsgSendStretDone
849 movl %eax, self_stret(%esp) // send to new receiver
850 jmp LMsgSendStretReceiverOk
851 LMsgSendStretDone:
852 ret $4 // pop struct return address (#2995932)
853
854 // guaranteed non-nil entry point (disabled for now)
855 // .globl _objc_msgSendNonNil_stret
856 // _objc_msgSendNonNil_stret:
857 // CALL_MCOUNTER LP3
858 // movl self_stret(%esp), %eax
859 // jmp LMsgSendStretReceiverOk
860
861 LMsgSendStretExit:
862 END_ENTRY _objc_msgSend_stret
863
864 /********************************************************************
865 *
866 * void objc_msgSendSuper_stret(void *st_addr, struct objc_super *super, SEL _cmd, ...);
867 *
868 * struct objc_super {
869 * id receiver;
870 * Class class;
871 * };
872 *
873 * objc_msgSendSuper_stret is the struct-return form of msgSendSuper.
874 * The ABI calls for (sp+4) to be used as the address of the structure
875 * being returned, with the parameters in the succeeding registers.
876 *
877 * On entry: (sp+4)is the address where the structure is returned,
878 * (sp+8) is the address of the objc_super structure,
879 * (sp+12) is the selector
880 *
881 ********************************************************************/
882
883 ENTRY _objc_msgSendSuper_stret
884 CALL_MCOUNTER LP4
885
886 movl super_stret(%esp), %eax
887
888 // receiver is non-nil: search the cache
889 CacheLookup STRUCT_RETURN, MSG_SENDSUPER, LMsgSendSuperStretCacheMiss
890 movl $kFwdMsgSendStret, %edx // flag struct-return for _objc_msgForward
891 jmp *%eax // goto *imp
892
893 // cache miss: go search the method lists
894 LMsgSendSuperStretCacheMiss:
895 MethodTableLookup STRUCT_RETURN, MSG_SENDSUPER
896 movl $kFwdMsgSendStret, %edx // flag struct-return for _objc_msgForward
897 jmp *%eax // goto *imp
898
899 LMsgSendSuperStretExit:
900 END_ENTRY _objc_msgSendSuper_stret
901
902
903 /********************************************************************
904 * id objc_msgSendv_stret(void *st_addr, id self, SEL _cmd, unsigned size, marg_list frame);
905 *
906 * objc_msgSendv_stret is the struct-return form of msgSendv.
907 * The ABI calls for (sp+4) to be used as the address of the structure
908 * being returned, with the parameters in the succeeding locations.
909 *
910 * On entry: (sp+4) is the address in which the returned struct is put,
911 * (sp+8) is the message receiver,
912 * (sp+12) is the selector,
913 * (sp+16) is the size of the marg_list, in bytes,
914 * (sp+20) is the address of the marg_list
915 *
916 ********************************************************************/
917
918 ENTRY _objc_msgSendv_stret
919
920 #if defined(KERNEL)
921 trap // _objc_msgSendv_stret is not for the kernel
922 #else
923 pushl %ebp
924 movl %esp, %ebp
925 movl (marg_list_stret+4)(%ebp), %edx
926 addl $8, %edx // skip self & selector
927 movl (marg_size_stret+4)(%ebp), %ecx
928 subl $5, %ecx // skip self & selector
929 shrl $2, %ecx
930 jle LMsgSendvStretArgsOK
931 LMsgSendvStretArgLoop:
932 decl %ecx
933 movl 0(%edx, %ecx, 4), %eax
934 pushl %eax
935 jg LMsgSendvStretArgLoop
936
937 LMsgSendvStretArgsOK:
938 movl (selector_stret+4)(%ebp), %ecx
939 pushl %ecx
940 movl (self_stret+4)(%ebp),%ecx
941 pushl %ecx
942 movl (struct_addr+4)(%ebp),%ecx
943 pushl %ecx
944 call _objc_msgSend_stret
945 movl %ebp,%esp
946 popl %ebp
947
948 ret
949 #endif
950 END_ENTRY _objc_msgSendv_stret
951
952
953 /********************************************************************
954 *
955 * id _objc_msgForward(id self, SEL _cmd,...);
956 *
957 ********************************************************************/
958
959 // Location LFwdStr contains the string "forward::"
960 // Location LFwdSel contains a pointer to LFwdStr, that can be changed
961 // to point to another forward:: string for selector uniquing
962 // purposes. ALWAYS dereference LFwdSel to get to "forward::" !!
963 .objc_meth_var_names
964 .align 2
965 LFwdStr:.ascii "forward::\0"
966
967 .objc_message_refs
968 .align 2
969 LFwdSel:.long LFwdStr
970
971 .cstring
972 .align 2
973 LUnkSelStr: .ascii "Does not recognize selector %s\0"
974
975 ENTRY __objc_msgForward
976
977 #if defined(KERNEL)
978 trap // _objc_msgForward is not for the kernel
979 #else
980 cmpl $kFwdMsgSendStret, %edx // check secret flag for word vs struct return
981 je LForwardStretVersion // jump to struct return version...
982
983 // non-stret version ...
984 pushl %ebp
985 movl %esp,%ebp
986 movl (selector+4)(%esp), %eax
987 #if defined(__DYNAMIC__)
988 call L__objc_msgForward$pic_base
989 L__objc_msgForward$pic_base:
990 popl %edx
991 leal LFwdSel-L__objc_msgForward$pic_base(%edx),%ecx
992 cmpl %ecx, %eax
993 #else
994 cmpl LFwdSel, %eax
995 #endif
996 je LMsgForwardError
997
998 leal (self+4)(%esp), %ecx
999 pushl %ecx
1000 pushl %eax
1001 #if defined(__DYNAMIC__)
1002 movl LFwdSel-L__objc_msgForward$pic_base(%edx),%ecx
1003 #else
1004 movl LFwdSel,%ecx
1005 #endif
1006 pushl %ecx
1007 pushl (self+16)(%esp)
1008 call _objc_msgSend
1009 movl %ebp,%esp
1010 popl %ebp
1011 ret
1012
1013 // call error handler with unrecognized selector message
1014 .align 4, 0x90
1015 LMsgForwardError:
1016 #if defined(__DYNAMIC__)
1017 leal LFwdSel-L__objc_msgForward$pic_base(%edx),%eax
1018 pushl %eax
1019 leal LUnkSelStr-L__objc_msgForward$pic_base(%edx),%eax
1020 pushl %eax
1021 #else
1022 pushl $LFwdSel
1023 pushl $LUnkSelStr
1024 #endif
1025 pushl (self+12)(%esp)
1026 CALL_EXTERN(___objc_error) // volatile, will not return
1027
1028 // ***** Stret version of function below
1029 // ***** offsets have been changed (by adding a word to make room for the
1030 // ***** structure, and labels have been changed to be unique.
1031
1032 LForwardStretVersion:
1033 pushl %ebp
1034 movl %esp,%ebp
1035 movl (selector_stret+4)(%esp), %eax
1036
1037 #if defined(__DYNAMIC__)
1038 call L__objc_msgForwardStret$pic_base
1039 L__objc_msgForwardStret$pic_base:
1040 popl %edx
1041 leal LFwdSel-L__objc_msgForwardStret$pic_base(%edx),%ecx
1042 cmpl %ecx, %eax
1043 #else
1044 cmpl LFwdSel, %eax
1045 #endif
1046 je LMsgForwardStretError
1047
1048 leal (self_stret+4)(%esp), %ecx
1049 pushl %ecx
1050 pushl %eax
1051 #if defined(__DYNAMIC__)
1052 movl LFwdSel-L__objc_msgForwardStret$pic_base(%edx),%ecx
1053 #else
1054 movl LFwdSel,%ecx
1055 #endif
1056 pushl %ecx
1057 pushl (self_stret+16)(%esp)
1058 call _objc_msgSend
1059 movl %ebp,%esp
1060 popl %ebp
1061 ret $4 // pop struct return address (#2995932)
1062
1063 // call error handler with unrecognized selector message
1064 .align 4, 0x90
1065 LMsgForwardStretError:
1066 #if defined(__DYNAMIC__)
1067 leal LFwdSel-L__objc_msgForwardStret$pic_base(%edx),%eax
1068 pushl %eax
1069 leal LUnkSelStr-L__objc_msgForwardStret$pic_base(%edx),%eax
1070 pushl %eax
1071 #else
1072 pushl $LFwdSel
1073 pushl $LUnkSelStr
1074 #endif
1075 pushl (self_stret+12)(%esp)
1076 CALL_EXTERN(___objc_error) // volatile, will not return
1077
1078 #endif /* defined (KERNEL) */
1079 END_ENTRY __objc_msgForward
1080