summaryrefslogtreecommitdiff
path: root/Objective-C/PyObjC
diff options
context:
space:
mode:
authorMatthias Benkard <code@mail.matthias.benkard.de>2008-01-28 20:17:26 +0100
committerMatthias Benkard <code@mail.matthias.benkard.de>2008-01-28 20:17:26 +0100
commitf18bd561556ce01b6f4c19244daf47e6acd0b47d (patch)
tree46ea2ca0ae55b6428e27c18bddd27515521e7945 /Objective-C/PyObjC
parentf955a86f64289de63702bd03f4d6d7fdec9dff1b (diff)
Import NeXT runtime support files from PyObjC.
darcs-hash:75e887a4c2fdef84a692ecc368886a3dfb523cde
Diffstat (limited to 'Objective-C/PyObjC')
-rw-r--r--Objective-C/PyObjC/objc-runtime-compat.h198
-rw-r--r--Objective-C/PyObjC/objc-runtime-compat.m987
2 files changed, 1185 insertions, 0 deletions
diff --git a/Objective-C/PyObjC/objc-runtime-compat.h b/Objective-C/PyObjC/objc-runtime-compat.h
new file mode 100644
index 0000000..3823f1f
--- /dev/null
+++ b/Objective-C/PyObjC/objc-runtime-compat.h
@@ -0,0 +1,198 @@
+#ifndef PyObjC_RUNTIME_COMPAT
+#define PyObjC_RUNTIME_COMPAT
+/*
+ * Objective-C 2.0 runtime compatibility.
+ *
+ * This files makes it possible to use the Objective-C 2.0 API on versions
+ * of Mac OS X before 10.5. Use PyObjC_FUNCNAME to access FUNCNAME from the
+ * Objective-C 2.0 API, see the Objective-C 2.0 runtime documentation to see
+ * how it should be used.
+ *
+ * TODO:
+ * - completely move PyObjC to the Objective-C 2.0 API
+ * - add more wizardry to ensure that this code compiles on OSX 10.4
+ *
+ * Special:
+ * - PyObjC_class_addMethodList is not a function in the ObjC 2.0 runtime API,
+ * but added here to (a) get semantics that are slightly nicer for what
+ * we do and (b) can be implemented efficiently on the "1.0" runtime.
+ * - PyObjC_methodlist_magic is meant to be used to determine if a class has
+ * changed in some way (such by loading a category).
+ * - Modifying a created but not yet registered class should be done using
+ * the preclass_* functions, not the regular ones because it isn't possible
+ * to emulate the entire ObjC 2.0 API on Tiger.
+ */
+#include <objc/objc-runtime.h>
+#include <objc/Protocol.h>
+
+#define _C_CONST 'r'
+#define _C_IN 'n'
+#define _C_INOUT 'N'
+#define _C_OUT 'o'
+#define _C_BYCOPY 'O'
+#define _C_ONEWAY 'V'
+#define _C_LNG_LNG 'q'
+#define _C_ULNG_LNG 'Q'
+#define _C_BOOL 'B' /* (Objective-)C++ 'bool' */
+
+struct PyObjC_method {
+ SEL name;
+ IMP imp;
+ const char* type;
+};
+
+#define objc_superSetReceiver(super, val) (super).receiver = (val)
+#define objc_superGetReceiver(super) ((super).receiver)
+
+#ifdef __OBJC2__
+
+#define objc_superSetClass(super, cls) (super).super_class = (cls)
+#define objc_superGetClass(super) ((super).super_class)
+
+#else
+
+#define objc_superSetClass(super, cls) (super).class = (cls)
+#define objc_superGetClass(super) ((super).class)
+
+#endif
+
+/* Some functions that are missing (oddly enough) */
+BOOL PyObjC_class_isSubclassOf(Class child, Class parent);
+#define class_isSubclassOf PyObjC_class_isSubclassOf
+
+#if (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5) && !defined(__OBJC2__)
+
+#define preclass_addIvar PyObjC_preclass_addIvar
+#define preclass_addMethod PyObjC_preclass_addMethod
+#define preclass_addProtocol PyObjC_preclass_addProtocol
+
+extern void PyObjC_SetupRuntimeCompat(void);
+
+extern BOOL (*PyObjC_preclass_addMethod)(Class, SEL, IMP, const char*);
+extern BOOL (*PyObjC_preclass_addIvar)(Class cls,
+ const char *name, size_t size, uint8_t alignment,
+ const char *types);
+extern BOOL (*PyObjC_preclass_addProtocol)(Class cls, Protocol *protocol);
+
+
+extern Class (*PyObjC_objc_allocateClassPair)(Class, const char*, size_t);
+extern void (*PyObjC_objc_registerClassPair)(Class);
+extern void (*PyObjC_objc_disposeClassPair)(Class cls);
+
+
+extern Class (*PyObjC_object_getClass)(id obj);
+extern Class (*PyObjC_object_setClass)(id obj, Class cls);
+extern const char* (*PyObjC_object_getClassName)(id obj);
+
+extern Method* (*PyObjC_class_copyMethodList)(Class, unsigned int*);
+extern const char* (*PyObjC_class_getName)(Class);
+extern Class (*PyObjC_class_getSuperclass)(Class);
+extern BOOL (*PyObjC_class_addMethod)(Class, SEL, IMP, const char*);
+extern BOOL (*PyObjC_class_addMethodList)(Class,
+ struct PyObjC_method*, unsigned int);
+extern Ivar* (*PyObjC_class_copyIvarList)(Class, unsigned int*);
+extern Protocol** (*PyObjC_class_copyProtocolList)(Class, unsigned int*);
+
+extern BOOL (*PyObjC_class_isMetaClass)(Class);
+
+extern SEL (*PyObjC_method_getName)(Method m);
+extern const char *(*PyObjC_method_getTypeEncoding)(Method m);
+extern IMP (*PyObjC_method_getImplementation)(Method m);
+extern IMP (*PyObjC_method_setImplementation)(Method m, IMP imp);
+
+extern BOOL (*PyObjC_sel_isEqual)(SEL, SEL);
+
+extern size_t (*PyObjC_methodlist_magic)(Class cls);
+
+extern const char* (*PyObjC_ivar_getName)(Ivar);
+extern const char* (*PyObjC_ivar_getTypeEncoding)(Ivar);
+extern ptrdiff_t (*PyObjC_ivar_getOffset)(Ivar);
+
+extern Protocol** (*PyObjC_objc_copyProtocolList)(unsigned int* outCount);
+extern Protocol* (*PyObjC_objc_getProtocol)(char* name);
+extern struct objc_method_description_list* (*PyObjC_protocol_copyInstanceMethodDescriptionList)(Protocol* proto);
+extern struct objc_method_description_list* (*PyObjC_protocol_copyClassMethodDescriptionList)(Protocol *proto);
+extern struct objc_method_description_list* (*PyObjC_protocol_copyOptionalInstanceMethodDescriptionList)(Protocol *proto);
+extern struct objc_method_description_list* (*PyObjC_protocol_copyOptionalClassMethodDescriptionList)(Protocol *proto);
+
+extern BOOL (*PyObjC_protocol_conformsToProtocol)(Protocol *proto, Protocol *other);
+extern const char *(*PyObjC_protocol_getName)(Protocol *p);
+extern struct objc_method_description *(*PyObjC_protocol_copyMethodDescriptionList)(Protocol *p, BOOL isRequiredMethod, BOOL isInstanceMethod, unsigned int *outCount);
+extern Protocol **(*PyObjC_protocol_copyProtocolList)(Protocol *proto, unsigned int *outCount);
+extern struct objc_method_description (*PyObjC_protocol_getMethodDescription)(Protocol *p, SEL aSel, BOOL isRequiredMethod, BOOL isInstanceMethod);
+
+extern id (*PyObjC_object_getIvar)(id obj, Ivar ivar);
+extern void (*PyObjC_object_setIvar)(id obj, Ivar ivar, id value);
+
+#define object_getIvar PyObjC_object_getIvar
+#define object_setIvar PyObjC_object_setIvar
+#define protocol_getName PyObjC_protocol_getName
+#define protocol_conformsToProtocol PyObjC_protocol_conformsToProtocol
+#define protocol_copyMethodDescriptionList PyObjC_protocol_copyMethodDescriptionList
+#define protocol_copyProtocolList PyObjC_protocol_copyProtocolList
+#define protocol_getMethodDescription PyObjC_protocol_getMethodDescription
+
+#define objc_allocateClassPair PyObjC_objc_allocateClassPair
+#define objc_registerClassPair PyObjC_objc_registerClassPair
+#define objc_disposeClassPair PyObjC_objc_disposeClassPair
+
+#define object_getClass PyObjC_object_getClass
+#define object_setClass PyObjC_object_setClass
+#define object_getClassName PyObjC_object_getClassName
+
+#define class_copyMethodList PyObjC_class_copyMethodList
+#define class_getName PyObjC_class_getName
+#define class_getSuperclass PyObjC_class_getSuperclass
+#define class_addMethod PyObjC_class_addMethod
+#define class_addMethodList PyObjC_class_addMethodList
+#define class_copyIvarList PyObjC_class_copyIvarList
+#define class_copyProtocolList PyObjC_class_copyProtocolList
+#define class_conformsToProtocol PyObjC_class_conformsToProtocol
+#define class_isMetaClass PyObjC_class_isMetaClass
+
+#define method_getName PyObjC_method_getName
+#define method_getTypeEncoding PyObjC_method_getTypeEncoding
+#define method_getImplementation PyObjC_method_getImplementation
+#define method_setImplementation PyObjC_method_setImplementation
+
+#define sel_isEqual PyObjC_sel_isEqual
+
+#define ivar_getName PyObjC_ivar_getName
+#define ivar_getTypeEncoding PyObjC_ivar_getTypeEncoding
+#define ivar_getOffset PyObjC_ivar_getOffset
+
+#define objc_copyProtocolList PyObjC_objc_copyProtocolList
+#define objc_getProtocol PyObjC_objc_getProtocol
+#define protocol_copyInstanceMethodDescriptionList PyObjC_protocol_copyInstanceMethodDescriptionList
+#define protocol_copyClassMethodDescriptionList PyObjC_protocol_copyClassMethodDescriptionList
+#define protocol_copyOptionalInstanceMethodDescriptionList PyObjC_protocol_copyOptionalInstanceMethodDescriptionList
+#define protocol_copyOptionalClassMethodDescriptionList PyObjC_protocol_copyOptionalClassMethodDescriptionList
+
+#else
+
+/*
+ * Compiled for 10.5 or later, use ObjC 2.0 runtime exclusively.
+ *
+ *
+ * Use the preclass_ versions to modify a Class between allocating it and
+ * registering it. This is needed for the 10.4 compatibility layer.
+ */
+
+#define preclass_addIvar class_addIvar
+#define preclass_addMethod class_addMethod
+#define preclass_addProtocol class_addProtocol
+
+static inline void PyObjC_SetupRuntimeCompat(void) { }
+extern BOOL PyObjC_class_addMethodList(Class class,
+ struct PyObjC_method* list, unsigned int count);
+
+
+extern size_t PyObjC_methodlist_magic(Class cls);
+
+#define class_addMethodList PyObjC_class_addMethodList
+
+
+#endif
+
+
+#endif /* PyObjC_RUNTIME_COMPAT */
diff --git a/Objective-C/PyObjC/objc-runtime-compat.m b/Objective-C/PyObjC/objc-runtime-compat.m
new file mode 100644
index 0000000..036b1a1
--- /dev/null
+++ b/Objective-C/PyObjC/objc-runtime-compat.m
@@ -0,0 +1,987 @@
+/*
+ * Objective-C runtime 2.0 compatibility for MacOS X 10.4 and earlier.
+ *
+ * This code works by poking into the ObjC runtime, which means loads of
+ * warnings on 10.5+ ;-)
+ */
+#include "pyobjc.h"
+
+BOOL PyObjC_class_isSubclassOf(Class child, Class parent)
+{
+ if (parent == nil) return YES;
+
+ while (child != nil) {
+ if (child == parent) {
+ return YES;
+ }
+ child = class_getSuperclass(child);
+ }
+ return NO;
+}
+
+
+
+#if (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5) &&!defined(__OBJC2__)
+
+#import <mach-o/dyld.h>
+#import <mach-o/getsect.h>
+#import <mach-o/loader.h>
+
+typedef struct _ProtocolTemplate { @defs(Protocol) } ProtocolTemplate;
+
+
+
+struct objc10_object {
+ Class isa;
+};
+
+struct PyObjC_ivar {
+ char* name;
+ size_t size;
+ uint8_t alignment;
+ char* types;
+};
+
+
+static Protocol** compat_objc_copyProtocolList(unsigned int* outCount)
+{
+ Protocol** protocols = NULL;
+ *outCount = 0;
+
+ uint32_t image_count, image_index;
+ image_count = _dyld_image_count();
+ for (image_index = 0; image_index < image_count; image_index++) {
+ uint32_t size = 0;
+ const struct mach_header *mh = _dyld_get_image_header(image_index);
+ intptr_t slide = _dyld_get_image_vmaddr_slide(image_index);
+ ProtocolTemplate *protos = (ProtocolTemplate*)(
+ ((char *)getsectdatafromheader(mh, SEG_OBJC, "__protocol", &size)) +
+ slide);
+ uint32_t nprotos = size / sizeof(ProtocolTemplate);
+ uint32_t i;
+
+ if (nprotos == 0) continue;
+
+ if (protocols == NULL) {
+ protocols = malloc(sizeof(Protocol*) * nprotos);
+ if (protocols == NULL) {
+ return NULL;
+ }
+ } else {
+ Protocol** tmp = realloc(protocols,
+ sizeof(Protocol*) * (*outCount+nprotos));
+ if (tmp == NULL) {
+ free(protocols);
+ return NULL;
+ }
+ protocols = tmp;
+ }
+
+ for (i = 0; i < nprotos; i++) {
+ protocols[(*outCount)++] = (Protocol*)&protos[i];
+ }
+ }
+ return protocols;
+}
+
+static void
+compat_objc_registerClassPair(Class cls)
+{
+ struct objc_method_list* list;
+
+ /* Add the list in the official way, just in case class_addMethods
+ * does something special.
+ */
+ list = cls->methodLists[0];
+ cls->methodLists[0] = (struct objc_method_list*)-1;
+ class_addMethods(cls, list);
+
+ list = cls->isa->methodLists[0];
+ cls->isa->methodLists[0] = (struct objc_method_list*)-1;
+ class_addMethods(cls->isa, list);
+
+ objc_addClass(cls);
+}
+
+static Class
+compat_objc_allocateClassPair(Class super_class, const char* name, size_t extra)
+{
+ struct objc_class* result;
+ Class root_class;
+
+ if (objc_getClass(name)) {
+ return Nil;
+ }
+
+ root_class = super_class;
+ while (root_class->super_class) {
+ root_class = root_class->super_class;
+ }
+
+ result = malloc(sizeof(struct objc_class) * 2 + extra);
+ if (result == NULL) {
+ return Nil;
+ }
+ memset(result, 0, sizeof(struct objc_class) * 2 + extra);
+
+ result->super_class = super_class;
+ result->isa = result + 1;
+
+ result[0].methodLists = NULL;
+ result[1].methodLists = NULL;
+
+ result[0].info = CLS_CLASS;
+ result[1].info = CLS_META;
+
+ result[0].name = strdup(name);
+ if (result[0].name == NULL) goto error_cleanup;
+
+ result[1].name = result[0].name;
+ result[0].methodLists = malloc(sizeof(struct objc_method_list*));
+ if (result[0].methodLists == NULL) goto error_cleanup;
+ memset(result[0].methodLists, 0, sizeof(struct objc_method_list*));
+
+ result[1].methodLists = malloc(sizeof(struct objc_method_list*));
+ if (result[1].methodLists == NULL) goto error_cleanup;
+ memset(result[1].methodLists, 0, sizeof(struct objc_method_list*));
+
+ /*
+ * This is MacOS X specific, and an undocumented feature (long live
+ * Open Source!).
+ *
+ * The code in the objc runtime assumes that the method lists are
+ * terminated by '-1', and will happily overwite existing data if
+ * they aren't.
+ *
+ * Ronald filed a bugreport for this: Radar #3317376
+ */
+ result[0].methodLists[0] = (struct objc_method_list*)-1;
+ result[1].methodLists[0] = (struct objc_method_list*)-1;
+
+ result[0].methodLists[0] = malloc(sizeof(struct objc_method_list));
+ if (result[0].methodLists[0] == NULL) goto error_cleanup;
+ result[0].methodLists[0]->method_count = 0;
+ result[0].methodLists[0]->obsolete = NULL;
+
+ result[1].methodLists[0] = malloc(sizeof(struct objc_method_list));
+ if (result[1].methodLists[0] == NULL) goto error_cleanup;
+ result[1].methodLists[0]->method_count = 0;
+ result[1].methodLists[0]->obsolete = NULL;
+
+
+ result[0].super_class = super_class;
+ result[1].super_class = ((struct objc10_object*)super_class)->isa;
+ result[1].isa = ((struct objc10_object*)root_class)->isa;
+
+ result[0].instance_size = super_class->instance_size;
+ result[1].instance_size = result[1].super_class->instance_size;
+
+ /* Initialize to NULL, otherwise poseAs: won't work */
+ result[0].ivars = result[1].ivars = NULL;
+
+ result[0].protocols = result[1].protocols = NULL;
+
+ return result;
+
+
+error_cleanup:
+ if (result) {
+ if (result[0].methodLists) {
+ if (result[0].methodLists[0] != 0 &&
+ result[0].methodLists[0] != 0) {
+ free(result[0].methodLists[0]);
+ }
+ free(result[0].methodLists);
+ }
+ if (result[1].methodLists) {
+ if (result[1].methodLists[1] != 0 &&
+ result[1].methodLists[0] != 0) {
+ free(result[1].methodLists[0]);
+ }
+ free(result[1].methodLists);
+ }
+
+ if (result[0].ivars) {
+ free(result[0].ivars);
+ }
+ if (result[1].ivars) {
+ free(result[1].ivars);
+ }
+
+ if (result[0].name) {
+ free((char*)result[0].name);
+ }
+ free(result);
+ }
+ return Nil;
+
+}
+
+static void
+compat_objc_disposeClassPair(Class cls)
+{
+ struct objc_class* val = cls;
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ if (val[i].methodLists) {
+ struct objc_method_list** cur;
+
+ cur = val[i].methodLists;
+ if (*cur != (struct objc_method_list*)-1) {
+ free(*cur);
+ *cur = NULL;
+ }
+ free(val[i].methodLists);
+ val[i].methodLists = NULL;
+ }
+ }
+
+ free((char*)val[0].name);
+ val[0].name = val[1].name = NULL;
+ free(val);
+}
+
+
+static size_t
+compat_methodlist_magic(Class cls)
+{
+ void* iterator = NULL;
+ struct objc_method_list* mlist;
+ size_t res = 0, cnt = 0;
+
+ if (cls == NULL) return -1;
+
+ while ( (mlist = class_nextMethodList(cls, &iterator )) != NULL ) {
+ res += mlist->method_count;
+ cnt++;
+ }
+
+ return (cnt << 16) | (res & 0xFFFF);
+}
+
+#ifndef NO_OBJC2_RUNTIME
+static size_t
+objc20_methodlist_magic(Class cls)
+{
+ Method* methods;
+ unsigned int count;
+ unsigned int i;
+ size_t result;
+
+ methods = class_copyMethodList(cls, &count);
+ result = 0;
+ for (i = 0; i < count; i++) {
+ result = (1000003*result) ^ ((size_t)(
+ method_getImplementation(methods[i])) >> 3);
+ }
+ result = result | (count << 16);
+ free(methods);
+ return result;
+}
+#endif
+
+static Class
+compat_object_setClass(id obj, Class cls)
+{
+ Class prev;
+ if (obj == nil) {
+ return Nil;
+ }
+ prev = ((struct objc10_object*)obj)->isa;
+ ((struct objc10_object*)obj)->isa = cls;
+ return prev;
+}
+
+
+
+static Class
+compat_object_getClass(id obj)
+{
+ return ((struct objc10_object*)obj)->isa;
+}
+
+static const char*
+compat_object_getClassName(id obj)
+{
+ return ((struct objc10_object*)obj)->isa->name;
+}
+
+
+
+static Method*
+compat_class_copyMethodList(Class cls, unsigned int* outCount)
+{
+ struct objc_method_list* mlist;
+ void* iterator;
+ unsigned int count;
+ Method* result;
+ Method* tmp;
+
+ iterator = NULL;
+ count = 0;
+
+ mlist = class_nextMethodList(cls, &iterator);
+ result = NULL;
+ while (mlist != NULL) {
+ int i;
+
+ tmp = realloc(result, (count + mlist->method_count) * sizeof(Method));
+ if (tmp == NULL) {
+ free(result);
+ return NULL;
+ } else {
+ result = tmp;
+ }
+
+ for (i = 0; i < mlist->method_count; i++) {
+ result[count] = mlist->method_list + i;
+ if (result[count] == NULL) continue;
+ count++;
+ }
+ mlist = class_nextMethodList(cls, &iterator);
+ }
+
+ if (outCount != NULL) {
+ *outCount = count;
+ }
+ return result;
+}
+
+static Ivar*
+compat_class_copyIvarList(Class cls, unsigned int* outCount)
+{
+ Ivar* list;
+ int i;
+ struct objc_ivar_list* ivars = cls->ivars;
+
+ if (ivars) {
+ list = malloc(sizeof(Ivar) * ivars->ivar_count);
+ if (list == NULL) {
+ return NULL;
+ }
+
+
+ for (i = 0; i < ivars->ivar_count; i++) {
+ list[i] = ivars->ivar_list + i;
+ }
+ *outCount = ivars->ivar_count;
+ return list;
+
+ } else {
+ list = malloc(1);
+ if (list == NULL) {
+ return NULL;
+ }
+
+ *outCount = 0;
+ return list;
+ }
+
+}
+
+static Protocol**
+compat_class_copyProtocolList(Class cls, unsigned int* outCount)
+{
+ Protocol** list;
+ unsigned int count = 0;
+ struct objc_protocol_list *protocol_list;
+
+ protocol_list = cls->protocols;
+ list = malloc(0);
+
+ while (protocol_list != NULL) {
+ list = realloc(list, (count + protocol_list->count)*sizeof(Protocol*));
+ if (list == NULL) {
+ /* Whoops, memory leak */
+ *outCount = 0;
+ return NULL;
+ }
+ memcpy(list + count, protocol_list->list, protocol_list->count*sizeof(Protocol*));
+ count += protocol_list->count;
+ protocol_list = protocol_list->next;
+ }
+
+ *outCount = count;
+ return list;
+}
+
+
+static const char*
+compat_class_getName(Class cls)
+{
+ return cls->name;
+}
+
+static Class
+compat_class_getSuperclass(Class cls)
+{
+ return cls->super_class;
+}
+
+static BOOL
+compat_class_addMethod(Class cls, SEL name, IMP imp, const char* types)
+{
+ struct objc_method_list* methodsToAdd;
+ struct objc_method* objcMethod;
+
+ methodsToAdd = malloc(sizeof(struct objc_method_list) +
+ 2*sizeof(struct objc_method));
+ methodsToAdd->method_count = 1;
+ methodsToAdd->obsolete = NULL;
+
+ objcMethod = methodsToAdd->method_list;
+ objcMethod->method_name = name;
+ objcMethod->method_imp = imp;
+ objcMethod->method_types = (char*)types;
+
+ class_addMethods(cls, methodsToAdd);
+ return YES; /* Have to return something ... */
+}
+
+static BOOL
+compat_preclass_addMethod(Class cls, SEL name, IMP imp, const char* types)
+{
+ /* Resize in-place, this is only valid during class construction. */
+ struct objc_method_list* new_list;
+ struct objc_method* objcMethod;
+
+ new_list = realloc(cls->methodLists[0],
+ sizeof(struct objc_method_list) +
+ (sizeof(struct objc_method
+ )*(cls->methodLists[0]->method_count+1)));
+ if (new_list == NULL) {
+ return NO;
+ }
+ cls->methodLists[0] = new_list;
+ objcMethod = new_list->method_list + (new_list->method_count)++;
+
+ objcMethod->method_name = name;
+ objcMethod->method_imp = imp;
+ objcMethod->method_types = strdup(types);
+ if (objcMethod == NULL) {
+ new_list->method_count--;
+ return NO;
+ }
+
+ return YES;
+}
+
+static BOOL
+compat_preclass_addIvar(
+ Class cls,
+ const char* name,
+ size_t size,
+ uint8_t align, const char* types)
+{
+ /* Update the class structure, only valid during class construction */
+ struct objc_ivar_list* new_ivars;
+ struct objc_ivar* ivar;
+
+ if (cls->ivars) {
+ new_ivars = realloc(cls->ivars,
+ sizeof(struct objc_ivar_list) +
+ ((cls->ivars->ivar_count+1) * sizeof(struct objc_ivar)));
+ } else {
+ new_ivars = malloc(
+ sizeof(struct objc_ivar_list) +
+ sizeof(struct objc_ivar));
+ new_ivars->ivar_count = 0;
+ }
+ if (new_ivars == NULL) {
+ return NO;
+ }
+ cls->ivars = new_ivars;
+ ivar = new_ivars->ivar_list + new_ivars->ivar_count;
+ ivar->ivar_name = strdup(name);
+ if (ivar->ivar_name == NULL) {
+ return NO;
+ }
+
+ ivar->ivar_type = strdup(types);
+ if (ivar->ivar_type == NULL) {
+ free(ivar->ivar_name);
+ return NO;
+ }
+
+ ivar->ivar_offset = cls->instance_size;
+ if (ivar->ivar_offset % align) {
+ ivar->ivar_offset += align - (ivar->ivar_offset % align);
+ }
+
+ new_ivars->ivar_count ++;
+ cls->instance_size = ivar->ivar_offset + size;
+ return YES;
+}
+
+static BOOL
+compat_preclass_addProtocol(Class cls, Protocol* protocol)
+{
+ struct objc_protocol_list* protocols;
+
+ if (cls->protocols) {
+ protocols = realloc(cls->protocols,
+ sizeof(struct objc_protocol_list) +
+ (sizeof(Protocol*)*(cls->protocols->count+1)));
+ } else {
+ protocols = malloc(sizeof(struct objc_protocol_list)
+ + sizeof(Protocol*));
+ protocols->count = 0;
+ protocols->next = NULL;
+ }
+ if (protocols == NULL) {
+ return NO;
+ }
+ cls->protocols = protocols;
+ protocols->list[protocols->count++] = protocol;
+ return YES;
+}
+
+static SEL
+compat_method_getName(Method m)
+{
+ return m->method_name;
+}
+
+static IMP
+compat_method_getImplementation(Method m)
+{
+ return m->method_imp;
+}
+
+static IMP
+compat_method_setImplementation(Method m, IMP imp)
+{
+ IMP result = m->method_imp;
+ m->method_imp = imp;
+ return result;
+}
+
+static const char *
+compat_method_getTypeEncoding(Method m)
+{
+ return m->method_types;
+}
+
+static BOOL
+compat_sel_isEqual(SEL lhs, SEL rhs)
+{
+ return lhs == rhs;
+}
+
+static const char*
+compat_ivar_getName(Ivar var)
+{
+ return var->ivar_name;
+}
+
+static const char*
+compat_ivar_getTypeEncoding(Ivar var)
+{
+ return var->ivar_type;
+}
+
+static ptrdiff_t
+compat_ivar_getOffset(Ivar var)
+{
+ return var->ivar_offset;
+}
+
+
+#ifndef NO_OBJC2_RUNTIME
+static BOOL
+objc20_class_addMethodList(Class cls,
+ struct PyObjC_method* list, unsigned int count)
+{
+ unsigned int i;
+ BOOL r;
+ Method m;
+
+ for (i = 0; i < count; i++) {
+ r = class_addMethod(cls,
+ list[i].name, list[i].imp, list[i].type);
+ if (!r) {
+ m = class_getInstanceMethod(cls, list[i].name);
+ if (m != NULL) {
+ method_setImplementation(m, list[i].imp);
+ } else {
+ return NO;
+ }
+ }
+ }
+ return YES;
+}
+#endif
+
+static BOOL
+compat_class_isMetaClass(Class cls)
+{
+ return CLS_GETINFO(cls, CLS_META) == CLS_META;
+}
+
+static BOOL
+compat_class_addMethodList(Class cls,
+ struct PyObjC_method* list, unsigned int count)
+{
+ unsigned int i;
+ struct objc_method_list* method_list;
+
+ method_list = malloc(
+ sizeof(struct objc_method_list) +
+ ((count+1) * sizeof(struct objc_method)));
+ if (method_list == NULL) {
+ return NO;
+ }
+ memset(method_list, 0,
+ sizeof(struct objc_method_list) +
+ ((count+1) * sizeof(struct objc_method)));
+
+ method_list->method_count = 0;
+ method_list->obsolete = 0;
+
+ for (i = 0; i < count; i++) {
+ method_list->method_list[i].method_name = list[i].name;
+ method_list->method_list[i].method_types = (char*)list[i].type;
+ method_list->method_list[i].method_imp = list[i].imp;
+ }
+ method_list->method_count = count;
+ class_addMethods(cls, method_list);
+ return YES;
+}
+
+static BOOL
+compat_protocol_conformsToProtocol(Protocol *proto, Protocol *other)
+{
+ return [proto conformsTo:other];
+}
+
+static const char *
+compat_protocol_getName(Protocol *p)
+{
+ return [p name];
+}
+
+static struct objc_method_description *
+compat_protocol_copyMethodDescriptionList(Protocol *p, BOOL isRequiredMethod, BOOL isInstanceMethod, unsigned int *outCount)
+{
+ if (!isRequiredMethod) {
+ *outCount = 0;
+ return NULL;
+ }
+
+ struct objc_method_description_list* list;
+
+ if (isInstanceMethod) {
+ list = ((ProtocolTemplate*)p)->instance_methods;
+ } else {
+ list = ((ProtocolTemplate*)p)->class_methods;
+ }
+
+ if (list == NULL || list->count == 0) {
+ *outCount = 0;
+ return NULL;
+ }
+
+ *outCount = list->count;
+ struct objc_method_description* result;
+
+ result = malloc(sizeof(struct objc_method_description) * list->count);
+ if (result == NULL) {
+ return NULL;
+ }
+
+ int i;
+ *outCount = 0;
+ for (i = 0; i < list->count; i++) {
+ if (list->list[i].name == NULL) continue;
+ result[*outCount++] = list->list[i];
+ }
+
+ return result;
+}
+
+static Protocol **
+compat_protocol_copyProtocolList(Protocol *proto, unsigned int *outCount)
+{
+ struct objc_protocol_list* list =
+ ((ProtocolTemplate*)proto)->protocol_list;
+
+ *outCount = 0;
+
+ struct objc_protocol_list* cur;
+ for (cur = list; cur != NULL; cur = cur->next) {
+ *outCount += cur->count;
+ }
+
+ Protocol** result = (Protocol**)malloc(sizeof(Protocol*) * *outCount);
+ if (result == NULL) {
+ return NULL;
+ }
+
+ unsigned curIdx = 0;
+ for (cur = list; cur != NULL; cur = cur->next) {
+ int i;
+ for (i = 0; i < cur->count; i++) {
+ if (cur->list[i] != NULL) {
+ result[curIdx++] = cur->list[i];
+ } else {
+ *outCount--;
+ }
+ }
+ }
+ return result;
+}
+
+static struct objc_method_description
+compat_protocol_getMethodDescription(Protocol *p, SEL aSel, BOOL isRequiredMethod, BOOL isInstanceMethod)
+{
+static struct objc_method_description empty_description = { NULL, NULL };
+ if (!isRequiredMethod) {
+ return empty_description;
+ }
+
+ struct objc_method_description* result;
+
+ if (isInstanceMethod) {
+ result = [p descriptionForInstanceMethod: aSel];
+ } else {
+ result = [p descriptionForClassMethod: aSel];
+ }
+
+ if (result == NULL) {
+ return empty_description;
+ } else {
+ return *result;
+ }
+}
+
+static id
+compat_object_getIvar(id obj, Ivar ivar)
+{
+ return *(id*)(((char*)obj) + ivar->ivar_offset);
+}
+static void
+compat_object_setIvar(id obj, Ivar ivar, id value)
+{
+ *(id*)(((char*)obj) + ivar->ivar_offset) = value;
+}
+
+/* Dispatch table */
+BOOL (*PyObjC_protocol_conformsToProtocol)(Protocol *proto, Protocol *other) = NULL;
+const char *(*PyObjC_protocol_getName)(Protocol *p) = NULL;
+struct objc_method_description *(*PyObjC_protocol_copyMethodDescriptionList)(Protocol *p, BOOL isRequiredMethod, BOOL isInstanceMethod, unsigned int *outCount) = NULL;
+Protocol **(*PyObjC_protocol_copyProtocolList)(Protocol *proto, unsigned int *outCount) = NULL;
+struct objc_method_description (*PyObjC_protocol_getMethodDescription)(Protocol *p, SEL aSel, BOOL isRequiredMethod, BOOL isInstanceMethod) = NULL;
+
+id (*PyObjC_object_getIvar)(id obj, Ivar ivar) = NULL;
+void (*PyObjC_object_setIvar)(id obj, Ivar ivar, id value) = NULL;
+
+
+
+Class (*PyObjC_objc_allocateClassPair)(Class, const char*, size_t) = NULL;
+void (*PyObjC_objc_registerClassPair)(Class) = NULL;
+void (*PyObjC_objc_disposeClassPair)(Class) = NULL;
+Protocol** (*PyObjC_objc_copyProtocolList)(unsigned int*) = NULL;
+
+BOOL (*PyObjC_preclass_addMethod)(Class, SEL, IMP, const char*) = NULL;
+BOOL (*PyObjC_preclass_addIvar)(Class cls,
+ const char *name, size_t size, uint8_t alignment,
+ const char *types) = NULL;
+BOOL (*PyObjC_preclass_addProtocol)(Class cls, Protocol *protocol) = NULL;
+
+
+Class (*PyObjC_object_getClass)(id obj) = NULL;
+Class (*PyObjC_object_setClass)(id obj, Class cls) = NULL;
+const char* (*PyObjC_object_getClassName)(id obj) = NULL;
+
+Method* (*PyObjC_class_copyMethodList)(Class, unsigned int*) = NULL;
+const char* (*PyObjC_class_getName)(Class) = NULL;
+Class (*PyObjC_class_getSuperclass)(Class) = NULL;
+BOOL (*PyObjC_class_addMethod)(Class, SEL, IMP, const char*) = NULL;
+BOOL (*PyObjC_class_addMethodList)(Class,
+ struct PyObjC_method*, unsigned int) = NULL;
+Ivar* (*PyObjC_class_copyIvarList)(Class, unsigned int*) = NULL;
+Protocol** (*PyObjC_class_copyProtocolList)(Class, unsigned int*) = NULL;
+BOOL (*PyObjC_class_isMetaClass)(Class) = NULL;
+
+SEL (*PyObjC_method_getName)(Method m) = NULL;
+IMP (*PyObjC_method_getImplementation)(Method m) = NULL;
+IMP (*PyObjC_method_setImplementation)(Method m, IMP imp) = NULL;
+const char *(*PyObjC_method_getTypeEncoding)(Method m) = NULL;
+
+BOOL (*PyObjC_sel_isEqual)(SEL, SEL) = NULL;
+
+size_t (*PyObjC_methodlist_magic)(Class cls);
+
+const char* (*PyObjC_ivar_getName)(Ivar) = NULL;
+const char* (*PyObjC_ivar_getTypeEncoding)(Ivar) = NULL;
+ptrdiff_t (*PyObjC_ivar_getOffset)(Ivar) = NULL;
+
+
+
+void PyObjC_SetupRuntimeCompat(void)
+{
+#ifdef NO_OBJC2_RUNTIME
+ /*
+ * Don't use ObjC 2.0 runtime (compiling on 10.4 or earlier), always
+ * use the compat implementation.
+ */
+ PyObjC_class_addMethodList = compat_class_addMethodList;
+ PyObjC_methodlist_magic = compat_methodlist_magic;
+ PyObjC_objc_disposeClassPair = compat_objc_disposeClassPair;
+ PyObjC_preclass_addMethod = compat_preclass_addMethod;
+ PyObjC_preclass_addIvar = compat_preclass_addIvar;
+ PyObjC_preclass_addProtocol = compat_preclass_addProtocol;
+
+# define SETUP(funcname) \
+ PyObjC_##funcname = compat_##funcname
+
+#else
+ if (class_addMethod) {
+ PyObjC_class_addMethodList = objc20_class_addMethodList;
+ PyObjC_preclass_addMethod = class_addMethod;
+ PyObjC_preclass_addIvar = class_addIvar;
+ PyObjC_preclass_addProtocol= class_addProtocol;
+ } else {
+ PyObjC_class_addMethodList = compat_class_addMethodList;
+ PyObjC_preclass_addMethod = compat_preclass_addMethod;
+ PyObjC_preclass_addIvar = compat_preclass_addIvar;
+ PyObjC_preclass_addProtocol= compat_preclass_addProtocol;
+ }
+
+
+ if (class_copyMethodList) {
+ PyObjC_methodlist_magic = objc20_methodlist_magic;
+ } else {
+ PyObjC_methodlist_magic = compat_methodlist_magic;
+ }
+
+# define SETUP(funcname) \
+ if (funcname == NULL) { \
+ PyObjC_##funcname = compat_##funcname; \
+ } else { \
+ PyObjC_##funcname = funcname; \
+ }
+#endif
+ SETUP(protocol_getName);
+ SETUP(protocol_conformsToProtocol);
+ SETUP(protocol_copyMethodDescriptionList);
+ SETUP(protocol_copyProtocolList);
+ SETUP(protocol_getMethodDescription);
+
+ SETUP(objc_allocateClassPair);
+ SETUP(objc_registerClassPair);
+ SETUP(objc_disposeClassPair);
+ SETUP(objc_copyProtocolList);
+
+ SETUP(object_getClass);
+ SETUP(object_setClass);
+ SETUP(object_getClassName);
+ SETUP(object_getIvar);
+ SETUP(object_setIvar);
+
+ SETUP(class_getSuperclass);
+ SETUP(class_addMethod);
+ SETUP(class_copyIvarList);
+ SETUP(class_copyProtocolList);
+ SETUP(class_copyMethodList);
+ SETUP(class_getName);
+ SETUP(class_isMetaClass);
+
+ SETUP(method_getName);
+ SETUP(method_getTypeEncoding);
+ SETUP(method_getImplementation);
+ SETUP(method_setImplementation);
+
+ SETUP(sel_isEqual);
+
+ SETUP(ivar_getName);
+ SETUP(ivar_getTypeEncoding);
+ SETUP(ivar_getOffset);
+#undef SETUP
+
+}
+
+#else
+
+BOOL PyObjC_class_addMethodList(Class cls,
+ struct PyObjC_method* list, unsigned int count)
+{
+ unsigned int i;
+ BOOL r;
+ Method m;
+
+ for (i = 0; i < count; i++) {
+ /*
+ * XXX: First try class_addMethod, if that fails assume this is
+ * because the method already exists in the class.
+ * Strictly speaking this isn't correct, but this is the best
+ * we can do through the 2.0 API (see 4809039 in RADAR)
+ */
+ r = class_addMethod(cls,
+ list[i].name, list[i].imp, list[i].type);
+ if (!r) {
+ m = class_getInstanceMethod(cls, list[i].name);
+ if (m != NULL) {
+ method_setImplementation(m, list[i].imp);
+ } else {
+ return NO;
+ }
+ }
+ }
+ return YES;
+}
+
+size_t PyObjC_methodlist_magic(Class cls)
+{
+ /* This is likely to be much slower than compat_methodlist_magic,
+ * but should works on the 64-bit runtime. Hopefully a callback will
+ * be added to the 2.0 runtime that will take away the need for this
+ * function...
+ */
+ Method* methods;
+ unsigned int count;
+
+ methods = class_copyMethodList(cls, &count);
+#if 0
+ unsigned int i;
+ size_t result;
+ result = 0;
+ for (i = 0; i < count; i++) {
+ result = (1000003*result) ^ ((size_t)(
+ method_getImplementation(methods[i])) >> 3);
+ }
+ result = result | (count << 16);
+ free(methods);
+ return result;
+#endif
+ free(methods);
+ return (size_t)count;
+}
+
+#endif
+
+#if defined(__x86_64__)
+
+@implementation Protocol (NSOBjectCompat)
+- self
+{
+ return self;
+}
+@end
+
+@implementation Object (NSOBjectCompat)
+- self
+{
+ return self;
+}
+
+-doesNotRecognizeSelector:(SEL)sel
+{
+ printf("--> %s\n", sel_getName(sel));
+ abort();
+}
+@end
+
+
+#endif