--- /dev/null
+#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