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