]>
Commit | Line | Data |
---|---|---|
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 | |
155 | LOCAL_SYMBOL = 0 | |
156 | EXTERNAL_SYMBOL = 1 | |
157 | ||
158 | .macro LOAD_STATIC_WORD | |
159 | ||
160 | #if defined(__DYNAMIC__) | |
b3962a83 A |
161 | call 1f |
162 | 1: 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 |
194 | 1: 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 |
293 | WORD_RETURN = 0 |
294 | STRUCT_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 |
298 | MSG_SEND = 0 // first argument is receiver, search the isa |
299 | MSG_SENDSUPER = 1 // first argument is objc_super, search the class | |
300 | CACHE_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 | 325 | LMsgSendProbeCache_$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 | 340 | LMsgSendCacheMiss_$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 | 363 | LMsgSendMaxMissProbeOK_$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 | 369 | LMsgSendMissHistoIndexSet_$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 | 376 | LMsgSendMissInstrumentDone_$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 | 424 | LMsgSendCacheHit_$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 | 447 | LMsgSendMaxHitProbeOK_$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 | 453 | LMsgSendHitHistoIndexSet_$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 | 460 | LMsgSendHitInstrumentDone_$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 |
553 | 1: movl $1, %eax |
554 | ret | |
1f20c7a7 A |
555 | |
556 | LGetMethodMiss: | |
557 | // cache miss, return nil | |
390d5862 A |
558 | xorl %eax, %eax // zero %eax |
559 | ret | |
1f20c7a7 A |
560 | |
561 | LGetMethodExit: | |
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 | |
585 | LGetImpMiss: | |
586 | // cache miss, return nil | |
390d5862 A |
587 | xorl %eax, %eax // zero %eax |
588 | ret | |
1f20c7a7 A |
589 | |
590 | LGetImpExit: | |
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 | 616 | LMsgSendReceiverOk: |
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 | |
623 | LMsgSendCacheMiss: | |
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 | 629 | LMsgSendNilSelf: |
b3962a83 A |
630 | call 1f // load new receiver |
631 | 1: 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 |
637 | LMsgSendReturnZero: |
638 | // %eax is already zero | |
639 | movl $0,%edx | |
13d88034 A |
640 | LMsgSendDone: |
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 |
649 | LMsgSendExit: |
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 | |
680 | LMsgSendSuperCacheMiss: | |
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 |
686 | LMsgSendSuperIgnored: | |
687 | movl super(%esp), %eax | |
688 | movl receiver(%eax), %eax | |
689 | ret | |
690 | ||
13d88034 A |
691 | LMsgSendSuperExit: |
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 |
727 | LMsgSendvArgLoop: |
728 | decl %ecx | |
729 | movl 0(%edx, %ecx, 4), %eax | |
730 | pushl %eax | |
731 | jg LMsgSendvArgLoop | |
732 | ||
733 | LMsgSendvArgsOK: | |
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 | 768 | LMsgSendFpretReceiverOk: |
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 | |
775 | LMsgSendFpretCacheMiss: | |
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 | |
781 | LMsgSendFpretNilSelf: | |
b3962a83 A |
782 | call 1f // load new receiver |
783 | 1: 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 |
789 | LMsgSendFpretReturnZero: |
790 | fldz | |
791 | LMsgSendFpretDone: | |
792 | ret | |
793 | ||
794 | LMsgSendFpretExit: | |
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 | ||
830 | LMsgSendvFpretArgLoop: | |
831 | decl %ecx | |
832 | movl 0(%edx, %ecx, 4), %eax | |
833 | pushl %eax | |
834 | jg LMsgSendvFpretArgLoop | |
835 | ||
836 | LMsgSendvFpretArgsOK: | |
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 | 875 | LMsgSendStretReceiverOk: |
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 | |
882 | LMsgSendStretCacheMiss: | |
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 | 888 | LMsgSendStretNilSelf: |
b3962a83 A |
889 | call 1f // load new receiver |
890 | 1: 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 | 896 | LMsgSendStretDone: |
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 | |
906 | LMsgSendStretExit: | |
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 | |
942 | LMsgSendSuperStretCacheMiss: | |
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 |
947 | LMsgSendSuperStretExit: |
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 |
988 | LMsgSendvStretArgLoop: |
989 | decl %ecx | |
990 | movl 0(%edx, %ecx, 4), %eax | |
991 | pushl %eax | |
992 | jg LMsgSendvStretArgLoop | |
993 | ||
994 | LMsgSendvStretArgsOK: | |
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 | 1025 | LUnkSelStr: .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 | |
1056 | L__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 | |
1064 | 1: | |
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 | 1091 | LMsgForwardError: |
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 | 1110 | L__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 | |
1118 | 1: | |
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 | 1145 | LMsgForwardStretError: |
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 |