]> git.saurik.com Git - apple/objc4.git/blob - runtime/Messengers.subproj/objc-msg-win32.m
objc4-493.9.tar.gz
[apple/objc4.git] / runtime / Messengers.subproj / objc-msg-win32.m
1 #include "objc-private.h"
2
3 // out-of-band parameter to objc_msgForward
4 #define kFwdMsgSend 1
5 #define kFwdMsgSendStret 0
6
7 // objc_msgSend parameters
8 #define SELF 8[ebp]
9 #define SUPER 8[ebp]
10 #define SELECTOR 12[ebp]
11 #define FIRST_ARG 16[ebp]
12
13 // objc_msgSend_stret parameters
14 #define STRUCT_ADDR 8[ebp]
15 #define SELF_STRET 12[ebp]
16 #define SUPER_STRET 12[ebp]
17 #define SELECTOR_STRET 16[ebp]
18
19 // objc_super parameter to sendSuper
20 #define super_receiver 0
21 #define super_class 4
22
23 // struct objc_class fields
24 #define isa 0
25 #define cache 32
26
27 // struct objc_method fields
28 #define method_name 0
29 #define method_imp 8
30
31 // struct objc_cache fields
32 #define mask 0
33 #define occupied 4
34 #define buckets 8
35
36 void *_objc_forward_handler = NULL;
37 void *_objc_forward_stret_handler = NULL;
38
39 __declspec(naked) Method _cache_getMethod(Class cls, SEL sel, IMP objc_msgForward_imp)
40 {
41 __asm {
42 push ebp
43 mov ebp, esp
44
45 mov ecx, SELECTOR
46 mov edx, SELF
47
48 // CacheLookup WORD_RETURN, CACHE_GET
49 push edi
50 mov edi, cache[edx]
51
52 push esi
53 mov esi, mask[edi]
54 mov edx, ecx
55 shr edx, 2
56 SCAN:
57 and edx, esi
58 mov eax, buckets[edi][edx*4]
59 test eax, eax
60 je MISS
61 cmp ecx, method_name[eax]
62 je HIT
63 add edx, 1
64 jmp SCAN
65
66 MISS:
67 xor eax, eax
68 pop esi
69 pop edi
70 leave
71 ret
72
73 HIT:
74 mov ecx, FIRST_ARG
75 cmp ecx, method_imp[eax]
76 je MISS
77 pop esi
78 pop edi
79 leave
80 ret
81 }
82 }
83
84 __declspec(naked) IMP _cache_getImp(Class cls, SEL sel)
85 {
86 __asm {
87 push ebp
88 mov ebp, esp
89
90 mov ecx, SELECTOR
91 mov edx, SELF
92
93 // CacheLookup WORD_RETURN, CACHE_GET
94 push edi
95 mov edi, cache[edx]
96
97 push esi
98 mov esi, mask[edi]
99 mov edx, ecx
100 shr edx, 2
101 SCAN:
102 and edx, esi
103 mov eax, buckets[edi][edx*4]
104 test eax, eax
105 je MISS
106 cmp ecx, method_name[eax]
107 je HIT
108 add edx, 1
109 jmp SCAN
110
111 MISS:
112 pop esi
113 pop edi
114 xor eax, eax
115 leave
116 ret
117
118 HIT:
119 pop esi
120 pop edi
121 mov eax, method_imp[eax]
122 leave
123 ret
124 }
125 }
126
127
128 OBJC_EXPORT __declspec(naked) id objc_msgSend(id a, SEL b, ...)
129 {
130 __asm {
131 push ebp
132 mov ebp, esp
133
134 // load receiver and selector
135 mov ecx, SELECTOR
136 mov eax, SELF
137
138 #if SUPPORT_GC
139 // check whether selector is ignored
140 #error oops
141 #endif
142
143 // check whether receiver is nil
144 test eax, eax
145 je NIL
146
147 // receiver (in eax) is non-nil: search the cache
148 mov edx, isa[eax]
149
150 // CacheLookup WORD_RETURN, MSG_SEND
151 push edi
152 mov edi, cache[edx]
153 push esi
154 mov esi, mask[edi]
155 mov edx, ecx
156 shr edx, 2
157 SCAN:
158 and edx, esi
159 mov eax, buckets[edi][edx*4]
160 test eax, eax
161 je MISS
162 cmp ecx, method_name[eax]
163 je HIT
164 add edx, 1
165 jmp SCAN
166
167 HIT:
168 mov eax, method_imp[eax]
169 pop esi
170 pop edi
171 mov edx, kFwdMsgSend
172 leave
173 jmp eax
174
175 // cache miss: search method lists
176 MISS:
177 pop esi
178 pop edi
179 mov eax, SELF
180 mov eax, isa[eax]
181
182 // MethodTableLookup WORD_RETURN, MSG_SEND
183 push ecx
184 push eax
185 call _class_lookupMethodAndLoadCache
186
187 mov edx, kFwdMsgSend
188 leave
189 jmp eax
190
191 // message send to nil: return zero
192 NIL:
193 // eax is already zero
194 mov edx, 0
195 leave
196 ret
197 }
198 }
199
200
201 OBJC_EXPORT __declspec(naked) double objc_msgSend_fpret(id a, SEL b, ...)
202 {
203 __asm {
204 push ebp
205 mov ebp, esp
206
207 // load receiver and selector
208 mov ecx, SELECTOR
209 mov eax, SELF
210
211 #if SUPPORT_GC
212 // check whether selector is ignored
213 #error oops
214 #endif
215
216 // check whether receiver is nil
217 test eax, eax
218 je NIL
219
220 // receiver (in eax) is non-nil: search the cache
221 mov edx, isa[eax]
222
223 // CacheLookup WORD_RETURN, MSG_SEND
224 push edi
225 mov edi, cache[edx]
226 push esi
227 mov esi, mask[edi]
228 mov edx, ecx
229 shr edx, 2
230 SCAN:
231 and edx, esi
232 mov eax, buckets[edi][edx*4]
233 test eax, eax
234 je MISS
235 cmp ecx, method_name[eax]
236 je HIT
237 add edx, 1
238 jmp SCAN
239
240 HIT:
241 mov eax, method_imp[eax]
242 pop esi
243 pop edi
244 mov edx, kFwdMsgSend
245 leave
246 jmp eax
247
248 // cache miss: search method lists
249 MISS:
250 pop esi
251 pop edi
252 mov eax, SELF
253 mov eax, isa[eax]
254
255 // MethodTableLookup WORD_RETURN, MSG_SEND
256 push ecx
257 push eax
258 call _class_lookupMethodAndLoadCache
259
260 mov edx, kFwdMsgSend
261 leave
262 jmp eax
263
264 // message send to nil: return zero
265 NIL:
266 fldz
267 leave
268 ret
269 }
270 }
271
272
273 OBJC_EXPORT __declspec(naked) id objc_msgSendSuper(struct objc_super *a, SEL b, ...)
274 {
275 __asm {
276 push ebp
277 mov ebp, esp
278
279 // load class and selector
280 mov eax, SUPER
281 mov ecx, SELECTOR
282 mov edx, super_class[eax]
283
284 #if SUPPORT_GC
285 // check whether selector is ignored
286 #error oops
287 #endif
288
289 // search the cache (class in edx)
290 // CacheLookup WORD_RETURN, MSG_SENDSUPER
291 push edi
292 mov edi, cache[edx]
293 push esi
294 mov esi, mask[edi]
295 mov edx, ecx
296 shr edx, 2
297 SCAN:
298 and edx, esi
299 mov eax, buckets[edi][edx*4]
300 test eax, eax
301 je MISS
302 cmp ecx, method_name[eax]
303 je HIT
304 add edx, 1
305 jmp SCAN
306
307 HIT:
308 mov eax, method_imp[eax]
309 pop esi
310 pop edi
311 mov edx, SUPER
312 mov edx, super_receiver[edx]
313 mov SUPER, edx
314 mov edx, kFwdMsgSend
315 leave
316 jmp eax
317
318 // cache miss: search method lists
319 MISS:
320
321 pop esi
322 pop edi
323 mov edx, SUPER
324 mov eax, super_receiver[edx]
325 mov SUPER, eax
326 mov eax, super_class[edx]
327
328 // MethodTableLookup WORD_RETURN, MSG_SENDSUPER
329 push ecx
330 push eax
331 call _class_lookupMethodAndLoadCache
332
333 mov edx, kFwdMsgSend
334 leave
335 jmp eax
336 }
337 }
338
339
340 OBJC_EXPORT __declspec(naked) void objc_msgSend_stret(void)
341 {
342 __asm {
343 push ebp
344 mov ebp, esp
345
346 // load receiver and selector
347 mov ecx, SELECTOR_STRET
348 mov eax, SELF_STRET
349
350 #if SUPPORT_GC
351 // check whether selector is ignored
352 #error oops
353 #endif
354
355 // check whether receiver is nil
356 test eax, eax
357 je NIL
358
359 // receiver (in eax) is non-nil: search the cache
360 mov edx, isa[eax]
361
362 // CacheLookup WORD_RETURN, MSG_SEND
363 push edi
364 mov edi, cache[edx]
365 push esi
366 mov esi, mask[edi]
367 mov edx, ecx
368 shr edx, 2
369 SCAN:
370 and edx, esi
371 mov eax, buckets[edi][edx*4]
372 test eax, eax
373 je MISS
374 cmp ecx, method_name[eax]
375 je HIT
376 add edx, 1
377 jmp SCAN
378
379 HIT:
380 mov eax, method_imp[eax]
381 pop esi
382 pop edi
383 mov edx, kFwdMsgSendStret
384 leave
385 jmp eax
386
387 // cache miss: search method lists
388 MISS:
389 pop esi
390 pop edi
391 mov eax, SELF_STRET
392 mov eax, isa[eax]
393
394 // MethodTableLookup WORD_RETURN, MSG_SEND
395 push ecx
396 push eax
397 call _class_lookupMethodAndLoadCache
398
399 mov edx, kFwdMsgSendStret
400 leave
401 jmp eax
402
403 // message send to nil: return zero
404 NIL:
405 // eax is already zero
406 mov edx, 0
407 leave
408 ret
409 }
410 }
411
412
413 OBJC_EXPORT __declspec(naked) id objc_msgSendSuper_stret(struct objc_super *a, SEL b, ...)
414 {
415 __asm {
416 push ebp
417 mov ebp, esp
418
419 // load class and selector
420 mov eax, SUPER_STRET
421 mov ecx, SELECTOR_STRET
422 mov edx, super_class[eax]
423
424 #if SUPPORT_GC
425 // check whether selector is ignored
426 #error oops
427 #endif
428
429 // search the cache (class in edx)
430 // CacheLookup WORD_RETURN, MSG_SENDSUPER
431 push edi
432 mov edi, cache[edx]
433 push esi
434 mov esi, mask[edi]
435 mov edx, ecx
436 shr edx, 2
437 SCAN:
438 and edx, esi
439 mov eax, buckets[edi][edx*4]
440 test eax, eax
441 je MISS
442 cmp ecx, method_name[eax]
443 je HIT
444 add edx, 1
445 jmp SCAN
446
447 HIT:
448 mov eax, method_imp[eax]
449 pop esi
450 pop edi
451 mov edx, SUPER_STRET
452 mov edx, super_receiver[edx]
453 mov SUPER_STRET, edx
454 mov edx, kFwdMsgSendStret
455 leave
456 jmp eax
457
458 // cache miss: search method lists
459 MISS:
460
461 pop esi
462 pop edi
463 mov edx, SUPER_STRET
464 mov eax, super_receiver[edx]
465 mov SUPER_STRET, eax
466 mov eax, super_class[edx]
467
468 // MethodTableLookup WORD_RETURN, MSG_SENDSUPER
469 push ecx
470 push eax
471 call _class_lookupMethodAndLoadCache
472
473 mov edx, kFwdMsgSendStret
474 leave
475 jmp eax
476 }
477 }
478
479
480 OBJC_EXPORT __declspec(naked) id _objc_msgForward(id a, SEL b, ...)
481 {
482 __asm {
483 mov ecx, _objc_forward_handler
484 // forward:: support omitted here
485 jmp ecx
486 }
487 }
488
489 OBJC_EXPORT __declspec(naked) id _objc_msgForward_stret(id a, SEL b, ...)
490 {
491 __asm {
492 mov ecx, _objc_forward_stret_handler
493 // forward:: support omitted here
494 jmp ecx
495 }
496 }
497
498
499 __declspec(naked) id _objc_msgForward_internal(id a, SEL b, ...)
500 {
501 __asm {
502 cmp edx, kFwdMsgSendStret
503 je STRET
504 jmp _objc_msgForward
505 STRET:
506 jmp _objc_msgForward_stret
507 }
508 }
509
510
511 OBJC_EXPORT __declspec(naked) void method_invoke(void)
512 {
513 __asm {
514 push ebp
515 mov ebp, esp
516
517 mov ecx, SELECTOR
518 mov edx, method_name[ecx]
519 mov eax, method_imp[ecx]
520 mov SELECTOR, edx
521
522 leave
523 jmp eax
524 }
525 }
526
527
528 OBJC_EXPORT __declspec(naked) void method_invoke_stret(void)
529 {
530 __asm {
531 push ebp
532 mov ebp, esp
533
534 mov ecx, SELECTOR_STRET
535 mov edx, method_name[ecx]
536 mov eax, method_imp[ecx]
537 mov SELECTOR_STRET, edx
538
539 leave
540 jmp eax
541 }
542 }
543
544
545 __declspec(naked) id _objc_ignored_method(id obj, SEL sel)
546 {
547 return obj;
548 }