1/*
2 * Copyright (c) 1999-2007 Apple Inc.  All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24#include <TargetConditionals.h>
25#if defined(__i386__)  &&  !TARGET_IPHONE_SIMULATOR
26
27/********************************************************************
28 ********************************************************************
29 **
30 **  objc-msg-i386.s - i386 code to support objc messaging.
31 **
32 ********************************************************************
33 ********************************************************************/
34
35// for kIgnore
36#include "objc-config.h"
37
38
39/********************************************************************
40* Data used by the ObjC runtime.
41*
42********************************************************************/
43
44.data
45// Substitute receiver for messages sent to nil (usually also nil)
46// id _objc_nilReceiver
47.align 4
48.private_extern __objc_nilReceiver
49__objc_nilReceiver:
50	.long   0
51
52// _objc_entryPoints and _objc_exitPoints are used by objc
53// to get the critical regions for which method caches
54// cannot be garbage collected.
55
56.private_extern _objc_entryPoints
57_objc_entryPoints:
58	.long	__cache_getImp
59	.long	__cache_getMethod
60	.long	_objc_msgSend
61	.long	_objc_msgSend_fpret
62	.long	_objc_msgSend_stret
63	.long	_objc_msgSendSuper
64	.long	_objc_msgSendSuper_stret
65	.long	0
66
67.private_extern _objc_exitPoints
68_objc_exitPoints:
69	.long	LGetImpExit
70	.long	LGetMethodExit
71	.long	LMsgSendExit
72	.long	LMsgSendFpretExit
73	.long	LMsgSendStretExit
74	.long	LMsgSendSuperExit
75	.long	LMsgSendSuperStretExit
76	.long	0
77
78
79/********************************************************************
80* List every exit insn from every messenger for debugger use.
81* Format:
82* (
83*   1 word instruction's address
84*   1 word type (ENTER or FAST_EXIT or SLOW_EXIT or NIL_EXIT)
85* )
86* 1 word zero
87*
88* ENTER is the start of a dispatcher
89* FAST_EXIT is method dispatch
90* SLOW_EXIT is uncached method lookup
91* NIL_EXIT is returning zero from a message sent to nil
92* These must match objc-gdb.h.
93********************************************************************/
94
95#define ENTER     1
96#define FAST_EXIT 2
97#define SLOW_EXIT 3
98#define NIL_EXIT  4
99
100.section __DATA,__objc_msg_break
101.globl _gdb_objc_messenger_breakpoints
102_gdb_objc_messenger_breakpoints:
103// contents populated by the macros below
104
105.macro MESSENGER_START
1064:
107	.section __DATA,__objc_msg_break
108	.long 4b
109	.long ENTER
110	.text
111.endmacro
112.macro MESSENGER_END_FAST
1134:
114	.section __DATA,__objc_msg_break
115	.long 4b
116	.long FAST_EXIT
117	.text
118.endmacro
119.macro MESSENGER_END_SLOW
1204:
121	.section __DATA,__objc_msg_break
122	.long 4b
123	.long SLOW_EXIT
124	.text
125.endmacro
126.macro MESSENGER_END_NIL
1274:
128	.section __DATA,__objc_msg_break
129	.long 4b
130	.long NIL_EXIT
131	.text
132.endmacro
133
134
135/********************************************************************
136 *
137 * Common offsets.
138 *
139 ********************************************************************/
140
141	self            = 4
142	super           = 4
143	selector        = 8
144	marg_size       = 12
145	marg_list       = 16
146	first_arg       = 12
147
148	struct_addr     = 4
149
150	self_stret      = 8
151	super_stret     = 8
152	selector_stret  = 12
153	marg_size_stret = 16
154	marg_list_stret = 20
155
156
157/********************************************************************
158 *
159 * Structure definitions.
160 *
161 ********************************************************************/
162
163// objc_super parameter to sendSuper
164	receiver        = 0
165	class           = 4
166
167// Selected field offsets in class structure
168	isa             = 0
169	cache           = 32
170
171// Method descriptor
172	method_name     = 0
173	method_imp      = 8
174
175// Cache header
176	mask            = 0
177	occupied        = 4
178	buckets         = 8		// variable length array
179
180#if defined(OBJC_INSTRUMENTED)
181// Cache instrumentation data, follows buckets
182	hitCount        = 0
183	hitProbes       = hitCount + 4
184	maxHitProbes    = hitProbes + 4
185	missCount       = maxHitProbes + 4
186	missProbes      = missCount + 4
187	maxMissProbes   = missProbes + 4
188	flushCount      = maxMissProbes + 4
189	flushedEntries  = flushCount + 4
190
191// Buckets in CacheHitHistogram and CacheMissHistogram
192	CACHE_HISTOGRAM_SIZE = 512
193#endif
194
195
196//////////////////////////////////////////////////////////////////////
197//
198// LOAD_STATIC_WORD	targetReg, symbolName, LOCAL_SYMBOL | EXTERNAL_SYMBOL
199//
200// Load the value of the named static data word.
201//
202// Takes: targetReg       - the register, other than r0, to load
203//        symbolName      - the name of the symbol
204//        LOCAL_SYMBOL    - symbol name used as-is
205//        EXTERNAL_SYMBOL - symbol name gets nonlazy treatment
206//
207// Eats: edx and targetReg
208//////////////////////////////////////////////////////////////////////
209
210// Values to specify whether the symbol is plain or nonlazy
211LOCAL_SYMBOL	= 0
212EXTERNAL_SYMBOL	= 1
213
214.macro	LOAD_STATIC_WORD
215
216#if defined(__DYNAMIC__)
217	call	1f
2181:	popl	%edx
219.if $2 == EXTERNAL_SYMBOL
220	movl	L$1-1b(%edx),$0
221	movl	0($0),$0
222.elseif $2 == LOCAL_SYMBOL
223	movl	$1-1b(%edx),$0
224.else
225	!!! Unknown symbol type !!!
226.endif
227#else
228	movl	$1,$0
229#endif
230
231.endmacro
232
233//////////////////////////////////////////////////////////////////////
234//
235// LEA_STATIC_DATA	targetReg, symbolName, LOCAL_SYMBOL | EXTERNAL_SYMBOL
236//
237// Load the address of the named static data.
238//
239// Takes: targetReg       - the register, other than edx, to load
240//        symbolName      - the name of the symbol
241//        LOCAL_SYMBOL    - symbol is local to this module
242//        EXTERNAL_SYMBOL - symbol is imported from another module
243//
244// Eats: edx and targetReg
245//////////////////////////////////////////////////////////////////////
246
247.macro	LEA_STATIC_DATA
248#if defined(__DYNAMIC__)
249	call	1f
2501:	popl	%edx
251.if $2 == EXTERNAL_SYMBOL
252	movl	L$1-1b(%edx),$0
253.elseif $2 == LOCAL_SYMBOL
254	leal	$1-1b(%edx),$0
255.else
256	!!! Unknown symbol type !!!
257.endif
258#else
259	leal	$1,$0
260#endif
261
262.endmacro
263
264//////////////////////////////////////////////////////////////////////
265//
266// ENTRY		functionName
267//
268// Assembly directives to begin an exported function.
269//
270// Takes: functionName - name of the exported function
271//////////////////////////////////////////////////////////////////////
272
273.macro ENTRY
274	.text
275	.globl	$0
276	.align	4, 0x90
277$0:
278.endmacro
279
280.macro STATIC_ENTRY
281	.text
282	.private_extern	$0
283	.align	4, 0x90
284$0:
285.endmacro
286
287//////////////////////////////////////////////////////////////////////
288//
289// END_ENTRY	functionName
290//
291// Assembly directives to end an exported function.  Just a placeholder,
292// a close-parenthesis for ENTRY, until it is needed for something.
293//
294// Takes: functionName - name of the exported function
295//////////////////////////////////////////////////////////////////////
296
297.macro END_ENTRY
298.endmacro
299
300//////////////////////////////////////////////////////////////////////
301//
302// CALL_MCOUNTER
303//
304// Calls mcount() profiling routine. Must be called immediately on
305// function entry, before any prologue executes.
306//
307//////////////////////////////////////////////////////////////////////
308
309.macro CALL_MCOUNTER
310#ifdef PROFILE
311	// Current stack contents: ret
312	pushl	%ebp
313	movl	%esp,%ebp
314	subl	$$8,%esp
315	// Current stack contents: ret, ebp, pad, pad
316	call	mcount
317	movl	%ebp,%esp
318	popl	%ebp
319#endif
320.endmacro
321
322
323/////////////////////////////////////////////////////////////////////
324//
325//
326// CacheLookup	WORD_RETURN | STRUCT_RETURN, MSG_SEND | MSG_SENDSUPER | CACHE_GET, cacheMissLabel
327//
328// Locate the implementation for a selector in a class method cache.
329//
330// Takes: WORD_RETURN	(first parameter is at sp+4)
331//        STRUCT_RETURN	(struct address is at sp+4, first parameter at sp+8)
332//        MSG_SEND	(first parameter is receiver)
333//        MSG_SENDSUPER	(first parameter is address of objc_super structure)
334//        CACHE_GET	(first parameter is class; return method triplet)
335//        selector in %ecx
336//        class to search in %edx
337//
338//	  cacheMissLabel = label to branch to iff method is not cached
339//
340// On exit: (found) MSG_SEND and MSG_SENDSUPER: return imp in eax
341//          (found) CACHE_GET: return method triplet in eax
342//          (not found) jumps to cacheMissLabel
343//
344/////////////////////////////////////////////////////////////////////
345
346
347// Values to specify to method lookup macros whether the return type of
348// the method is word or structure.
349WORD_RETURN   = 0
350STRUCT_RETURN = 1
351
352// Values to specify to method lookup macros whether the first argument
353// is an object/class reference or a 'objc_super' structure.
354MSG_SEND      = 0	// first argument is receiver, search the isa
355MSG_SENDSUPER = 1	// first argument is objc_super, search the class
356CACHE_GET     = 2	// first argument is class, search that class
357
358.macro	CacheLookup
359
360// load variables and save caller registers.
361
362	pushl	%edi			// save scratch register
363	movl	cache(%edx), %edi	// cache = class->cache
364	pushl	%esi			// save scratch register
365
366#if defined(OBJC_INSTRUMENTED)
367	pushl	%ebx			// save non-volatile register
368	pushl	%eax			// save cache pointer
369	xorl	%ebx, %ebx		// probeCount = 0
370#endif
371	movl	mask(%edi), %esi		// mask = cache->mask
372	movl	%ecx, %edx		// index = selector
373	shrl	$$2, %edx		// index = selector >> 2
374
375// search the receiver's cache
376// ecx = selector
377// edi = cache
378// esi = mask
379// edx = index
380// eax = method (soon)
381LMsgSendProbeCache_$0_$1_$2:
382#if defined(OBJC_INSTRUMENTED)
383	addl	$$1, %ebx			// probeCount += 1
384#endif
385	andl	%esi, %edx		// index &= mask
386	movl	buckets(%edi, %edx, 4), %eax	// meth = cache->buckets[index]
387
388	testl	%eax, %eax		// check for end of bucket
389	je	LMsgSendCacheMiss_$0_$1_$2	// go to cache miss code
390	cmpl	method_name(%eax), %ecx	// check for method name match
391	je	LMsgSendCacheHit_$0_$1_$2	// go handle cache hit
392	addl	$$1, %edx			// bump index ...
393	jmp	LMsgSendProbeCache_$0_$1_$2 // ... and loop
394
395// not found in cache: restore state and go to callers handler
396LMsgSendCacheMiss_$0_$1_$2:
397#if defined(OBJC_INSTRUMENTED)
398	popl	%edx			// retrieve cache pointer
399	movl	mask(%edx), %esi		// mask = cache->mask
400	testl	%esi, %esi		// a mask of zero is only for the...
401	je	LMsgSendMissInstrumentDone_$0_$1_$2	// ... emptyCache, do not record anything
402
403	// locate and update the CacheInstrumentation structure
404	addl	$$1, %esi			// entryCount = mask + 1
405	shll	$$2, %esi		// tableSize = entryCount * sizeof(entry)
406	addl	$buckets, %esi		// offset = buckets + tableSize
407	addl	%edx, %esi		// cacheData = &cache->buckets[mask+1]
408
409	movl	missCount(%esi), %edi	//
410	addl	$$1, %edi			//
411	movl	%edi, missCount(%esi)	// cacheData->missCount += 1
412	movl	missProbes(%esi), %edi	//
413	addl	%ebx, %edi		//
414	movl	%edi, missProbes(%esi)	// cacheData->missProbes += probeCount
415	movl	maxMissProbes(%esi), %edi// if (cacheData->maxMissProbes < probeCount)
416	cmpl	%ebx, %edi		//
417	jge	LMsgSendMaxMissProbeOK_$0_$1_$2	//
418	movl	%ebx, maxMissProbes(%esi)// cacheData->maxMissProbes = probeCount
419LMsgSendMaxMissProbeOK_$0_$1_$2:
420
421	// update cache miss probe histogram
422	cmpl	$CACHE_HISTOGRAM_SIZE, %ebx	// pin probeCount to max index
423	jl	LMsgSendMissHistoIndexSet_$0_$1_$2
424	movl	$(CACHE_HISTOGRAM_SIZE-1), %ebx
425LMsgSendMissHistoIndexSet_$0_$1_$2:
426	LEA_STATIC_DATA	%esi, _CacheMissHistogram, EXTERNAL_SYMBOL
427	shll	$$2, %ebx		// convert probeCount to histogram index
428	addl	%ebx, %esi		// calculate &CacheMissHistogram[probeCount<<2]
429	movl	0(%esi), %edi		// get current tally
430	addl	$$1, %edi			//
431	movl	%edi, 0(%esi)		// tally += 1
432LMsgSendMissInstrumentDone_$0_$1_$2:
433	popl	%ebx			// restore non-volatile register
434#endif
435
436.if $0 == WORD_RETURN			// Regular word return
437.if $1 == MSG_SEND			// MSG_SEND
438	popl	%esi			//  restore callers register
439	popl	%edi			//  restore callers register
440	movl	self(%esp), %edx	//  get messaged object
441	movl	isa(%edx), %eax		//  get objects class
442.elseif $1 == MSG_SENDSUPER		// MSG_SENDSUPER
443	// replace "super" arg with "receiver"
444	movl	super+8(%esp), %edi	//  get super structure
445	movl	receiver(%edi), %edx	//  get messaged object
446	movl	%edx, super+8(%esp)	//  make it the first argument
447	movl	class(%edi), %eax	//  get messaged class
448	popl	%esi			//  restore callers register
449	popl	%edi			//  restore callers register
450.else					// CACHE_GET
451	popl	%esi			//  restore callers register
452	popl	%edi			//  restore callers register
453.endif
454.else					// Struct return
455.if $1 == MSG_SEND			// MSG_SEND (stret)
456	popl	%esi			//  restore callers register
457	popl	%edi			//  restore callers register
458	movl	self_stret(%esp), %edx	//  get messaged object
459	movl	isa(%edx), %eax		//  get objects class
460.elseif $1 == MSG_SENDSUPER		// MSG_SENDSUPER (stret)
461	// replace "super" arg with "receiver"
462	movl	super_stret+8(%esp), %edi//  get super structure
463	movl	receiver(%edi), %edx	//  get messaged object
464	movl	%edx, super_stret+8(%esp)//  make it the first argument
465	movl	class(%edi), %eax	//  get messaged class
466	popl	%esi			//  restore callers register
467	popl	%edi			//  restore callers register
468.else					// CACHE_GET
469	!! This should not happen.
470.endif
471.endif
472
473					// edx = receiver
474					// ecx = selector
475					// eax = class
476	jmp	$2			// go to callers handler
477
478// eax points to matching cache entry
479	.align	4, 0x90
480LMsgSendCacheHit_$0_$1_$2:
481#if defined(OBJC_INSTRUMENTED)
482	popl	%edx			// retrieve cache pointer
483	movl	mask(%edx), %esi		// mask = cache->mask
484	testl	%esi, %esi		// a mask of zero is only for the...
485	je	LMsgSendHitInstrumentDone_$0_$1_$2	// ... emptyCache, do not record anything
486
487	// locate and update the CacheInstrumentation structure
488	addl	$$1, %esi			// entryCount = mask + 1
489	shll	$$2, %esi		// tableSize = entryCount * sizeof(entry)
490	addl	$buckets, %esi		// offset = buckets + tableSize
491	addl	%edx, %esi		// cacheData = &cache->buckets[mask+1]
492
493	movl	hitCount(%esi), %edi
494	addl	$$1, %edi
495	movl	%edi, hitCount(%esi)	// cacheData->hitCount += 1
496	movl	hitProbes(%esi), %edi
497	addl	%ebx, %edi
498	movl	%edi, hitProbes(%esi)	// cacheData->hitProbes += probeCount
499	movl	maxHitProbes(%esi), %edi// if (cacheData->maxHitProbes < probeCount)
500	cmpl	%ebx, %edi
501	jge	LMsgSendMaxHitProbeOK_$0_$1_$2
502	movl	%ebx, maxHitProbes(%esi)// cacheData->maxHitProbes = probeCount
503LMsgSendMaxHitProbeOK_$0_$1_$2:
504
505	// update cache hit probe histogram
506	cmpl	$CACHE_HISTOGRAM_SIZE, %ebx	// pin probeCount to max index
507	jl	LMsgSendHitHistoIndexSet_$0_$1_$2
508	movl	$(CACHE_HISTOGRAM_SIZE-1), %ebx
509LMsgSendHitHistoIndexSet_$0_$1_$2:
510	LEA_STATIC_DATA	%esi, _CacheHitHistogram, EXTERNAL_SYMBOL
511	shll	$$2, %ebx		// convert probeCount to histogram index
512	addl	%ebx, %esi		// calculate &CacheHitHistogram[probeCount<<2]
513	movl	0(%esi), %edi		// get current tally
514	addl	$$1, %edi			//
515	movl	%edi, 0(%esi)		// tally += 1
516LMsgSendHitInstrumentDone_$0_$1_$2:
517	popl	%ebx			// restore non-volatile register
518#endif
519
520// load implementation address, restore state, and we're done
521.if $1 == CACHE_GET
522	// method triplet is already in eax
523.else
524	movl	method_imp(%eax), %eax	// imp = method->method_imp
525.endif
526
527.if $0 == WORD_RETURN			// Regular word return
528.if $1 == MSG_SENDSUPER			// MSG_SENDSUPER
529	// replace "super" arg with "self"
530	movl	super+8(%esp), %edi
531	movl	receiver(%edi), %esi
532	movl	%esi, super+8(%esp)
533.endif
534.else					// Struct return
535.if $1 == MSG_SENDSUPER			// MSG_SENDSUPER (stret)
536	// replace "super" arg with "self"
537	movl	super_stret+8(%esp), %edi
538	movl	receiver(%edi), %esi
539	movl	%esi, super_stret+8(%esp)
540.endif
541.endif
542
543	// restore caller registers
544	popl	%esi
545	popl	%edi
546.endmacro
547
548
549/////////////////////////////////////////////////////////////////////
550//
551// MethodTableLookup WORD_RETURN | STRUCT_RETURN, MSG_SEND | MSG_SENDSUPER
552//
553// Takes: WORD_RETURN	(first parameter is at sp+4)
554//	  STRUCT_RETURN	(struct address is at sp+4, first parameter at sp+8)
555// 	  MSG_SEND	(first parameter is receiver)
556//	  MSG_SENDSUPER	(first parameter is address of objc_super structure)
557//
558//	  edx = receiver
559// 	  ecx = selector
560// 	  eax = class
561//        (all set by CacheLookup's miss case)
562//
563// Stack must be at 0xXXXXXXXc on entrance.
564//
565// On exit:  esp unchanged
566//           imp in eax
567//
568/////////////////////////////////////////////////////////////////////
569
570.macro MethodTableLookup
571	MESSENGER_END_SLOW
572	// stack is already aligned
573	pushl	%eax			// class
574	pushl	%ecx			// selector
575	pushl	%edx			// receiver
576	call	__class_lookupMethodAndLoadCache3
577	addl    $$12, %esp		// pop parameters
578.endmacro
579
580
581/********************************************************************
582 * Method _cache_getMethod(Class cls, SEL sel, IMP msgForward_internal_imp)
583 *
584 * If found, returns method triplet pointer.
585 * If not found, returns NULL.
586 *
587 * NOTE: _cache_getMethod never returns any cache entry whose implementation
588 * is _objc_msgForward_impcache. It returns 1 instead. This prevents thread-
589 * safety and memory management bugs in _class_lookupMethodAndLoadCache.
590 * See _class_lookupMethodAndLoadCache for details.
591 *
592 * _objc_msgForward_impcache is passed as a parameter because it's more
593 * efficient to do the (PIC) lookup once in the caller than repeatedly here.
594 ********************************************************************/
595
596	STATIC_ENTRY __cache_getMethod
597
598// load the class and selector
599	movl	selector(%esp), %ecx
600	movl	self(%esp), %edx
601
602// do lookup
603	CacheLookup WORD_RETURN, CACHE_GET, LGetMethodMiss
604
605// cache hit, method triplet in %eax
606	movl    first_arg(%esp), %ecx   // check for _objc_msgForward_impcache
607	cmpl    method_imp(%eax), %ecx  // if (imp==_objc_msgForward_impcache)
608	je      1f                      //     return (Method)1
609	ret                             // else return method triplet address
6101:	movl	$1, %eax
611	ret
612
613LGetMethodMiss:
614// cache miss, return nil
615	xorl    %eax, %eax      // zero %eax
616	ret
617
618LGetMethodExit:
619	END_ENTRY __cache_getMethod
620
621
622/********************************************************************
623 * IMP _cache_getImp(Class cls, SEL sel)
624 *
625 * If found, returns method implementation.
626 * If not found, returns NULL.
627 ********************************************************************/
628
629	STATIC_ENTRY __cache_getImp
630
631// load the class and selector
632	movl    selector(%esp), %ecx
633	movl	self(%esp), %edx
634
635// do lookup
636	CacheLookup WORD_RETURN, CACHE_GET, LGetImpMiss
637
638// cache hit, method triplet in %eax
639	movl    method_imp(%eax), %eax  // return method imp
640	ret
641
642LGetImpMiss:
643// cache miss, return nil
644	xorl    %eax, %eax      // zero %eax
645	ret
646
647LGetImpExit:
648	END_ENTRY __cache_getImp
649
650
651/********************************************************************
652 *
653 * id objc_msgSend(id self, SEL	_cmd,...);
654 *
655 ********************************************************************/
656
657	ENTRY	_objc_msgSend
658	MESSENGER_START
659	CALL_MCOUNTER
660
661// load receiver and selector
662	movl    selector(%esp), %ecx
663	movl	self(%esp), %eax
664
665// check whether selector is ignored
666	cmpl    $ kIgnore, %ecx
667	je      LMsgSendDone		// return self from %eax
668
669// check whether receiver is nil
670	testl	%eax, %eax
671	je	LMsgSendNilSelf
672
673// receiver (in %eax) is non-nil: search the cache
674LMsgSendReceiverOk:
675	movl	isa(%eax), %edx		// class = self->isa
676	CacheLookup WORD_RETURN, MSG_SEND, LMsgSendCacheMiss
677	xor	%edx, %edx		// set nonstret for msgForward_internal
678	MESSENGER_END_FAST
679	jmp	*%eax
680
681// cache miss: go search the method lists
682LMsgSendCacheMiss:
683	MethodTableLookup WORD_RETURN, MSG_SEND
684	xor	%edx, %edx		// set nonstret for msgForward_internal
685	jmp	*%eax			// goto *imp
686
687// message sent to nil: redirect to nil receiver, if any
688LMsgSendNilSelf:
689	call	1f			// load new receiver
6901:	popl	%edx
691	movl	__objc_nilReceiver-1b(%edx),%eax
692	testl	%eax, %eax		// return nil if no new receiver
693	je	LMsgSendReturnZero
694	movl	%eax, self(%esp)	// send to new receiver
695	jmp	LMsgSendReceiverOk	// receiver must be in %eax
696LMsgSendReturnZero:
697	// %eax is already zero
698	movl	$0,%edx
699LMsgSendDone:
700	MESSENGER_END_NIL
701	ret
702
703// guaranteed non-nil entry point (disabled for now)
704// .globl _objc_msgSendNonNil
705// _objc_msgSendNonNil:
706// 	movl	self(%esp), %eax
707// 	jmp     LMsgSendReceiverOk
708
709LMsgSendExit:
710	END_ENTRY	_objc_msgSend
711
712/********************************************************************
713 *
714 * id objc_msgSendSuper(struct objc_super *super, SEL _cmd,...);
715 *
716 * struct objc_super {
717 *		id	receiver;
718 *		Class	class;
719 * };
720 ********************************************************************/
721
722	ENTRY	_objc_msgSendSuper
723	MESSENGER_START
724	CALL_MCOUNTER
725
726// load selector and class to search
727	movl	super(%esp), %eax	// struct objc_super
728	movl    selector(%esp), %ecx
729	movl	class(%eax), %edx	// struct objc_super->class
730
731// check whether selector is ignored
732	cmpl    $ kIgnore, %ecx
733	je      LMsgSendSuperIgnored	// return self from %eax
734
735// search the cache (class in %edx)
736	CacheLookup WORD_RETURN, MSG_SENDSUPER, LMsgSendSuperCacheMiss
737	xor	%edx, %edx		// set nonstret for msgForward_internal
738	MESSENGER_END_FAST
739	jmp	*%eax			// goto *imp
740
741// cache miss: go search the method lists
742LMsgSendSuperCacheMiss:
743	MethodTableLookup WORD_RETURN, MSG_SENDSUPER
744	xor	%edx, %edx		// set nonstret for msgForward_internal
745	jmp	*%eax			// goto *imp
746
747// ignored selector: return self
748LMsgSendSuperIgnored:
749	movl	super(%esp), %eax
750	movl    receiver(%eax), %eax
751	MESSENGER_END_NIL
752	ret
753
754LMsgSendSuperExit:
755	END_ENTRY	_objc_msgSendSuper
756
757/********************************************************************
758 * id objc_msgSendv(id self, SEL _cmd, unsigned size, marg_list frame);
759 *
760 * On entry:
761 *		(sp+4)  is the message receiver,
762 *		(sp+8)	is the selector,
763 *		(sp+12) is the size of the marg_list, in bytes,
764 *		(sp+16) is the address of the marg_list
765 *
766 ********************************************************************/
767
768	ENTRY	_objc_msgSendv
769
770#if defined(KERNEL)
771	trap				// _objc_msgSendv is not for the kernel
772#else
773	pushl	%ebp
774	movl	%esp, %ebp
775	// stack is currently aligned assuming no extra arguments
776	movl	(marg_list+4)(%ebp), %edx
777	addl	$8, %edx			// skip self & selector
778	movl	(marg_size+4)(%ebp), %ecx
779	subl    $8, %ecx			// skip self & selector
780	shrl	$2, %ecx
781	je      LMsgSendvArgsOK
782
783	// %esp = %esp - (16 - ((numVariableArguments & 3) << 2))
784	movl    %ecx, %eax			// 16-byte align stack
785	andl    $3, %eax
786	shll    $2, %eax
787	subl    $16, %esp
788	addl    %eax, %esp
789
790LMsgSendvArgLoop:
791	decl	%ecx
792	movl	0(%edx, %ecx, 4), %eax
793	pushl	%eax
794	jg	LMsgSendvArgLoop
795
796LMsgSendvArgsOK:
797	movl	(selector+4)(%ebp), %ecx
798	pushl	%ecx
799	movl	(self+4)(%ebp),%ecx
800	pushl	%ecx
801	call	_objc_msgSend
802	movl	%ebp,%esp
803	popl	%ebp
804
805	ret
806#endif
807	END_ENTRY	_objc_msgSendv
808
809/********************************************************************
810 *
811 * double objc_msgSend_fpret(id self, SEL _cmd,...);
812 *
813 ********************************************************************/
814
815	ENTRY	_objc_msgSend_fpret
816	MESSENGER_START
817	CALL_MCOUNTER
818
819// load receiver and selector
820	movl    selector(%esp), %ecx
821	movl	self(%esp), %eax
822
823// check whether selector is ignored
824	cmpl    $ kIgnore, %ecx
825	je      LMsgSendFpretDone	// return self from %eax
826
827// check whether receiver is nil
828	testl	%eax, %eax
829	je	LMsgSendFpretNilSelf
830
831// receiver (in %eax) is non-nil: search the cache
832LMsgSendFpretReceiverOk:
833	movl	isa(%eax), %edx		// class = self->isa
834	CacheLookup WORD_RETURN, MSG_SEND, LMsgSendFpretCacheMiss
835	xor	%edx, %edx		// set nonstret for msgForward_internal
836	MESSENGER_END_FAST
837	jmp	*%eax			// goto *imp
838
839// cache miss: go search the method lists
840LMsgSendFpretCacheMiss:
841	MethodTableLookup WORD_RETURN, MSG_SEND
842	xor	%edx, %edx		// set nonstret for msgForward_internal
843	jmp	*%eax			// goto *imp
844
845// message sent to nil: redirect to nil receiver, if any
846LMsgSendFpretNilSelf:
847	call	1f			// load new receiver
8481:	popl	%edx
849	movl	__objc_nilReceiver-1b(%edx),%eax
850	testl	%eax, %eax		// return zero if no new receiver
851	je	LMsgSendFpretReturnZero
852	movl	%eax, self(%esp)	// send to new receiver
853	jmp	LMsgSendFpretReceiverOk	// receiver must be in %eax
854LMsgSendFpretReturnZero:
855	fldz
856LMsgSendFpretDone:
857	MESSENGER_END_NIL
858	ret
859
860LMsgSendFpretExit:
861	END_ENTRY	_objc_msgSend_fpret
862
863/********************************************************************
864 * double objc_msgSendv_fpret(id self, SEL _cmd, unsigned size, marg_list frame);
865 *
866 * On entry:
867 *		(sp+4)  is the message receiver,
868 *		(sp+8)	is the selector,
869 *		(sp+12) is the size of the marg_list, in bytes,
870 *		(sp+16) is the address of the marg_list
871 *
872 ********************************************************************/
873
874	ENTRY	_objc_msgSendv_fpret
875
876#if defined(KERNEL)
877	trap				// _objc_msgSendv is not for the kernel
878#else
879	pushl	%ebp
880	movl	%esp, %ebp
881	// stack is currently aligned assuming no extra arguments
882	movl	(marg_list+4)(%ebp), %edx
883	addl	$8, %edx			// skip self & selector
884	movl	(marg_size+4)(%ebp), %ecx
885	subl    $8, %ecx			// skip self & selector
886	shrl	$2, %ecx
887	je      LMsgSendvFpretArgsOK
888
889	// %esp = %esp - (16 - ((numVariableArguments & 3) << 2))
890	movl    %ecx, %eax			// 16-byte align stack
891	andl    $3, %eax
892	shll    $2, %eax
893	subl    $16, %esp
894	addl    %eax, %esp
895
896LMsgSendvFpretArgLoop:
897	decl	%ecx
898	movl	0(%edx, %ecx, 4), %eax
899	pushl	%eax
900	jg	LMsgSendvFpretArgLoop
901
902LMsgSendvFpretArgsOK:
903	movl	(selector+4)(%ebp), %ecx
904	pushl	%ecx
905	movl	(self+4)(%ebp),%ecx
906	pushl	%ecx
907	call	_objc_msgSend_fpret
908	movl	%ebp,%esp
909	popl	%ebp
910
911	ret
912#endif
913	END_ENTRY	_objc_msgSendv_fpret
914
915/********************************************************************
916 *
917 * void	objc_msgSend_stret(void *st_addr	, id self, SEL _cmd, ...);
918 *
919 *
920 * objc_msgSend_stret is the struct-return form of msgSend.
921 * The ABI calls for (sp+4) to be used as the address of the structure
922 * being returned, with the parameters in the succeeding locations.
923 *
924 * On entry:	(sp+4)is the address where the structure is returned,
925 *		(sp+8) is the message receiver,
926 *		(sp+12) is the selector
927 ********************************************************************/
928
929	ENTRY	_objc_msgSend_stret
930	MESSENGER_START
931	CALL_MCOUNTER
932
933// load receiver and selector
934	movl	self_stret(%esp), %eax
935	movl	(selector_stret)(%esp), %ecx
936
937// check whether receiver is nil
938	testl	%eax, %eax
939	je	LMsgSendStretNilSelf
940
941// receiver (in %eax) is non-nil: search the cache
942LMsgSendStretReceiverOk:
943	movl	isa(%eax), %edx		//   class = self->isa
944	CacheLookup STRUCT_RETURN, MSG_SEND, LMsgSendStretCacheMiss
945	movl	$1, %edx		// set stret for objc_msgForward
946	MESSENGER_END_FAST
947	jmp	*%eax			// goto *imp
948
949// cache miss: go search the method lists
950LMsgSendStretCacheMiss:
951	MethodTableLookup STRUCT_RETURN, MSG_SEND
952	movl	$1, %edx		// set stret for objc_msgForward
953	jmp	*%eax			// goto *imp
954
955// message sent to nil: redirect to nil receiver, if any
956LMsgSendStretNilSelf:
957	call	1f			// load new receiver
9581:	popl	%edx
959	movl	__objc_nilReceiver-1b(%edx),%eax
960	testl	%eax, %eax		// return nil if no new receiver
961	je	LMsgSendStretDone
962	movl	%eax, self_stret(%esp)	// send to new receiver
963	jmp	LMsgSendStretReceiverOk	// receiver must be in %eax
964LMsgSendStretDone:
965	MESSENGER_END_NIL
966	ret	$4			// pop struct return address (#2995932)
967
968// guaranteed non-nil entry point (disabled for now)
969// .globl _objc_msgSendNonNil_stret
970// _objc_msgSendNonNil_stret:
971// 	CALL_MCOUNTER
972// 	movl	self_stret(%esp), %eax
973// 	jmp     LMsgSendStretReceiverOk
974
975LMsgSendStretExit:
976	END_ENTRY	_objc_msgSend_stret
977
978/********************************************************************
979 *
980 * void objc_msgSendSuper_stret(void *st_addr, struct objc_super *super, SEL _cmd, ...);
981 *
982 * struct objc_super {
983 *		id	receiver;
984 *		Class	class;
985 * };
986 *
987 * objc_msgSendSuper_stret is the struct-return form of msgSendSuper.
988 * The ABI calls for (sp+4) to be used as the address of the structure
989 * being returned, with the parameters in the succeeding registers.
990 *
991 * On entry:	(sp+4)is the address where the structure is returned,
992 *		(sp+8) is the address of the objc_super structure,
993 *		(sp+12) is the selector
994 *
995 ********************************************************************/
996
997	ENTRY	_objc_msgSendSuper_stret
998	MESSENGER_START
999	CALL_MCOUNTER
1000
1001// load selector and class to search
1002	movl	super_stret(%esp), %eax	// struct objc_super
1003	movl	(selector_stret)(%esp), %ecx	//   get selector
1004	movl	class(%eax), %edx	// struct objc_super->class
1005
1006// search the cache (class in %edx)
1007	CacheLookup STRUCT_RETURN, MSG_SENDSUPER, LMsgSendSuperStretCacheMiss
1008	movl	$1, %edx		// set stret for objc_msgForward
1009	MESSENGER_END_FAST
1010	jmp	*%eax			// goto *imp
1011
1012// cache miss: go search the method lists
1013LMsgSendSuperStretCacheMiss:
1014	MethodTableLookup STRUCT_RETURN, MSG_SENDSUPER
1015	movl	$1, %edx		// set stret for objc_msgForward
1016	jmp	*%eax			// goto *imp
1017
1018LMsgSendSuperStretExit:
1019	END_ENTRY	_objc_msgSendSuper_stret
1020
1021
1022/********************************************************************
1023 * void objc_msgSendv_stret(void *st_addr, id self, SEL _cmd, unsigned size, marg_list frame);
1024 *
1025 * objc_msgSendv_stret is the struct-return form of msgSendv.
1026 * This function does not use the struct-return ABI; instead, the
1027 * structure return address is passed as a normal parameter.
1028 *
1029 * On entry:	(sp+4)  is the address in which the returned struct is put,
1030 *		(sp+8)  is the message receiver,
1031 *		(sp+12) is the selector,
1032 *		(sp+16) is the size of the marg_list, in bytes,
1033 *		(sp+20) is the address of the marg_list
1034 *
1035 ********************************************************************/
1036
1037	ENTRY	_objc_msgSendv_stret
1038
1039#if defined(KERNEL)
1040	trap				// _objc_msgSendv_stret is not for the kernel
1041#else
1042	pushl	%ebp
1043	movl	%esp, %ebp
1044	subl    $12, %esp	// align stack assuming no extra arguments
1045	movl	(marg_list_stret+4)(%ebp), %edx
1046	addl	$8, %edx			// skip self & selector
1047	movl	(marg_size_stret+4)(%ebp), %ecx
1048	subl	$5, %ecx			// skip self & selector
1049	shrl	$2, %ecx
1050	jle	LMsgSendvStretArgsOK
1051
1052	// %esp = %esp - (16 - ((numVariableArguments & 3) << 2))
1053	movl    %ecx, %eax			// 16-byte align stack
1054	andl    $3, %eax
1055	shll    $2, %eax
1056	subl    $16, %esp
1057	addl    %eax, %esp
1058
1059LMsgSendvStretArgLoop:
1060	decl	%ecx
1061	movl	0(%edx, %ecx, 4), %eax
1062	pushl	%eax
1063	jg	LMsgSendvStretArgLoop
1064
1065LMsgSendvStretArgsOK:
1066	movl	(selector_stret+4)(%ebp), %ecx
1067	pushl	%ecx
1068	movl	(self_stret+4)(%ebp),%ecx
1069	pushl	%ecx
1070	movl	(struct_addr+4)(%ebp),%ecx
1071	pushl	%ecx
1072	call	_objc_msgSend_stret
1073	movl	%ebp,%esp
1074	popl	%ebp
1075
1076	ret
1077#endif
1078	END_ENTRY	_objc_msgSendv_stret
1079
1080
1081/********************************************************************
1082 *
1083 * id _objc_msgForward(id self, SEL _cmd,...);
1084 *
1085 ********************************************************************/
1086
1087// _FwdSel is @selector(forward::), set up in map_images().
1088// ALWAYS dereference _FwdSel to get to "forward::" !!
1089	.data
1090	.align 2
1091	.private_extern _FwdSel
1092_FwdSel: .long 0
1093
1094	.cstring
1095	.align 2
1096LUnkSelStr: .ascii "Does not recognize selector %s (while forwarding %s)\0"
1097
1098	.data
1099	.align 2
1100	.private_extern __objc_forward_handler
1101__objc_forward_handler:	.long 0
1102
1103	.data
1104	.align 2
1105	.private_extern __objc_forward_stret_handler
1106__objc_forward_stret_handler:	.long 0
1107
1108	STATIC_ENTRY	__objc_msgForward_impcache
1109	// Method cache version
1110
1111	// THIS IS NOT A CALLABLE C FUNCTION
1112	// Out-of-band register %edx is nonzero for stret, zero otherwise
1113
1114	MESSENGER_START
1115	nop
1116	MESSENGER_END_SLOW
1117
1118	// Check return type (stret or not)
1119	testl	%edx, %edx
1120	jnz	__objc_msgForward_stret
1121	jmp	__objc_msgForward
1122
1123	END_ENTRY	_objc_msgForward_impcache
1124
1125
1126	ENTRY	__objc_msgForward
1127	// Non-struct return version
1128
1129	// Get PIC base into %edx
1130	call	L__objc_msgForward$pic_base
1131L__objc_msgForward$pic_base:
1132	popl	%edx
1133
1134	// Call user handler, if any
1135	movl	__objc_forward_handler-L__objc_msgForward$pic_base(%edx),%ecx
1136	testl	%ecx, %ecx		// if not NULL
1137	je	1f			//   skip to default handler
1138	jmp	*%ecx			// call __objc_forward_handler
11391:
1140	// No user handler
1141	// Push stack frame
1142	pushl   %ebp
1143	movl    %esp, %ebp
1144
1145	// Die if forwarding "forward::"
1146	movl    (selector+4)(%ebp), %eax
1147	movl	_FwdSel-L__objc_msgForward$pic_base(%edx),%ecx
1148	cmpl	%ecx, %eax
1149	je	LMsgForwardError
1150
1151	// Call [receiver forward:sel :margs]
1152	subl    $8, %esp		// 16-byte align the stack
1153	leal    (self+4)(%ebp), %ecx
1154	pushl	%ecx			// &margs
1155	pushl	%eax			// sel
1156	movl	_FwdSel-L__objc_msgForward$pic_base(%edx),%ecx
1157	pushl	%ecx			// forward::
1158	pushl   (self+4)(%ebp)		// receiver
1159
1160	call	_objc_msgSend
1161
1162	movl    %ebp, %esp
1163	popl    %ebp
1164	ret
1165
1166LMsgForwardError:
1167	// Call __objc_error(receiver, "unknown selector %s %s", "forward::", forwardedSel)
1168	subl    $8, %esp		// 16-byte align the stack
1169	pushl	(selector+4+4)(%ebp)	// the forwarded selector
1170	movl	_FwdSel-L__objc_msgForward$pic_base(%edx),%eax
1171	pushl 	%eax
1172	leal	LUnkSelStr-L__objc_msgForward$pic_base(%edx),%eax
1173	pushl 	%eax
1174	pushl   (self+4)(%ebp)
1175	call	___objc_error	// never returns
1176
1177	END_ENTRY	__objc_msgForward
1178
1179
1180	ENTRY	__objc_msgForward_stret
1181	// Struct return version
1182
1183	// Get PIC base into %edx
1184	call	L__objc_msgForwardStret$pic_base
1185L__objc_msgForwardStret$pic_base:
1186	popl	%edx
1187
1188	// Call user handler, if any
1189	movl	__objc_forward_stret_handler-L__objc_msgForwardStret$pic_base(%edx), %ecx
1190	testl	%ecx, %ecx		// if not NULL
1191	je	1f			//   skip to default handler
1192	jmp	*%ecx			// call __objc_forward_stret_handler
11931:
1194	// No user handler
1195	// Push stack frame
1196	pushl	%ebp
1197	movl	%esp, %ebp
1198
1199	// Die if forwarding "forward::"
1200	movl	(selector_stret+4)(%ebp), %eax
1201	movl	_FwdSel-L__objc_msgForwardStret$pic_base(%edx), %ecx
1202	cmpl	%ecx, %eax
1203	je	LMsgForwardStretError
1204
1205	// Call [receiver forward:sel :margs]
1206	subl    $8, %esp		// 16-byte align the stack
1207	leal    (self_stret+4)(%ebp), %ecx
1208	pushl	%ecx			// &margs
1209	pushl	%eax			// sel
1210	movl	_FwdSel-L__objc_msgForwardStret$pic_base(%edx),%ecx
1211	pushl	%ecx			// forward::
1212	pushl   (self_stret+4)(%ebp)	// receiver
1213
1214	call	_objc_msgSend
1215
1216	movl    %ebp, %esp
1217	popl    %ebp
1218	ret	$4			// pop struct return address (#2995932)
1219
1220LMsgForwardStretError:
1221	// Call __objc_error(receiver, "unknown selector %s %s", "forward::", forwardedSelector)
1222	subl    $8, %esp		// 16-byte align the stack
1223	pushl	(selector_stret+4+4)(%ebp)	// the forwarded selector
1224	leal	_FwdSel-L__objc_msgForwardStret$pic_base(%edx),%eax
1225	pushl 	%eax
1226	leal	LUnkSelStr-L__objc_msgForwardStret$pic_base(%edx),%eax
1227	pushl 	%eax
1228	pushl   (self_stret+4)(%ebp)
1229	call	___objc_error	// never returns
1230
1231	END_ENTRY	__objc_msgForward_stret
1232
1233
1234	ENTRY _method_invoke
1235
1236	movl	selector(%esp), %ecx
1237	movl	method_name(%ecx), %edx
1238	movl	method_imp(%ecx), %eax
1239	movl	%edx, selector(%esp)
1240	jmp	*%eax
1241
1242	END_ENTRY _method_invoke
1243
1244
1245	ENTRY _method_invoke_stret
1246
1247	movl	selector_stret(%esp), %ecx
1248	movl	method_name(%ecx), %edx
1249	movl	method_imp(%ecx), %eax
1250	movl	%edx, selector_stret(%esp)
1251	jmp	*%eax
1252
1253	END_ENTRY _method_invoke_stret
1254
1255
1256	STATIC_ENTRY __objc_ignored_method
1257
1258	movl	self(%esp), %eax
1259	ret
1260
1261	END_ENTRY __objc_ignored_method
1262
1263
1264.section __DATA,__objc_msg_break
1265.long 0
1266.long 0
1267
1268#endif
1269