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