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