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