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
36void *_objc_forward_handler = NULL;
37void *_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
56SCAN:
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
66MISS:
67        xor eax, eax
68        pop esi
69        pop edi
70        leave
71        ret
72
73HIT:
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
101SCAN:
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
111MISS:
112        pop esi
113        pop edi
114        xor eax, eax
115        leave
116        ret
117
118HIT:
119        pop esi
120        pop edi
121        mov eax, method_imp[eax]
122        leave
123        ret
124    }
125}
126
127
128OBJC_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
157SCAN:
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
167HIT:
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
176MISS:
177        pop esi
178        pop edi
179        mov edx, SELF
180        mov eax, isa[edx]
181
182        // MethodTableLookup WORD_RETURN, MSG_SEND
183        push eax
184        push ecx
185        push edx
186        call _class_lookupMethodAndLoadCache3
187
188        mov edx, kFwdMsgSend
189        leave
190        jmp eax
191
192        // message send to nil: return zero
193NIL:
194        // eax is already zero
195        mov edx, 0
196        leave
197        ret
198    }
199}
200
201
202OBJC_EXPORT __declspec(naked) double objc_msgSend_fpret(id a, SEL b, ...)
203{
204    __asm {
205        push ebp
206        mov ebp, esp
207
208        // load receiver and selector
209        mov ecx, SELECTOR
210        mov eax, SELF
211
212#if SUPPORT_GC
213        // check whether selector is ignored
214#error oops
215#endif
216
217        // check whether receiver is nil
218        test eax, eax
219        je NIL
220
221        // receiver (in eax) is non-nil: search the cache
222        mov edx, isa[eax]
223
224        // CacheLookup WORD_RETURN, MSG_SEND
225        push edi
226        mov edi, cache[edx]
227        push esi
228        mov esi, mask[edi]
229        mov edx, ecx
230        shr edx, 2
231SCAN:
232        and edx, esi
233        mov eax, buckets[edi][edx*4]
234        test eax, eax
235        je MISS
236        cmp ecx, method_name[eax]
237        je HIT
238        add edx, 1
239        jmp SCAN
240
241HIT:
242        mov eax, method_imp[eax]
243        pop esi
244        pop edi
245        mov edx, kFwdMsgSend
246        leave
247        jmp eax
248
249        // cache miss: search method lists
250MISS:
251        pop esi
252        pop edi
253        mov edx, SELF
254        mov eax, isa[edx]
255
256        // MethodTableLookup WORD_RETURN, MSG_SEND
257        push eax
258        push ecx
259        push edx
260        call _class_lookupMethodAndLoadCache3
261
262        mov edx, kFwdMsgSend
263        leave
264        jmp eax
265
266        // message send to nil: return zero
267NIL:
268        fldz
269        leave
270        ret
271    }
272}
273
274
275OBJC_EXPORT __declspec(naked) id objc_msgSendSuper(struct objc_super *a, SEL b, ...)
276{
277    __asm {
278        push ebp
279        mov ebp, esp
280
281        // load class and selector
282        mov eax, SUPER
283        mov ecx, SELECTOR
284        mov edx, super_class[eax]
285
286#if SUPPORT_GC
287        // check whether selector is ignored
288#error oops
289#endif
290
291        // search the cache (class in edx)
292        // CacheLookup WORD_RETURN, MSG_SENDSUPER
293        push edi
294        mov edi, cache[edx]
295        push esi
296        mov esi, mask[edi]
297        mov edx, ecx
298        shr edx, 2
299SCAN:
300        and edx, esi
301        mov eax, buckets[edi][edx*4]
302        test eax, eax
303        je MISS
304        cmp ecx, method_name[eax]
305        je HIT
306        add edx, 1
307        jmp SCAN
308
309HIT:
310        mov eax, method_imp[eax]
311        pop esi
312        pop edi
313        mov edx, SUPER
314        mov edx, super_receiver[edx]
315        mov SUPER, edx
316        mov edx, kFwdMsgSend
317        leave
318        jmp eax
319
320        // cache miss: search method lists
321MISS:
322
323        pop esi
324        pop edi
325        mov eax, SUPER
326        mov edx, super_receiver[eax]
327        mov SUPER, edx
328        mov eax, super_class[eax]
329
330        // MethodTableLookup WORD_RETURN, MSG_SENDSUPER
331        push eax
332        push ecx
333        push edx
334        call _class_lookupMethodAndLoadCache3
335
336        mov edx, kFwdMsgSend
337        leave
338        jmp eax
339    }
340}
341
342
343OBJC_EXPORT __declspec(naked) void objc_msgSend_stret(void)
344{
345    __asm {
346        push ebp
347        mov ebp, esp
348
349        // load receiver and selector
350        mov ecx, SELECTOR_STRET
351        mov eax, SELF_STRET
352
353#if SUPPORT_GC
354        // check whether selector is ignored
355#error oops
356#endif
357
358        // check whether receiver is nil
359        test eax, eax
360        je NIL
361
362        // receiver (in eax) is non-nil: search the cache
363        mov edx, isa[eax]
364
365        // CacheLookup WORD_RETURN, MSG_SEND
366        push edi
367        mov edi, cache[edx]
368        push esi
369        mov esi, mask[edi]
370        mov edx, ecx
371        shr edx, 2
372SCAN:
373        and edx, esi
374        mov eax, buckets[edi][edx*4]
375        test eax, eax
376        je MISS
377        cmp ecx, method_name[eax]
378        je HIT
379        add edx, 1
380        jmp SCAN
381
382HIT:
383        mov eax, method_imp[eax]
384        pop esi
385        pop edi
386        mov edx, kFwdMsgSendStret
387        leave
388        jmp eax
389
390        // cache miss: search method lists
391MISS:
392        pop esi
393        pop edi
394        mov edx, SELF_STRET
395        mov eax, isa[edx]
396
397        // MethodTableLookup WORD_RETURN, MSG_SEND
398        push eax
399        push ecx
400        push edx
401        call _class_lookupMethodAndLoadCache3
402
403        mov edx, kFwdMsgSendStret
404        leave
405        jmp eax
406
407        // message send to nil: return zero
408NIL:
409        // eax is already zero
410        mov edx, 0
411        leave
412        ret
413    }
414}
415
416
417OBJC_EXPORT __declspec(naked) id objc_msgSendSuper_stret(struct objc_super *a, SEL b, ...)
418{
419    __asm {
420        push ebp
421        mov ebp, esp
422
423        // load class and selector
424        mov eax, SUPER_STRET
425        mov ecx, SELECTOR_STRET
426        mov edx, super_class[eax]
427
428#if SUPPORT_GC
429        // check whether selector is ignored
430#error oops
431#endif
432
433        // search the cache (class in edx)
434        // CacheLookup WORD_RETURN, MSG_SENDSUPER
435        push edi
436        mov edi, cache[edx]
437        push esi
438        mov esi, mask[edi]
439        mov edx, ecx
440        shr edx, 2
441SCAN:
442        and edx, esi
443        mov eax, buckets[edi][edx*4]
444        test eax, eax
445        je MISS
446        cmp ecx, method_name[eax]
447        je HIT
448        add edx, 1
449        jmp SCAN
450
451HIT:
452        mov eax, method_imp[eax]
453        pop esi
454        pop edi
455        mov edx, SUPER_STRET
456        mov edx, super_receiver[edx]
457        mov SUPER_STRET, edx
458        mov edx, kFwdMsgSendStret
459        leave
460        jmp eax
461
462        // cache miss: search method lists
463MISS:
464
465        pop esi
466        pop edi
467        mov eax, SUPER_STRET
468        mov edx, super_receiver[eax]
469        mov SUPER_STRET, edx
470        mov eax, super_class[eax]
471
472        // MethodTableLookup WORD_RETURN, MSG_SENDSUPER
473        push eax
474        push ecx
475        push edx
476        call _class_lookupMethodAndLoadCache3
477
478        mov edx, kFwdMsgSendStret
479        leave
480        jmp eax
481    }
482}
483
484
485OBJC_EXPORT __declspec(naked) id _objc_msgForward(id a, SEL b, ...)
486{
487    __asm {
488        mov ecx, _objc_forward_handler
489        jmp ecx
490    }
491}
492
493OBJC_EXPORT __declspec(naked) id _objc_msgForward_stret(id a, SEL b, ...)
494{
495    __asm {
496        mov ecx, _objc_forward_stret_handler
497        jmp ecx
498    }
499}
500
501
502__declspec(naked) id _objc_msgForward_cached(id a, SEL b, ...)
503{
504    __asm {
505        cmp edx, kFwdMsgSendStret
506        je  STRET
507        jmp _objc_msgForward
508STRET:
509        jmp _objc_msgForward_stret
510    }
511}
512
513
514OBJC_EXPORT __declspec(naked) void method_invoke(void)
515{
516    __asm {
517        push ebp
518        mov ebp, esp
519
520        mov ecx, SELECTOR
521        mov edx, method_name[ecx]
522        mov eax, method_imp[ecx]
523        mov SELECTOR, edx
524
525        leave
526        jmp eax
527    }
528}
529
530
531OBJC_EXPORT __declspec(naked) void method_invoke_stret(void)
532{
533    __asm {
534        push ebp
535        mov ebp, esp
536
537        mov ecx, SELECTOR_STRET
538        mov edx, method_name[ecx]
539        mov eax, method_imp[ecx]
540        mov SELECTOR_STRET, edx
541
542        leave
543        jmp eax
544    }
545}
546
547
548__declspec(naked) id _objc_ignored_method(id obj, SEL sel)
549{
550    return obj;
551}
552