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