]> git.saurik.com Git - apple/objc4.git/blobdiff - runtime/Messengers.subproj/objc-msg-win32.m
objc4-437.tar.gz
[apple/objc4.git] / runtime / Messengers.subproj / objc-msg-win32.m
diff --git a/runtime/Messengers.subproj/objc-msg-win32.m b/runtime/Messengers.subproj/objc-msg-win32.m
new file mode 100644 (file)
index 0000000..7fcc38e
--- /dev/null
@@ -0,0 +1,505 @@
+#include "objc-private.h"\r
+\r
+// out-of-band parameter to objc_msgForward\r
+#define kFwdMsgSend 1\r
+#define kFwdMsgSendStret 0\r
+\r
+// objc_msgSend parameters\r
+#define self 4\r
+#define super 4\r
+#define selector 8\r
+#define first_arg 12\r
+\r
+// objc_msgSend_stret parameters\r
+#define struct_addr 4\r
+#define self_stret 8\r
+#define super_stret 8\r
+#define selector_stret 12\r
+\r
+// objc_super parameter to sendSuper\r
+#define super_receiver 0\r
+#define super_class 4\r
+\r
+// struct objc_class fields\r
+#define isa 0\r
+#define cache 32\r
+\r
+// struct objc_method fields\r
+#define method_name 0\r
+#define method_imp 8\r
+\r
+// struct objc_cache fields\r
+#define mask 0\r
+#define occupied 4\r
+#define buckets 8\r
+\r
+void *_objc_forward_handler = NULL;\r
+void *_objc_forward_stret_handler = NULL;\r
+\r
+__declspec(naked) Method _cache_getMethod(Class cls, SEL sel, IMP objc_msgForward_imp)\r
+{\r
+    __asm {\r
+        mov ecx, selector[esp]\r
+        mov edx, self[esp]\r
+\r
+// CacheLookup WORD_RETURN, CACHE_GET\r
+        push edi\r
+        mov edi, cache[edx]\r
+\r
+        push esi\r
+        mov esi, mask[edi]\r
+        mov edx, ecx\r
+        shr edx, 2\r
+SCAN:\r
+        and edx, esi\r
+        mov eax, buckets[edi][edx*4]\r
+        test eax, eax\r
+        je MISS\r
+        cmp ecx, method_name[eax]\r
+        je HIT\r
+        add edx, 1\r
+        jmp SCAN\r
+\r
+MISS:\r
+        xor eax, eax\r
+        pop esi\r
+        pop edi\r
+        ret\r
+\r
+HIT:\r
+        mov ecx, 8+first_arg[esp]\r
+        cmp ecx, method_imp[eax]\r
+        je MISS\r
+        pop esi\r
+        pop edi\r
+        ret\r
+    }\r
+}\r
+\r
+__declspec(naked) IMP _cache_getImp(Class cls, SEL sel)\r
+{\r
+    __asm {\r
+        mov ecx, selector[esp]\r
+        mov edx, self[esp]\r
+\r
+// CacheLookup WORD_RETURN, CACHE_GET\r
+        push edi\r
+        mov edi, cache[edx]\r
+\r
+        push esi\r
+        mov esi, mask[edi]\r
+        mov edx, ecx\r
+        shr edx, 2\r
+SCAN:\r
+        and edx, esi\r
+        mov eax, buckets[edi][edx*4]\r
+        test eax, eax\r
+        je MISS\r
+        cmp ecx, method_name[eax]\r
+        je HIT\r
+        add edx, 1\r
+        jmp SCAN\r
+\r
+MISS:\r
+        pop esi\r
+        pop edi\r
+        xor eax, eax\r
+        ret\r
+\r
+HIT:\r
+        pop esi\r
+        pop edi\r
+        mov eax, method_imp[eax]\r
+        ret\r
+\r
+    }\r
+}\r
+\r
+\r
+OBJC_EXPORT __declspec(naked) id objc_msgSend(id a, SEL b, ...)\r
+{\r
+    __asm {\r
+        // load receiver and selector\r
+        mov ecx, selector[esp]\r
+        mov eax, self[esp]\r
+\r
+#if !defined(NO_GC)\r
+        // check whether selector is ignored\r
+#error oops\r
+#endif\r
+\r
+        // check whether receiver is nil\r
+        test eax, eax\r
+        je NIL\r
+\r
+        // receiver (in eax) is non-nil: search the cache\r
+        mov edx, isa[eax]\r
+\r
+        // CacheLookup WORD_RETURN, MSG_SEND\r
+        push edi\r
+        mov edi, cache[edx]\r
+        push esi\r
+        mov esi, mask[edi]\r
+        mov edx, ecx\r
+        shr edx, 2\r
+SCAN:\r
+        and edx, esi\r
+        mov eax, buckets[edi][edx*4]\r
+        test eax, eax\r
+        je MISS\r
+        cmp ecx, method_name[eax]\r
+        je HIT\r
+        add edx, 1\r
+        jmp SCAN\r
+\r
+HIT:\r
+        mov eax, method_imp[eax]\r
+        pop esi\r
+        pop edi\r
+        mov edx, kFwdMsgSend\r
+        jmp eax\r
+\r
+        // cache miss: search method lists\r
+MISS:\r
+        pop esi\r
+        pop edi\r
+        mov eax, self[esp]\r
+        mov eax, isa[eax]\r
+\r
+        // MethodTableLookup WORD_RETURN, MSG_SEND\r
+        sub esp, 4\r
+        push ecx\r
+        push eax\r
+        call _class_lookupMethodAndLoadCache\r
+        add esp, 12\r
+\r
+        mov edx, kFwdMsgSend\r
+        jmp eax\r
+\r
+        // message send to nil: return zero\r
+NIL:\r
+        // eax is already zero\r
+        mov edx, 0\r
+        ret\r
+    }\r
+}\r
+\r
+\r
+OBJC_EXPORT __declspec(naked) double objc_msgSend_fpret(id a, SEL b, ...)\r
+{\r
+    __asm {\r
+        // load receiver and selector\r
+        mov ecx, selector[esp]\r
+        mov eax, self[esp]\r
+\r
+#if !defined(NO_GC)\r
+        // check whether selector is ignored\r
+#error oops\r
+#endif\r
+\r
+        // check whether receiver is nil\r
+        test eax, eax\r
+        je NIL\r
+\r
+        // receiver (in eax) is non-nil: search the cache\r
+        mov edx, isa[eax]\r
+\r
+        // CacheLookup WORD_RETURN, MSG_SEND\r
+        push edi\r
+        mov edi, cache[edx]\r
+        push esi\r
+        mov esi, mask[edi]\r
+        mov edx, ecx\r
+        shr edx, 2\r
+SCAN:\r
+        and edx, esi\r
+        mov eax, buckets[edi][edx*4]\r
+        test eax, eax\r
+        je MISS\r
+        cmp ecx, method_name[eax]\r
+        je HIT\r
+        add edx, 1\r
+        jmp SCAN\r
+\r
+HIT:\r
+        mov eax, method_imp[eax]\r
+        pop esi\r
+        pop edi\r
+        mov edx, kFwdMsgSend\r
+        jmp eax\r
+\r
+        // cache miss: search method lists\r
+MISS:\r
+        pop esi\r
+        pop edi\r
+        mov eax, self[esp]\r
+        mov eax, isa[eax]\r
+\r
+        // MethodTableLookup WORD_RETURN, MSG_SEND\r
+        sub esp, 4\r
+        push ecx\r
+        push eax\r
+        call _class_lookupMethodAndLoadCache\r
+        add esp, 12\r
+\r
+        mov edx, kFwdMsgSend\r
+        jmp eax\r
+\r
+        // message send to nil: return zero\r
+NIL:\r
+        fldz\r
+        ret\r
+    }\r
+}\r
+\r
+\r
+OBJC_EXPORT __declspec(naked) id objc_msgSendSuper(struct objc_super *a, SEL b, ...)\r
+{\r
+    __asm {\r
+        // load class and selector\r
+        mov eax, super[esp]\r
+        mov ecx, selector[esp]\r
+        mov edx, super_class[eax]\r
+\r
+#if !defined(NO_GC)\r
+        // check whether selector is ignored\r
+#error oops\r
+#endif\r
+\r
+        // search the cache (class in edx)\r
+        // CacheLookup WORD_RETURN, MSG_SENDSUPER\r
+        push edi\r
+        mov edi, cache[edx]\r
+        push esi\r
+        mov esi, mask[edi]\r
+        mov edx, ecx\r
+        shr edx, 2\r
+SCAN:\r
+        and edx, esi\r
+        mov eax, buckets[edi][edx*4]\r
+        test eax, eax\r
+        je MISS\r
+        cmp ecx, method_name[eax]\r
+        je HIT\r
+        add edx, 1\r
+        jmp SCAN\r
+\r
+HIT:\r
+        mov eax, method_imp[eax]\r
+        pop esi\r
+        pop edi\r
+        mov edx, super[esp]\r
+        mov edx, super_receiver[edx]\r
+        mov super[esp], edx\r
+        mov edx, kFwdMsgSend\r
+        jmp eax\r
+\r
+        // cache miss: search method lists\r
+MISS:\r
+\r
+        pop esi\r
+        pop edi\r
+        mov edx, super[esp]\r
+        mov eax, super_receiver[edx]\r
+        mov super[esp], eax\r
+        mov eax, super_class[edx]\r
+\r
+        // MethodTableLookup WORD_RETURN, MSG_SENDSUPER\r
+        sub esp, 4\r
+        push ecx\r
+        push eax\r
+        call _class_lookupMethodAndLoadCache\r
+        add esp, 12\r
+\r
+        mov edx, kFwdMsgSend\r
+        jmp eax\r
+    }\r
+}\r
+\r
+\r
+OBJC_EXPORT __declspec(naked) void objc_msgSend_stret(void)\r
+{\r
+    __asm {\r
+        // load receiver and selector\r
+        mov ecx, selector_stret[esp]\r
+        mov eax, self_stret[esp]\r
+\r
+#if !defined(NO_GC)\r
+        // check whether selector is ignored\r
+#error oops\r
+#endif\r
+\r
+        // check whether receiver is nil\r
+        test eax, eax\r
+        je NIL\r
+\r
+        // receiver (in eax) is non-nil: search the cache\r
+        mov edx, isa[eax]\r
+\r
+        // CacheLookup WORD_RETURN, MSG_SEND\r
+        push edi\r
+        mov edi, cache[edx]\r
+        push esi\r
+        mov esi, mask[edi]\r
+        mov edx, ecx\r
+        shr edx, 2\r
+SCAN:\r
+        and edx, esi\r
+        mov eax, buckets[edi][edx*4]\r
+        test eax, eax\r
+        je MISS\r
+        cmp ecx, method_name[eax]\r
+        je HIT\r
+        add edx, 1\r
+        jmp SCAN\r
+\r
+HIT:\r
+        mov eax, method_imp[eax]\r
+        pop esi\r
+        pop edi\r
+        mov edx, kFwdMsgSendStret\r
+        jmp eax\r
+\r
+        // cache miss: search method lists\r
+MISS:\r
+        pop esi\r
+        pop edi\r
+        mov eax, self_stret[esp]\r
+        mov eax, isa[eax]\r
+\r
+        // MethodTableLookup WORD_RETURN, MSG_SEND\r
+        sub esp, 4\r
+        push ecx\r
+        push eax\r
+        call _class_lookupMethodAndLoadCache\r
+        add esp, 12\r
+\r
+        mov edx, kFwdMsgSendStret\r
+        jmp eax\r
+\r
+        // message send to nil: return zero\r
+NIL:\r
+        // eax is already zero\r
+        mov edx, 0\r
+        ret\r
+    }\r
+}\r
+\r
+\r
+OBJC_EXPORT __declspec(naked) id objc_msgSendSuper_stret(struct objc_super *a, SEL b, ...)\r
+{\r
+    __asm {\r
+        // load class and selector\r
+        mov eax, super_stret[esp]\r
+        mov ecx, selector_stret[esp]\r
+        mov edx, super_class[eax]\r
+\r
+#if !defined(NO_GC)\r
+        // check whether selector is ignored\r
+#error oops\r
+#endif\r
+\r
+        // search the cache (class in edx)\r
+        // CacheLookup WORD_RETURN, MSG_SENDSUPER\r
+        push edi\r
+        mov edi, cache[edx]\r
+        push esi\r
+        mov esi, mask[edi]\r
+        mov edx, ecx\r
+        shr edx, 2\r
+SCAN:\r
+        and edx, esi\r
+        mov eax, buckets[edi][edx*4]\r
+        test eax, eax\r
+        je MISS\r
+        cmp ecx, method_name[eax]\r
+        je HIT\r
+        add edx, 1\r
+        jmp SCAN\r
+\r
+HIT:\r
+        mov eax, method_imp[eax]\r
+        pop esi\r
+        pop edi\r
+        mov edx, super[esp]\r
+        mov edx, super_receiver[edx]\r
+        mov super[esp], edx\r
+        mov edx, kFwdMsgSendStret\r
+        jmp eax\r
+\r
+        // cache miss: search method lists\r
+MISS:\r
+\r
+        pop esi\r
+        pop edi\r
+        mov edx, super_stret[esp]\r
+        mov eax, super_receiver[edx]\r
+        mov super_stret[esp], eax\r
+        mov eax, super_class[edx]\r
+\r
+        // MethodTableLookup WORD_RETURN, MSG_SENDSUPER\r
+        sub esp, 4\r
+        push ecx\r
+        push eax\r
+        call _class_lookupMethodAndLoadCache\r
+        add esp, 12\r
+\r
+        mov edx, kFwdMsgSendStret\r
+        jmp eax\r
+    }\r
+}\r
+\r
+\r
+OBJC_EXPORT __declspec(naked) id _objc_msgForward(id a, SEL b, ...)\r
+{\r
+    __asm {\r
+        mov ecx, _objc_forward_handler\r
+        // forward:: support omitted here\r
+        jmp ecx\r
+    }\r
+}\r
+\r
+OBJC_EXPORT __declspec(naked) id _objc_msgForward_stret(id a, SEL b, ...)\r
+{\r
+    __asm {\r
+        mov ecx, _objc_forward_stret_handler\r
+        // forward:: support omitted here\r
+        jmp ecx\r
+    }\r
+}\r
+\r
+\r
+__declspec(naked) id _objc_msgForward_internal(id a, SEL b, ...)\r
+{\r
+    __asm {\r
+        cmp edx, kFwdMsgSendStret\r
+        je  STRET\r
+        jmp _objc_msgForward\r
+STRET:\r
+        jmp _objc_msgForward_stret\r
+    }\r
+}\r
+\r
+\r
+OBJC_EXPORT __declspec(naked) void method_invoke(void)\r
+{\r
+    __asm {\r
+        mov ecx, selector[esp]\r
+        mov edx, method_name[ecx]\r
+        mov eax, method_imp[ecx]\r
+        mov selector[esp], edx\r
+        jmp eax\r
+    }\r
+}\r
+\r
+\r
+OBJC_EXPORT __declspec(naked) void method_invoke_stret(void)\r
+{\r
+    __asm {\r
+        mov ecx, selector_stret[esp]\r
+        mov edx, method_name[ecx]\r
+        mov eax, method_imp[ecx]\r
+        mov selector_stret[esp], edx\r
+        jmp eax\r
+    }\r
+}\r