1/* 2 * Objective-C runtime 2.0 compatibility for MacOS X 10.4 and earlier. 3 * 4 * This code works by poking into the ObjC runtime, which means loads of 5 * warnings on 10.5+ ;-) 6 */ 7 8#define PYOBJC_COMPAT_IMPL 9#include "pyobjc.h" 10 11 12 13 14#if (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5) &&!defined(__OBJC2__) 15 16BOOL PyObjC_class_isSubclassOf(Class child, Class parent) 17{ 18 if (parent == nil) return YES; 19 20 while (child != nil) { 21 if (child == parent) { 22 return YES; 23 } 24 child = PyObjC_class_getSuperclass(child); 25 } 26 return NO; 27} 28 29#import <mach-o/dyld.h> 30#import <mach-o/getsect.h> 31#import <mach-o/loader.h> 32 33typedef struct _ProtocolTemplate { @defs(Protocol) } ProtocolTemplate; 34 35 36 37struct objc10_object { 38 Class isa; 39}; 40 41struct PyObjC_ivar { 42 char* name; 43 size_t size; 44 uint8_t alignment; 45 char* types; 46}; 47 48 49static Protocol** compat_objc_copyProtocolList(unsigned int* outCount) 50{ 51 Protocol** protocols = NULL; 52 *outCount = 0; 53 54 uint32_t image_count, image_index; 55 image_count = _dyld_image_count(); 56 for (image_index = 0; image_index < image_count; image_index++) { 57 uint32_t size = 0; 58 const struct mach_header *mh = _dyld_get_image_header(image_index); 59 intptr_t slide = _dyld_get_image_vmaddr_slide(image_index); 60 ProtocolTemplate *protos = (ProtocolTemplate*)( 61 ((char *)getsectdatafromheader(mh, SEG_OBJC, "__protocol", &size)) + 62 slide); 63 uint32_t nprotos = size / sizeof(ProtocolTemplate); 64 uint32_t i; 65 66 if (nprotos == 0) continue; 67 68 if (protocols == NULL) { 69 protocols = malloc(sizeof(Protocol*) * nprotos); 70 if (protocols == NULL) { 71 return NULL; 72 } 73 } else { 74 Protocol** tmp = realloc(protocols, 75 sizeof(Protocol*) * (*outCount+nprotos)); 76 if (tmp == NULL) { 77 free(protocols); 78 return NULL; 79 } 80 protocols = tmp; 81 } 82 83 for (i = 0; i < nprotos; i++) { 84 protocols[(*outCount)++] = (Protocol*)&protos[i]; 85 } 86 } 87 return protocols; 88} 89 90static void 91compat_objc_registerClassPair(Class cls) 92{ 93 struct objc_method_list* list; 94 95 /* Add the list in the official way, just in case class_addMethods 96 * does something special. 97 */ 98 list = cls->methodLists[0]; 99 cls->methodLists[0] = (struct objc_method_list*)-1; 100 class_addMethods(cls, list); 101 102 list = cls->isa->methodLists[0]; 103 cls->isa->methodLists[0] = (struct objc_method_list*)-1; 104 class_addMethods(cls->isa, list); 105 106 objc_addClass(cls); 107} 108 109static Class 110compat_objc_allocateClassPair(Class super_class, const char* name, size_t extra) 111{ 112 struct objc_class* result; 113 Class root_class; 114 115 if (objc_getClass(name)) { 116 return Nil; 117 } 118 119 root_class = super_class; 120 while (root_class->super_class) { 121 root_class = root_class->super_class; 122 } 123 124 result = malloc(sizeof(struct objc_class) * 2 + extra); 125 if (result == NULL) { 126 return Nil; 127 } 128 memset(result, 0, sizeof(struct objc_class) * 2 + extra); 129 130 result->super_class = super_class; 131 result->isa = result + 1; 132 133 result[0].methodLists = NULL; 134 result[1].methodLists = NULL; 135 136 result[0].info = CLS_CLASS; 137 result[1].info = CLS_META; 138 139 result[0].name = strdup(name); 140 if (result[0].name == NULL) goto error_cleanup; 141 142 result[1].name = result[0].name; 143 result[0].methodLists = malloc(sizeof(struct objc_method_list*)); 144 if (result[0].methodLists == NULL) goto error_cleanup; 145 memset(result[0].methodLists, 0, sizeof(struct objc_method_list*)); 146 147 result[1].methodLists = malloc(sizeof(struct objc_method_list*)); 148 if (result[1].methodLists == NULL) goto error_cleanup; 149 memset(result[1].methodLists, 0, sizeof(struct objc_method_list*)); 150 151 /* 152 * This is MacOS X specific, and an undocumented feature (long live 153 * Open Source!). 154 * 155 * The code in the objc runtime assumes that the method lists are 156 * terminated by '-1', and will happily overwite existing data if 157 * they aren't. 158 * 159 * Ronald filed a bugreport for this: Radar #3317376 160 */ 161 result[0].methodLists[0] = (struct objc_method_list*)-1; 162 result[1].methodLists[0] = (struct objc_method_list*)-1; 163 164 result[0].methodLists[0] = malloc(sizeof(struct objc_method_list)); 165 if (result[0].methodLists[0] == NULL) goto error_cleanup; 166 result[0].methodLists[0]->method_count = 0; 167 result[0].methodLists[0]->obsolete = NULL; 168 169 result[1].methodLists[0] = malloc(sizeof(struct objc_method_list)); 170 if (result[1].methodLists[0] == NULL) goto error_cleanup; 171 result[1].methodLists[0]->method_count = 0; 172 result[1].methodLists[0]->obsolete = NULL; 173 174 175 result[0].super_class = super_class; 176 result[1].super_class = ((struct objc10_object*)super_class)->isa; 177 result[1].isa = ((struct objc10_object*)root_class)->isa; 178 179 result[0].instance_size = super_class->instance_size; 180 result[1].instance_size = result[1].super_class->instance_size; 181 182 /* Initialize to NULL, otherwise poseAs: won't work */ 183 result[0].ivars = result[1].ivars = NULL; 184 185 result[0].protocols = result[1].protocols = NULL; 186 187 return result; 188 189 190error_cleanup: 191 if (result) { 192 if (result[0].methodLists) { 193 if (result[0].methodLists[0] != 0 && 194 result[0].methodLists[0] != 0) { 195 free(result[0].methodLists[0]); 196 } 197 free(result[0].methodLists); 198 } 199 if (result[1].methodLists) { 200 if (result[1].methodLists[1] != 0 && 201 result[1].methodLists[0] != 0) { 202 free(result[1].methodLists[0]); 203 } 204 free(result[1].methodLists); 205 } 206 207 if (result[0].ivars) { 208 free(result[0].ivars); 209 } 210 if (result[1].ivars) { 211 free(result[1].ivars); 212 } 213 214 if (result[0].name) { 215 free((char*)result[0].name); 216 } 217 free(result); 218 } 219 return Nil; 220 221} 222 223static void 224compat_objc_disposeClassPair(Class cls) 225{ 226 struct objc_class* val = cls; 227 int i; 228 229 for (i = 0; i < 2; i++) { 230 if (val[i].methodLists) { 231 struct objc_method_list** cur; 232 233 cur = val[i].methodLists; 234 if (*cur != (struct objc_method_list*)-1) { 235 free(*cur); 236 *cur = NULL; 237 } 238 free(val[i].methodLists); 239 val[i].methodLists = NULL; 240 } 241 } 242 243 free((char*)val[0].name); 244 val[0].name = val[1].name = NULL; 245 free(val); 246} 247 248 249static size_t 250compat_methodlist_magic(Class cls) 251{ 252 void* iterator = NULL; 253 struct objc_method_list* mlist; 254 size_t res = 0, cnt = 0; 255 256 if (cls == NULL) return -1; 257 258 while ( (mlist = class_nextMethodList(cls, &iterator )) != NULL ) { 259 res += mlist->method_count; 260 cnt++; 261 } 262 263 return (cnt << 16) | (res & 0xFFFF); 264} 265 266#ifndef NO_OBJC2_RUNTIME 267static size_t 268objc20_methodlist_magic(Class cls) 269{ 270 Method* methods; 271 unsigned int count; 272 unsigned int i; 273 size_t result; 274 275 methods = class_copyMethodList(cls, &count); 276 result = 0; 277 for (i = 0; i < count; i++) { 278 result = (1000003*result) ^ ((size_t)( 279 method_getImplementation(methods[i])) >> 3); 280 } 281 result = result | (count << 16); 282 free(methods); 283 return result; 284} 285#endif 286 287static Class 288compat_object_setClass(id obj, Class cls) 289{ 290 Class prev; 291 if (obj == nil) { 292 return Nil; 293 } 294 prev = ((struct objc10_object*)obj)->isa; 295 ((struct objc10_object*)obj)->isa = cls; 296 return prev; 297} 298 299 300 301static Class 302compat_object_getClass(id obj) 303{ 304 return ((struct objc10_object*)obj)->isa; 305} 306 307static const char* 308compat_object_getClassName(id obj) 309{ 310 return ((struct objc10_object*)obj)->isa->name; 311} 312 313 314 315static Method* 316compat_class_copyMethodList(Class cls, unsigned int* outCount) 317{ 318 struct objc_method_list* mlist; 319 void* iterator; 320 unsigned int count; 321 Method* result; 322 Method* tmp; 323 324 iterator = NULL; 325 count = 0; 326 327 mlist = class_nextMethodList(cls, &iterator); 328 result = NULL; 329 while (mlist != NULL) { 330 int i; 331 332 tmp = realloc(result, (count + mlist->method_count) * sizeof(Method)); 333 if (tmp == NULL) { 334 free(result); 335 return NULL; 336 } else { 337 result = tmp; 338 } 339 340 for (i = 0; i < mlist->method_count; i++) { 341 result[count] = mlist->method_list + i; 342 if (result[count] == NULL) continue; 343 count++; 344 } 345 mlist = class_nextMethodList(cls, &iterator); 346 } 347 348 if (outCount != NULL) { 349 *outCount = count; 350 } 351 return result; 352} 353 354static Ivar* 355compat_class_copyIvarList(Class cls, unsigned int* outCount) 356{ 357 Ivar* list; 358 int i; 359 struct objc_ivar_list* ivars = cls->ivars; 360 361 if (ivars) { 362 list = malloc(sizeof(Ivar) * ivars->ivar_count); 363 if (list == NULL) { 364 return NULL; 365 } 366 367 368 for (i = 0; i < ivars->ivar_count; i++) { 369 list[i] = ivars->ivar_list + i; 370 } 371 *outCount = ivars->ivar_count; 372 return list; 373 374 } else { 375 list = malloc(1); 376 if (list == NULL) { 377 return NULL; 378 } 379 380 *outCount = 0; 381 return list; 382 } 383 384} 385 386static Protocol** 387compat_class_copyProtocolList(Class cls, unsigned int* outCount) 388{ 389 Protocol** list; 390 unsigned int count = 0; 391 struct objc_protocol_list *protocol_list; 392 393 protocol_list = cls->protocols; 394 list = malloc(0); 395 396 while (protocol_list != NULL) { 397 list = realloc(list, (count + protocol_list->count)*sizeof(Protocol*)); 398 if (list == NULL) { 399 /* Whoops, memory leak */ 400 *outCount = 0; 401 return NULL; 402 } 403 memcpy(list + count, protocol_list->list, protocol_list->count*sizeof(Protocol*)); 404 count += protocol_list->count; 405 protocol_list = protocol_list->next; 406 } 407 408 *outCount = count; 409 return list; 410} 411 412 413static const char* 414compat_class_getName(Class cls) 415{ 416 return cls->name; 417} 418 419static Class 420compat_class_getSuperclass(Class cls) 421{ 422 return cls->super_class; 423} 424 425static BOOL 426compat_class_addMethod(Class cls, SEL name, IMP imp, const char* types) 427{ 428 struct objc_method_list* methodsToAdd; 429 struct objc_method* objcMethod; 430 431 methodsToAdd = malloc(sizeof(struct objc_method_list) + 432 2*sizeof(struct objc_method)); 433 methodsToAdd->method_count = 1; 434 methodsToAdd->obsolete = NULL; 435 436 objcMethod = methodsToAdd->method_list; 437 objcMethod->method_name = name; 438 objcMethod->method_imp = imp; 439 objcMethod->method_types = (char*)types; 440 441 class_addMethods(cls, methodsToAdd); 442 return YES; /* Have to return something ... */ 443} 444 445static BOOL 446compat_preclass_addMethod(Class cls, SEL name, IMP imp, const char* types) 447{ 448 /* Resize in-place, this is only valid during class construction. */ 449 struct objc_method_list* new_list; 450 struct objc_method* objcMethod; 451 452 new_list = realloc(cls->methodLists[0], 453 sizeof(struct objc_method_list) + 454 (sizeof(struct objc_method 455 )*(cls->methodLists[0]->method_count+1))); 456 if (new_list == NULL) { 457 return NO; 458 } 459 cls->methodLists[0] = new_list; 460 objcMethod = new_list->method_list + (new_list->method_count)++; 461 462 objcMethod->method_name = name; 463 objcMethod->method_imp = imp; 464 objcMethod->method_types = strdup(types); 465 if (objcMethod == NULL) { 466 new_list->method_count--; 467 return NO; 468 } 469 470 return YES; 471} 472 473static BOOL 474compat_preclass_addIvar( 475 Class cls, 476 const char* name, 477 size_t size, 478 uint8_t align, const char* types) 479{ 480 /* Update the class structure, only valid during class construction */ 481 struct objc_ivar_list* new_ivars; 482 struct objc_ivar* ivar; 483 484 if (cls->ivars) { 485 new_ivars = realloc(cls->ivars, 486 sizeof(struct objc_ivar_list) + 487 ((cls->ivars->ivar_count+1) * sizeof(struct objc_ivar))); 488 } else { 489 new_ivars = malloc( 490 sizeof(struct objc_ivar_list) + 491 sizeof(struct objc_ivar)); 492 new_ivars->ivar_count = 0; 493 } 494 if (new_ivars == NULL) { 495 return NO; 496 } 497 cls->ivars = new_ivars; 498 ivar = new_ivars->ivar_list + new_ivars->ivar_count; 499 ivar->ivar_name = strdup(name); 500 if (ivar->ivar_name == NULL) { 501 return NO; 502 } 503 504 ivar->ivar_type = strdup(types); 505 if (ivar->ivar_type == NULL) { 506 free(ivar->ivar_name); 507 return NO; 508 } 509 510 ivar->ivar_offset = cls->instance_size; 511 if (ivar->ivar_offset % align) { 512 ivar->ivar_offset += align - (ivar->ivar_offset % align); 513 } 514 515 new_ivars->ivar_count ++; 516 cls->instance_size = ivar->ivar_offset + size; 517 return YES; 518} 519 520static BOOL 521compat_preclass_addProtocol(Class cls, Protocol* protocol) 522{ 523 struct objc_protocol_list* protocols; 524 525 if (cls->protocols) { 526 protocols = realloc(cls->protocols, 527 sizeof(struct objc_protocol_list) + 528 (sizeof(Protocol*)*(cls->protocols->count+1))); 529 } else { 530 protocols = malloc(sizeof(struct objc_protocol_list) 531 + sizeof(Protocol*)); 532 protocols->count = 0; 533 protocols->next = NULL; 534 } 535 if (protocols == NULL) { 536 return NO; 537 } 538 cls->protocols = protocols; 539 protocols->list[protocols->count] = protocol; 540 protocols->count++; 541 return YES; 542} 543 544static SEL 545compat_method_getName(Method m) 546{ 547 return m->method_name; 548} 549 550static IMP 551compat_method_getImplementation(Method m) 552{ 553 return m->method_imp; 554} 555 556static IMP 557compat_method_setImplementation(Method m, IMP imp) 558{ 559 IMP result = m->method_imp; 560 m->method_imp = imp; 561 return result; 562} 563 564static const char * 565compat_method_getTypeEncoding(Method m) 566{ 567 return m->method_types; 568} 569 570static BOOL 571compat_sel_isEqual(SEL lhs, SEL rhs) 572{ 573 return lhs == rhs; 574} 575 576static const char* 577compat_ivar_getName(Ivar var) 578{ 579 return var->ivar_name; 580} 581 582static const char* 583compat_ivar_getTypeEncoding(Ivar var) 584{ 585 return var->ivar_type; 586} 587 588static ptrdiff_t 589compat_ivar_getOffset(Ivar var) 590{ 591 return var->ivar_offset; 592} 593 594 595#ifndef NO_OBJC2_RUNTIME 596static BOOL 597objc20_class_addMethodList(Class cls, 598 struct PyObjC_method* list, unsigned int count) 599{ 600 unsigned int i; 601 BOOL r; 602 Method m; 603 604 for (i = 0; i < count; i++) { 605 r = class_addMethod(cls, 606 list[i].name, list[i].imp, list[i].type); 607 if (!r) { 608 m = class_getInstanceMethod(cls, list[i].name); 609 if (m != NULL) { 610 method_setImplementation(m, list[i].imp); 611 } else { 612 return NO; 613 } 614 } 615 } 616 return YES; 617} 618#endif 619 620static BOOL 621compat_class_isMetaClass(Class cls) 622{ 623 return CLS_GETINFO(cls, CLS_META) == CLS_META; 624} 625 626static BOOL 627compat_class_addMethodList(Class cls, 628 struct PyObjC_method* list, unsigned int count) 629{ 630 unsigned int i; 631 struct objc_method_list* method_list; 632 633 method_list = malloc( 634 sizeof(struct objc_method_list) + 635 ((count+1) * sizeof(struct objc_method))); 636 if (method_list == NULL) { 637 return NO; 638 } 639 memset(method_list, 0, 640 sizeof(struct objc_method_list) + 641 ((count+1) * sizeof(struct objc_method))); 642 643 method_list->method_count = 0; 644 method_list->obsolete = 0; 645 646 for (i = 0; i < count; i++) { 647 method_list->method_list[i].method_name = list[i].name; 648 method_list->method_list[i].method_types = (char*)list[i].type; 649 method_list->method_list[i].method_imp = list[i].imp; 650 } 651 method_list->method_count = count; 652 class_addMethods(cls, method_list); 653 return YES; 654} 655 656static BOOL 657compat_protocol_conformsToProtocol(Protocol *proto, Protocol *other) 658{ 659 return [proto conformsTo:other]; 660} 661 662static const char * 663compat_protocol_getName(Protocol *p) 664{ 665 return [p name]; 666} 667 668static struct objc_method_description * 669compat_protocol_copyMethodDescriptionList(Protocol *p, BOOL isRequiredMethod, BOOL isInstanceMethod, unsigned int *outCount) 670{ 671 if (!isRequiredMethod) { 672 *outCount = 0; 673 return NULL; 674 } 675 676 struct objc_method_description_list* list; 677 678 if (isInstanceMethod) { 679 list = ((ProtocolTemplate*)p)->instance_methods; 680 } else { 681 list = ((ProtocolTemplate*)p)->class_methods; 682 } 683 684 if (list == NULL || list->count == 0) { 685 *outCount = 0; 686 return NULL; 687 } 688 689 *outCount = list->count; 690 struct objc_method_description* result; 691 692 result = malloc(sizeof(struct objc_method_description) * list->count); 693 if (result == NULL) { 694 return NULL; 695 } 696 697 int i; 698 *outCount = 0; 699 for (i = 0; i < list->count; i++) { 700 if (list->list[i].name == NULL) continue; 701 result[*outCount].name = list->list[i].name; 702 result[*outCount].types = list->list[i].types; 703 (*outCount)++; 704 } 705 706 return result; 707} 708 709static Protocol ** 710compat_protocol_copyProtocolList(Protocol *proto, unsigned int *outCount) 711{ 712 struct objc_protocol_list* list = 713 ((ProtocolTemplate*)proto)->protocol_list; 714 715 *outCount = 0; 716 717 struct objc_protocol_list* cur; 718 for (cur = list; cur != NULL; cur = cur->next) { 719 *outCount += cur->count; 720 } 721 722 Protocol** result = (Protocol**)malloc(sizeof(Protocol*) * *outCount); 723 if (result == NULL) { 724 return NULL; 725 } 726 727 unsigned curIdx = 0; 728 for (cur = list; cur != NULL; cur = cur->next) { 729 int i; 730 for (i = 0; i < cur->count; i++) { 731 if (cur->list[i] != NULL) { 732 result[curIdx++] = cur->list[i]; 733 } else { 734 *outCount--; 735 } 736 } 737 } 738 return result; 739} 740 741static struct objc_method_description 742compat_protocol_getMethodDescription(Protocol *p, SEL aSel, BOOL isRequiredMethod, BOOL isInstanceMethod) 743{ 744static struct objc_method_description empty_description = { NULL, NULL }; 745 if (!isRequiredMethod) { 746 return empty_description; 747 } 748 749 struct objc_method_description* result; 750 751 if (isInstanceMethod) { 752 result = [p descriptionForInstanceMethod: aSel]; 753 } else { 754 result = [p descriptionForClassMethod: aSel]; 755 } 756 757 if (result == NULL) { 758 return empty_description; 759 } else { 760 return *result; 761 } 762} 763 764static id 765compat_object_getIvar(id obj, Ivar ivar) 766{ 767 return *(id*)(((char*)obj) + ivar->ivar_offset); 768} 769static void 770compat_object_setIvar(id obj, Ivar ivar, id value) 771{ 772 *(id*)(((char*)obj) + ivar->ivar_offset) = value; 773} 774 775/* Dispatch table */ 776BOOL (*PyObjC_protocol_conformsToProtocol)(Protocol *proto, Protocol *other) = NULL; 777const char *(*PyObjC_protocol_getName)(Protocol *p) = NULL; 778struct objc_method_description *(*PyObjC_protocol_copyMethodDescriptionList)(Protocol *p, BOOL isRequiredMethod, BOOL isInstanceMethod, unsigned int *outCount) = NULL; 779Protocol **(*PyObjC_protocol_copyProtocolList)(Protocol *proto, unsigned int *outCount) = NULL; 780struct objc_method_description (*PyObjC_protocol_getMethodDescription)(Protocol *p, SEL aSel, BOOL isRequiredMethod, BOOL isInstanceMethod) = NULL; 781 782id (*PyObjC_object_getIvar)(id obj, Ivar ivar) = NULL; 783void (*PyObjC_object_setIvar)(id obj, Ivar ivar, id value) = NULL; 784 785 786 787Class (*PyObjC_objc_allocateClassPair)(Class, const char*, size_t) = NULL; 788void (*PyObjC_objc_registerClassPair)(Class) = NULL; 789void (*PyObjC_objc_disposeClassPair)(Class) = NULL; 790Protocol** (*PyObjC_objc_copyProtocolList)(unsigned int*) = NULL; 791 792BOOL (*PyObjC_preclass_addMethod)(Class, SEL, IMP, const char*) = NULL; 793BOOL (*PyObjC_preclass_addIvar)(Class cls, 794 const char *name, size_t size, uint8_t alignment, 795 const char *types) = NULL; 796BOOL (*PyObjC_preclass_addProtocol)(Class cls, Protocol *protocol) = NULL; 797 798 799Class (*PyObjC_object_getClass)(id obj) = NULL; 800Class (*PyObjC_object_setClass)(id obj, Class cls) = NULL; 801const char* (*PyObjC_object_getClassName)(id obj) = NULL; 802 803Method* (*PyObjC_class_copyMethodList)(Class, unsigned int*) = NULL; 804const char* (*PyObjC_class_getName)(Class) = NULL; 805Class (*PyObjC_class_getSuperclass)(Class) = NULL; 806BOOL (*PyObjC_class_addMethod)(Class, SEL, IMP, const char*) = NULL; 807BOOL (*PyObjC_class_addMethodList)(Class, 808 struct PyObjC_method*, unsigned int) = NULL; 809Ivar* (*PyObjC_class_copyIvarList)(Class, unsigned int*) = NULL; 810Protocol** (*PyObjC_class_copyProtocolList)(Class, unsigned int*) = NULL; 811BOOL (*PyObjC_class_isMetaClass)(Class) = NULL; 812 813SEL (*PyObjC_method_getName)(Method m) = NULL; 814IMP (*PyObjC_method_getImplementation)(Method m) = NULL; 815IMP (*PyObjC_method_setImplementation)(Method m, IMP imp) = NULL; 816const char *(*PyObjC_method_getTypeEncoding)(Method m) = NULL; 817 818BOOL (*PyObjC_sel_isEqual)(SEL, SEL) = NULL; 819 820size_t (*PyObjC_methodlist_magic)(Class cls); 821 822const char* (*PyObjC_ivar_getName)(Ivar) = NULL; 823const char* (*PyObjC_ivar_getTypeEncoding)(Ivar) = NULL; 824ptrdiff_t (*PyObjC_ivar_getOffset)(Ivar) = NULL; 825 826 827 828void PyObjC_SetupRuntimeCompat(void) 829{ 830#ifdef NO_OBJC2_RUNTIME 831 /* 832 * Don't use ObjC 2.0 runtime (compiling on 10.4 or earlier), always 833 * use the compat implementation. 834 */ 835 PyObjC_class_addMethodList = compat_class_addMethodList; 836 PyObjC_methodlist_magic = compat_methodlist_magic; 837 PyObjC_objc_disposeClassPair = compat_objc_disposeClassPair; 838 PyObjC_preclass_addMethod = compat_preclass_addMethod; 839 PyObjC_preclass_addIvar = compat_preclass_addIvar; 840 PyObjC_preclass_addProtocol = compat_preclass_addProtocol; 841 842# define SETUP(funcname) \ 843 PyObjC_##funcname = compat_##funcname 844 845#else 846 if (class_addMethod) { 847 PyObjC_class_addMethodList = objc20_class_addMethodList; 848 PyObjC_preclass_addMethod = class_addMethod; 849 PyObjC_preclass_addIvar = class_addIvar; 850 PyObjC_preclass_addProtocol= class_addProtocol; 851 } else { 852 PyObjC_class_addMethodList = compat_class_addMethodList; 853 PyObjC_preclass_addMethod = compat_preclass_addMethod; 854 PyObjC_preclass_addIvar = compat_preclass_addIvar; 855 PyObjC_preclass_addProtocol= compat_preclass_addProtocol; 856 } 857 858 859 if (class_copyMethodList) { 860 PyObjC_methodlist_magic = objc20_methodlist_magic; 861 } else { 862 PyObjC_methodlist_magic = compat_methodlist_magic; 863 } 864 865# define SETUP(funcname) \ 866 if ((funcname) == NULL) { \ 867 PyObjC_##funcname = compat_##funcname; \ 868 } else { \ 869 PyObjC_##funcname = funcname; \ 870 } 871#endif 872 SETUP(protocol_getName); 873 SETUP(protocol_conformsToProtocol); 874 SETUP(protocol_copyMethodDescriptionList); 875 SETUP(protocol_copyProtocolList); 876 SETUP(protocol_getMethodDescription); 877 878 SETUP(objc_allocateClassPair); 879 SETUP(objc_registerClassPair); 880 SETUP(objc_disposeClassPair); 881 SETUP(objc_copyProtocolList); 882 883 SETUP(object_getClass); 884 SETUP(object_setClass); 885 SETUP(object_getClassName); 886 SETUP(object_getIvar); 887 SETUP(object_setIvar); 888 889 SETUP(class_getSuperclass); 890 SETUP(class_addMethod); 891 SETUP(class_copyIvarList); 892 SETUP(class_copyProtocolList); 893 SETUP(class_copyMethodList); 894 SETUP(class_getName); 895 SETUP(class_isMetaClass); 896 897 SETUP(method_getName); 898 SETUP(method_getTypeEncoding); 899 SETUP(method_getImplementation); 900 SETUP(method_setImplementation); 901 902 SETUP(sel_isEqual); 903 904 SETUP(ivar_getName); 905 SETUP(ivar_getTypeEncoding); 906 SETUP(ivar_getOffset); 907#undef SETUP 908 909} 910 911#else 912 913 914BOOL PyObjC_class_isSubclassOf(Class child, Class parent) 915{ 916 if (parent == nil) return YES; 917 918 while (child != nil) { 919 if (child == parent) { 920 return YES; 921 } 922 child = class_getSuperclass(child); 923 } 924 return NO; 925} 926 927BOOL PyObjC_class_addMethodList(Class cls, 928 struct PyObjC_method* list, unsigned int count) 929{ 930 unsigned int i; 931 BOOL r; 932 Method m; 933 934 for (i = 0; i < count; i++) { 935 /* 936 * XXX: First try class_addMethod, if that fails assume this is 937 * because the method already exists in the class. 938 * Strictly speaking this isn't correct, but this is the best 939 * we can do through the 2.0 API (see 4809039 in RADAR) 940 */ 941 r = class_addMethod(cls, 942 list[i].name, list[i].imp, list[i].type); 943 if (!r) { 944 m = class_getInstanceMethod(cls, list[i].name); 945 if (m != NULL) { 946 method_setImplementation(m, list[i].imp); 947 } else { 948 return NO; 949 } 950 } 951 } 952 return YES; 953} 954 955size_t PyObjC_methodlist_magic(Class cls) 956{ 957 /* This is likely to be much slower than compat_methodlist_magic, 958 * but should works on the 64-bit runtime. Hopefully a callback will 959 * be added to the 2.0 runtime that will take away the need for this 960 * function... 961 */ 962 Method* methods; 963 unsigned int count; 964 965 methods = class_copyMethodList(cls, &count); 966#if 0 967 unsigned int i; 968 size_t result; 969 result = 0; 970 for (i = 0; i < count; i++) { 971 result = (1000003*result) ^ ((size_t)( 972 method_getImplementation(methods[i])) >> 3); 973 } 974 result = result | (count << 16); 975 free(methods); 976 return result; 977#endif 978 free(methods); 979 return (size_t)count; 980} 981 982#endif 983 984#if __OBJC2__ 985 986@implementation Protocol (NSOBjectCompat) 987- self 988{ 989 return self; 990} 991@end 992 993@implementation Object (NSOBjectCompat) 994- self 995{ 996 return self; 997} 998 999-doesNotRecognizeSelector:(SEL)sel 1000{ 1001 printf("--> %s\n", sel_getName(sel)); 1002 abort(); 1003} 1004@end 1005 1006 1007#endif 1008