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