diff options
Diffstat (limited to 'Objective-C/PyObjC')
-rw-r--r-- | Objective-C/PyObjC/libffi_support.h | 21 | ||||
-rw-r--r-- | Objective-C/PyObjC/libffi_support.m | 401 | ||||
-rw-r--r-- | Objective-C/PyObjC/objc-runtime-apple.h | 137 | ||||
-rw-r--r-- | Objective-C/PyObjC/objc-runtime-apple.m | 159 | ||||
-rw-r--r-- | Objective-C/PyObjC/objc-runtime-gnu.h | 174 | ||||
-rw-r--r-- | Objective-C/PyObjC/objc-runtime-gnu.m | 217 | ||||
-rw-r--r-- | Objective-C/PyObjC/objc_support.h | 46 | ||||
-rw-r--r-- | Objective-C/PyObjC/objc_support.m | 505 | ||||
-rw-r--r-- | Objective-C/PyObjC/pyobjc.h | 46 |
9 files changed, 1706 insertions, 0 deletions
diff --git a/Objective-C/PyObjC/libffi_support.h b/Objective-C/PyObjC/libffi_support.h new file mode 100644 index 0000000..ca04c6b --- /dev/null +++ b/Objective-C/PyObjC/libffi_support.h @@ -0,0 +1,21 @@ +#ifndef PyObjC_FFI_SUPPORT_H +#define PyObjC_FFI_SUPPORT_H + +#ifdef USE_LIBFFI +#ifdef HAVE_FFI_H +#include <ffi.h> +#elif HAVE_FFI_FFI_H +#include <ffi/ffi.h> +#else +/* We are using our own build of libffi. */ +#include <ffi.h> +#endif +#endif + +ffi_type* +objcl_pyobjc_signature_to_ffi_return_type (const char* argtype); + +ffi_type* +objcl_pyobjc_arg_signature_to_ffi_type (const char* argtype); + +#endif /* PyObjC_FFI_SUPPORT_H */ diff --git a/Objective-C/PyObjC/libffi_support.m b/Objective-C/PyObjC/libffi_support.m new file mode 100644 index 0000000..4bc1137 --- /dev/null +++ b/Objective-C/PyObjC/libffi_support.m @@ -0,0 +1,401 @@ +/* + * Support for libffi (http://sources.redhat.com/libffi) + * + * libffi is a library that makes it possible to dynamicly create calls + * to C functions (without knowing the signature at compile-time). It also + * provides a way to create closures, that is dynamicly create functions with + * a runtime specified interface. + * + * This file contains functions to dynamicly call objc_msgSendSuper and to + * dynamicly create IMPs for use in Objective-C method dispatch tables. The + * file 'register.m' contains compile-time generated equivalents of these. + */ +#include "pyobjc.h" + +#import <Foundation/NSDictionary.h> +#import <Foundation/NSString.h> +#import <Foundation/NSHost.h> + +#ifdef MACOSX +/* + * Define SMALL_STRUCT_LIMIT as the largest struct that will be returned + * in registers instead of with a hidden pointer argument. + */ + +#if defined(__ppc__) + +# define SMALL_STRUCT_LIMIT 4 + +#elif defined(__i386__) + +# define SMALL_STRUCT_LIMIT 8 + +#else + +# error "Unsupported MACOSX platform" + +#endif + +#endif /* MACOSX */ + + + +#if 0 /* Usefull during debugging, only used in the debugger */ +static void describe_ffitype(ffi_type* type) +{ + switch (type->type) { + case FFI_TYPE_VOID: printf("%s", "void"); break; + case FFI_TYPE_INT: printf("%s", "int"); break; + case FFI_TYPE_FLOAT: printf("%s", "float"); break; + case FFI_TYPE_DOUBLE: printf("%s", "double"); break; + case FFI_TYPE_UINT8: printf("%s", "uint8"); break; + case FFI_TYPE_SINT8: printf("%s", "sint8"); break; + case FFI_TYPE_UINT16: printf("%s", "uint16"); break; + case FFI_TYPE_SINT16: printf("%s", "sint16"); break; + case FFI_TYPE_UINT32: printf("%s", "uint32"); break; + case FFI_TYPE_SINT32: printf("%s", "sint32"); break; + case FFI_TYPE_UINT64: printf("%s", "uint64"); break; + case FFI_TYPE_SINT64: printf("%s", "sint64"); break; + case FFI_TYPE_POINTER: printf("%s", "*"); break; + case FFI_TYPE_STRUCT: { + ffi_type** elems = type->elements; + + printf("%s", "struct { "); + if (elems) { + while (*elems) { + describe_ffitype(*(elems++)); + printf("%s", "; "); + } + } + printf("%s", "}"); + } + break; + + default: + // Don't abort, this is called from the debugger + printf("?(%d)", type->type); + } +} + +static void describe_cif(ffi_cif* cif) +{ + size_t i; + printf("<ffi_cif abi=%d nargs=%d bytes=%d flags=%#x args=[", + cif->abi, cif->nargs, cif->bytes, cif->flags); + for (i = 0; i < cif->nargs; i++) { + describe_ffitype(cif->arg_types[i]); + printf("%s", ", "); + } + printf("%s", "] rettype="); + describe_ffitype(cif->rtype); + printf("%s", ">\n"); +} + +#endif + + +static Py_ssize_t +num_struct_fields(const char* argtype) +{ + Py_ssize_t res = 0; + + if (*argtype != _C_STRUCT_B) return -1; + while (*argtype != _C_STRUCT_E && *argtype != '=') argtype++; + if (*argtype == _C_STRUCT_E) return 0; + + argtype++; + while (*argtype != _C_STRUCT_E) { + argtype = PyObjCRT_SkipTypeSpec(argtype); + if (argtype == NULL) return -1; + res ++; + } + return res; +} + + +static void +free_type(void *obj) +{ + PyMem_Free(((ffi_type*)obj)->elements); + PyMem_Free(obj); +} + +static ffi_type* signature_to_ffi_type(const char* argtype); + +static ffi_type* +array_to_ffi_type(const char* argtype) +{ + static NSMutableDictionary* array_types = nil; + NSValue *v; + ffi_type* type; + Py_ssize_t field_count; + Py_ssize_t i; + const NSString* key = [NSString stringWithUTF8String: argtype]; + + if (array_types == NULL || array_types == nil) { + array_types = [NSMutableDictionary dictionaryWithCapacity: 100]; + if (array_types == NULL || array_types == nil) return NULL; + } + + v = [array_types objectForKey: key]; + if (v != nil) { + return (ffi_type*)[v pointerValue]; + } + + /* We don't have a type description yet, dynamicly + * create it. + */ + field_count = atoi(argtype+1); + + type = PyMem_Malloc(sizeof(*type)); + if (type == NULL) { + PyErr_NoMemory(); + return NULL; + } + type->size = PyObjCRT_SizeOfType(argtype); + type->alignment = PyObjCRT_AlignOfType(argtype); + + /* Libffi doesn't really know about arrays as part of larger + * data-structres (e.g. struct foo { int field[3]; };). We fake it + * by treating the nested array as a struct. This seems to work + * fine on MacOS X. + */ + type->type = FFI_TYPE_STRUCT; + type->elements = PyMem_Malloc((1+field_count) * sizeof(ffi_type*)); + if (type->elements == NULL) { + PyMem_Free(type); + PyErr_NoMemory(); + return NULL; + } + + while (isdigit(*++argtype)); + type->elements[0] = signature_to_ffi_type(argtype); + for (i = 1; i < field_count; i++) { + type->elements[i] = type->elements[0]; + } + type->elements[field_count] = 0; + + v = [NSValue valueWithPointer: type]; + if (v == NULL || v == nil) { + free_type(type); + return NULL; + } + + NS_DURING + { + [array_types setObject: v forKey: key]; + } + NS_HANDLER + { + NS_VALUERETURN (NULL, ffi_type*); + } + NS_ENDHANDLER + + return type; +} + +static ffi_type* +struct_to_ffi_type(const char* argtype) +{ + static NSMutableDictionary* struct_types = nil; + NSValue* v; + ffi_type* type; + Py_ssize_t field_count; + const char* curtype; + const NSString* key = [NSString stringWithUTF8String: argtype]; + + if (struct_types == NULL || struct_types == nil) { + struct_types = [NSMutableDictionary dictionaryWithCapacity: 100]; + if (struct_types == NULL || struct_types == nil) return NULL; + } + + v = [struct_types objectForKey: key]; + if (v != nil) { + return (ffi_type*)[v pointerValue]; + } + + /* We don't have a type description yet, dynamicly + * create it. + */ + field_count = num_struct_fields(argtype); + if (field_count == -1) { +#ifdef STRICT_TYPE_PARSING + [[NSException exceptionWithName: @"PyObjCExc_InternalError" + reason: [NSString stringWithFormat: @"Cannot determine layout of %s", argtype] + userInfo: NULL] raise]; +#else + NSLog (@"PyObjCExc_InternalError: Cannot determine layout of %s", argtype); +#endif + return NULL; + } + + type = PyMem_Malloc(sizeof(*type)); + if (type == NULL) { + PyErr_NoMemory(); + return NULL; + } + type->size = PyObjCRT_SizeOfType(argtype); + type->alignment = PyObjCRT_AlignOfType(argtype); + type->type = FFI_TYPE_STRUCT; + type->elements = PyMem_Malloc((1+field_count) * sizeof(ffi_type*)); + if (type->elements == NULL) { + PyMem_Free(type); + PyErr_NoMemory(); + return NULL; + } + + field_count = 0; + curtype = argtype+1; + while (*curtype != _C_STRUCT_E && *curtype != '=') curtype++; + if (*curtype == '=') { + curtype ++; + while (*curtype != _C_STRUCT_E) { + type->elements[field_count] = + signature_to_ffi_type(curtype); + if (type->elements[field_count] == NULL) { + PyMem_Free(type->elements); + return NULL; + } + field_count++; + curtype = PyObjCRT_SkipTypeSpec(curtype); + if (curtype == NULL) { + PyMem_Free(type->elements); + return NULL; + } + } + } + type->elements[field_count] = NULL; + + v = [NSValue valueWithPointer: type]; + if (v == NULL || v == nil) { + free_type(type); + return NULL; + } + + NS_DURING + { + [struct_types setObject: v forKey: key]; + } + NS_HANDLER + { + NS_VALUERETURN (NULL, ffi_type*); + } + NS_ENDHANDLER + + return type; +} + +ffi_type* +objcl_pyobjc_signature_to_ffi_return_type(const char* argtype) +{ + switch (*argtype) { + case _C_CHR: case _C_SHT: + return &ffi_type_sint; + case _C_UCHR: case _C_USHT: + return &ffi_type_uint; +#ifdef _C_BOOL + case _C_BOOL: return &ffi_type_sint; +#endif + default: + return signature_to_ffi_type(argtype); + } +} + + +static ffi_type* +signature_to_ffi_type(const char* argtype) +{ + switch (*argtype) { + case _C_VOID: return &ffi_type_void; + case _C_ID: return &ffi_type_pointer; + case _C_CLASS: return &ffi_type_pointer; + case _C_SEL: return &ffi_type_pointer; + case _C_CHR: return &ffi_type_schar; +#ifdef _C_BOOL + case _C_BOOL: return &ffi_type_sint; +#endif + case _C_UCHR: return &ffi_type_uchar; + case _C_SHT: return &ffi_type_sshort; + case _C_USHT: return &ffi_type_ushort; + case _C_INT: return &ffi_type_sint; + case _C_UINT: return &ffi_type_uint; + + /* The next to defintions are incorrect, but the correct definitions + * don't work (e.g. give testsuite failures). We should be fine + * as long as sizeof(long) == sizeof(int) + */ + case _C_LNG: return &ffi_type_sint; /* ffi_type_slong */ + case _C_ULNG: return &ffi_type_uint; /* ffi_type_ulong */ + case _C_LNGLNG: return &ffi_type_sint64; + case _C_ULNGLNG: return &ffi_type_uint64; + case _C_FLT: return &ffi_type_float; + case _C_DBL: return &ffi_type_double; + case _C_CHARPTR: return &ffi_type_pointer; + case _C_PTR: return &ffi_type_pointer; + case _C_ARY_B: + return array_to_ffi_type(argtype); + case _C_IN: case _C_OUT: case _C_INOUT: case _C_CONST: + return signature_to_ffi_type(argtype+1); + case _C_STRUCT_B: + return struct_to_ffi_type(argtype); + default: +#ifdef STRICT_TYPE_PARSING + [[NSException exceptionWithName: @"PyExc_NotImplementedError" + reason: [NSString stringWithFormat: @"Type '%c' not supported", *argtype] + userInfo: NULL] raise]; +#else + NSLog (@"PyExc_NotImplementedError: Type '%#x' not supported", *argtype); +#endif + return NULL; + } +} + +/* + * arg_signature_to_ffi_type: Make the ffi_type for the call to the method IMP, + * on MacOS X this is the same as the normal signature_to_ffi_type, but on + * Linux/GNUstep we need a slightly different function. + */ +#ifdef MACOSX + +#ifdef __ppc__ +ffi_type* +objcl_pyobjc_arg_signature_to_ffi_type(const char* argtype) +{ + return signature_to_ffi_type (argtype); +} + +#else +ffi_type* +objcl_pyobjc_arg_signature_to_ffi_type(const char* argtype) +{ + /* NOTE: This is the minimal change to pass the unittests, it is not + * based on analysis of the calling conventions. + */ + switch (*argtype) { + case _C_CHR: return &ffi_type_sint; + case _C_UCHR: return &ffi_type_uint; + case _C_SHT: return &ffi_type_sint; + case _C_USHT: return &ffi_type_uint; + default: return signature_to_ffi_type(argtype); + } +} +#endif + +#else /* GNUstep */ + +ffi_type* +objcl_pyobjc_arg_signature_to_ffi_type(const char* argtype) +{ + /* NOTE: This is the minimal change to pass the unittests, it is not + * based on analysis of the calling conventions. + */ + switch (*argtype) { + case _C_CHR: return &ffi_type_sint; + case _C_UCHR: return &ffi_type_uint; + case _C_SHT: return &ffi_type_sint; + case _C_USHT: return &ffi_type_uint; + default: return signature_to_ffi_type(argtype); + } +} + +#endif /* GNUstep */ diff --git a/Objective-C/PyObjC/objc-runtime-apple.h b/Objective-C/PyObjC/objc-runtime-apple.h new file mode 100644 index 0000000..8d050a1 --- /dev/null +++ b/Objective-C/PyObjC/objc-runtime-apple.h @@ -0,0 +1,137 @@ +/* Copyright (c) 1996,97,98 by Lele Gaifax. All Rights Reserved + * Copyright (c) 2003 Ronald Oussoren + * + * This software may be used and distributed freely for any purpose + * provided that this notice is included unchanged on any and all + * copies. The author does not warrant or guarantee this software in + * any way. + * + * This file is part of the PyObjC package. + * + * RCSfile: objc_support.h,v + * Revision: 1.16 + * Date: 1998/08/18 15:35:57 + * + * Created Tue Sep 10 14:11:38 1996. + */ + +#ifndef PyObjC_RUNTIME_APPLE_H +#define PyObjC_RUNTIME_APPLE_H + +#import <Foundation/NSObject.h> +#import <Foundation/NSString.h> + +#include <objc/objc-runtime.h> +#include <objc/Protocol.h> + +#include <string.h> +#include <stdlib.h> +#include <assert.h> +#include <ctype.h> + +static inline int +PyObjCRT_SameSEL(SEL a, SEL b) +{ + return a == b; +} + +static inline const char* +PyObjCRT_SELName(SEL sel) +{ + return sel_getName(sel); +} + +static inline SEL +PyObjCRT_SELUID(const char* str) +{ + return sel_getUid(str); +} + +static inline Class +PyObjCRT_LookUpClass(const char* name) +{ + return objc_lookUpClass(name); +} + +static inline struct objc_method_list * +PyObjCRT_NextMethodList(Class c, void ** p) +{ + return class_nextMethodList(c, p); +} + +static inline void +PyObjCRT_InitMethod(Method m, SEL name, const char* types, IMP imp) +{ + memset(m, 0, sizeof(*m)); + m->method_name = name; + m->method_types = strdup((char*)types); + m->method_imp = imp; +} + +static inline void +PyObjCRT_ClassAddMethodList(Class cls, struct objc_method_list* lst) +{ + class_addMethods(cls, lst); +} + + +extern struct objc_method_list* PyObjCRT_AllocMethodList(ssize_t); +extern struct objc_protocol_list* PyObjCRT_AllocProtocolList(ssize_t); + +typedef Method PyObjCRT_Method_t; +typedef Ivar PyObjCRT_Ivar_t; + +#define GETISA(c) ((c)->isa) + +#define RECEIVER(c) ((c).receiver) + +#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_LNGLNG 'q' +#define _C_ULNGLNG 'Q' +#define _C_BOOL 'B' /* (Objective-)C++ 'bool' */ + + +/* Return a number that is likely to change when the method list changes, + * and is cheap to compute. + */ +static inline int +objc_methodlist_magic(Class cls) +{ + int res = 0; + int cnt = 0; + + /* This is the documented way of enumerating the method list. It + * is slower than the obvious way, but does not explode under + * esoteric situations. + */ + void *iterator = NULL; + struct objc_method_list *mlist; + + if (cls == NULL) return -1; + + while ( (mlist = class_nextMethodList( cls, &iterator )) != NULL ) { + res += mlist->method_count; + cnt++; + } + + return (cnt << 16) | (res & 0xFFFF); +} + +static inline const char * +get_selector_encoding (id self, SEL sel) +{ + struct objc_method* m = class_getInstanceMethod(self->isa, sel); + + if (!m) { + return NULL; + } else { + return m->method_types; + } +} + +#endif /* PyObjC_RUNTIME_APPLE_H */ diff --git a/Objective-C/PyObjC/objc-runtime-apple.m b/Objective-C/PyObjC/objc-runtime-apple.m new file mode 100644 index 0000000..b2888ac --- /dev/null +++ b/Objective-C/PyObjC/objc-runtime-apple.m @@ -0,0 +1,159 @@ +/* This file is part of the PyObjC package. */ +/* + * Support code for the Apple runtime + */ +#include "pyobjc.h" + +#if defined(APPLE_RUNTIME) +#include "objc-runtime-apple.h" + +int PyObjCRT_SetupClass( + Class cls, + Class metaCls, + const char*name, + Class superCls, + Class rootCls, + ssize_t ivarSize, + struct objc_ivar_list* ivarList, + struct objc_protocol_list* protocolList +) + +{ + /* Initialize the structure */ + memset(cls, 0, sizeof(*cls)); + memset(metaCls, 0, sizeof(*cls)); + + cls->methodLists = NULL; + metaCls->methodLists = NULL; + cls->isa = metaCls; + + cls->info = CLS_CLASS; // |CLS_METHOD_ARRAY; + metaCls->info = CLS_META; // |CLS_METHOD_ARRAY; + + cls->name = strdup(name); + if (cls->name == NULL) { + return -1; + } + metaCls->name = strdup(name); + if (metaCls->name == NULL) { + free((char*)(cls->name)); + cls->name = NULL; + return -1; + } + + cls->methodLists = malloc(sizeof(struct objc_method_list*)); + if (cls->methodLists == NULL) { + PyErr_NoMemory(); + free((char*)(cls->name)); + cls->name = NULL; + free((char*)(metaCls->name)); + metaCls->name = NULL; + return -1; + } + memset(cls->methodLists, 0, sizeof(*(cls->methodLists))); + + metaCls->methodLists = malloc(sizeof(struct objc_method_list*)); + if (cls->methodLists == NULL) { + PyErr_NoMemory(); + free((char*)(cls->name)); + cls->name = NULL; + free((char*)(metaCls->name)); + metaCls->name = NULL; + free(cls->methodLists); + cls->methodLists = NULL; + return -1; + } + memset(metaCls->methodLists, 0, sizeof(*(metaCls->methodLists))); + + /* + * 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 + */ + cls->methodLists[0] = (struct objc_method_list*)-1; + metaCls->methodLists[0] = (struct objc_method_list*)-1; + + cls->super_class = superCls; + metaCls->super_class = superCls->isa; + metaCls->isa = rootCls->isa; + + cls->instance_size = ivarSize; + cls->ivars = ivarList; + + metaCls->instance_size = metaCls->super_class->instance_size; + metaCls->ivars = NULL; + + metaCls->protocols = cls->protocols = protocolList; + + return 0; +} + +void PyObjCRT_ClearClass(Class cls) +{ + if (cls->methodLists) { + if (cls->methodLists) { + struct objc_method_list** cur; + + cur = cls->methodLists; + while (*cur != (struct objc_method_list*)-1) { + if (*cur != NULL) { + free(*cur); + *cur = NULL; + } + cur++; + } + free(cls->methodLists); + cls->methodLists = NULL; + } + cls->methodLists = NULL; + } + + if (cls->name) { + free((char*)(cls->name)); + } +} + +struct objc_method_list *PyObjCRT_AllocMethodList(ssize_t numMethods) +{ + struct objc_method_list *mlist; + + mlist = malloc(sizeof(struct objc_method_list) + + ((numMethods+1) * sizeof(struct objc_method))); + + if (mlist == NULL) { + return NULL; + } + + mlist->method_count = 0; + mlist->obsolete = NULL; + + return mlist; +} + +struct objc_protocol_list* PyObjCRT_AllocProtocolList(ssize_t numProtocols) +{ + struct objc_protocol_list *plist; + + plist = malloc(sizeof(struct objc_protocol_list) + + ((numProtocols+1) * sizeof(Protocol *))); + + if (plist == NULL) { + return NULL; + } + + plist->count = 0; + plist->next = NULL; + + return plist; +} + +#else /* !APPLE_RUNTIME */ + +static int dummy __attribute__((__unused__)); + +#endif /* !APPLE_RUNTIME */ diff --git a/Objective-C/PyObjC/objc-runtime-gnu.h b/Objective-C/PyObjC/objc-runtime-gnu.h new file mode 100644 index 0000000..5c87b6d --- /dev/null +++ b/Objective-C/PyObjC/objc-runtime-gnu.h @@ -0,0 +1,174 @@ +#ifndef PyObjC_RUNTIME_GNU_H +#define PyObjC_RUNTIME_GNU_H + +/* + * Specific support for the GNU Objective-C runtime + */ + +#include <Foundation/NSException.h> +#include <Foundation/NSString.h> + +#define objc_msgSendSuper(super, op, args...) \ + ((super)->self == NULL \ + ? 0 \ + : ( \ + class_get_instance_method( \ + (super)->class, (op) \ + )->method_imp)( \ + (super)->self, \ + (op) ,##args)) + + +/* + * XXX: AFAIK as I (Ronald) know, there should be an include named + * <objc/runtime.h> on systems with the GNU runtime. However, this file + * not present on my Linux playmachine (running Debian testing)... + * + * The alternative is to declare some prototypes ourselves... + */ +#if 0 +# include <objc/runtime.h> +#else + extern void class_add_method_list(Class, MethodList_t); + extern void __objc_add_class_to_hash(Class); +#endif + + +#ifndef nil +#define nil NULL +#endif + +/* What we call _C_LNGLNG is actually _C_LNG_LNG in the GNU runtime */ +#define _C_LNGLNG _C_LNG_LNG +#define _C_ULNGLNG _C_ULNG_LNG + +/* XXX: names don't conform to the coding-style! */ +extern Ivar_t class_getInstanceVariable(Class aClass, const char *name); +extern Ivar_t object_getInstanceVariable(id obj, const char *name, void **out); +extern Ivar_t object_setInstanceVariable(id obj, const char *name, void *value); +extern void objc_addClass(Class aClass); +//extern id objc_msgSendSuper(struct objc_super *super, SEL op, ...); +extern void objc_freeMethodList(struct objc_method_list *list); + +static inline int PyObjCRT_SameSEL(SEL a, SEL b) +{ + return sel_eq(a, b); +} + + +static inline const char* +PyObjCRT_SELName(SEL sel) +{ + return sel_get_name(sel); +} + +static inline SEL +PyObjCRT_SELUID(const char* str) +{ + return sel_get_uid(str); +} + +static inline void +PyObjCRT_ClassAddMethodList(Class cls, MethodList_t lst) +{ + int i; + + /* First convert the method_names to strings, class_add_method_list + * assumes the method_names are strings and converts these back + * to selectors. + */ + for (i = 0; i < lst->method_count; i++) { + lst->method_list[i].method_name = (SEL)PyObjCRT_SELName(lst->method_list[i].method_name); + } + + class_add_method_list(cls, lst); +} + +static inline Class +PyObjCRT_LookUpClass(const char* name) +{ + return objc_lookup_class(name); +} + +static inline struct objc_method_list * +PyObjCRT_NextMethodList(Class c, void ** p) +{ + if (*p == 0) { + *p = c->methods; + } else { + *p = (*((MethodList_t*)p))->method_next; + } + return *(MethodList_t*)p; +} + +static inline void +PyObjCRT_InitMethod(Method_t m, SEL name, const char* types, IMP imp) +{ + /* XXX: With some versions of the GNU runtime, the runtime assumes + * that method_name is initialy a string instead of a selector, other + * versions do not. The version on my development box currently + * doesn't. + * + * m->method_name = (SEL)PyObjCRT_SELName(name); + */ + m->method_name = name; + m->method_types = types; + m->method_imp = imp; +} + + +extern MethodList_t PyObjCRT_AllocMethodList(ssize_t); +extern struct objc_protocol_list* PyObjCRT_AllocProtocolList(ssize_t); + + +typedef Method_t PyObjCRT_Method_t; +typedef Ivar_t PyObjCRT_Ivar_t; + +static inline Class GETISA(id obj) +{ + return obj->class_pointer; +} + +//#define GETISA(c) (*((struct objc_object**)&(c))->class_pointer) +#define CLS_CLASS _CLS_CLASS +#define CLS_META _CLS_META +#define RECEIVER(c) (c).self + +static inline const char * +get_selector_encoding (id self, SEL sel) +{ + return sel->sel_types; +} + + + +extern void PyObjCRT_AddClass(Class cls); +#define objc_addClass PyObjCRT_AddClass + +/* Return a number that is likely to change when the method list changes, + * and is cheap to compute. + */ +static inline int +objc_methodlist_magic(Class cls) +{ + struct objc_method_list *mlist; + int res, cnt; + void *iterator = 0; + + res = cnt = 0; + + if (cls == NULL) + return -1; + + while ((mlist = PyObjCRT_NextMethodList(cls, &iterator))) + { + res += mlist->method_count; + cnt ++; + } + + return (cnt << 16) | (res & 0xFFFF); +} + + + +#endif /* PyObjC_RUNTIME_GNU_H */ diff --git a/Objective-C/PyObjC/objc-runtime-gnu.m b/Objective-C/PyObjC/objc-runtime-gnu.m new file mode 100644 index 0000000..df868e4 --- /dev/null +++ b/Objective-C/PyObjC/objc-runtime-gnu.m @@ -0,0 +1,217 @@ +/* This file is part of the PyObjC package. */ +/* + * Support code for the GNU runtime + * + * NOTE: This file uses some private functions in the GNU runtime as that seems + * to be the only way to properly interface with that runtime. + */ +#include "pyobjc.h" + +#if defined(GNU_RUNTIME) +#include "objc-runtime-gnu.h" + +struct objc_protocol_list* PyObjCRT_AllocProtocolList(int numProtocols) +{ + struct objc_protocol_list *plist; + + plist = malloc(sizeof(struct objc_protocol_list) + + ((numProtocols+1) * sizeof(Protocol *))); + + if (plist == NULL) { + return NULL; + } + + plist->count = 0; + plist->next = NULL; + + return plist; +} + +int PyObjCRT_SetupClass( + Class cls, + Class metaCls, + const char*name, + Class superCls, + Class rootCls, + int ivarSize, + struct objc_ivar_list* ivarList, + struct objc_protocol_list* protocolList +) + +{ + /* This is a private function, but seems to be the only way to + * really create the class. + */ + extern void __objc_install_premature_dtable (Class); + + /* Initialize the structure */ + memset(cls, 0, sizeof(*cls)); + memset(metaCls, 0, sizeof(*cls)); + + cls->version = 0; + metaCls->version = 0; + cls->subclass_list = NULL; + metaCls->subclass_list = NULL; + cls->sibling_class = NULL; + metaCls->sibling_class = NULL; + + cls->methods = NULL; + metaCls->methods = NULL; + cls->class_pointer = metaCls; + + cls->info = CLS_CLASS; + metaCls->info = CLS_META; + + cls->name = strdup(name); + if (cls->name == NULL) { + return -1; + } + metaCls->name = strdup(name); + if (metaCls->name == NULL) { + free((char*)(cls->name)); + cls->name = NULL; + return -1; + } + + cls->methods = NULL; + metaCls->methods = NULL; + + cls->super_class = superCls; + metaCls->super_class = superCls->class_pointer; + metaCls->class_pointer = rootCls->class_pointer; + CLS_SETRESOLV(cls); + CLS_SETRESOLV(metaCls); + + cls->instance_size = ivarSize; + cls->ivars = ivarList; + + metaCls->instance_size = metaCls->super_class->instance_size; + metaCls->ivars = NULL; + + metaCls->protocols = cls->protocols = protocolList; + + metaCls->dtable = objc_get_uninstalled_dtable(); + cls->dtable = objc_get_uninstalled_dtable(); + + return 0; +} + +void PyObjCRT_AddClass(Class cls) +{ + cls->sibling_class = cls->super_class->subclass_list; + cls->super_class->subclass_list = cls; + cls->class_pointer->sibling_class = cls->super_class->class_pointer->subclass_list; + cls->super_class->class_pointer->subclass_list = cls->class_pointer; + __objc_add_class_to_hash(cls); +} + + +void PyObjCRT_ClearClass(Class cls) +{ + if (cls->methods) { + MethodList_t next, cur; + + cur = cls->methods; + + while (cur != NULL) { + next = cur->method_next; + + objc_free(cur); + cur = next; + } + cls->methods = NULL; + } + + if (cls->name) { + free((char*)(cls->name)); + cls->name = NULL; + } +} + +struct objc_method_list *PyObjCRT_AllocMethodList(int numMethods) +{ + struct objc_method_list *mlist; + + mlist = objc_malloc(sizeof(struct objc_method_list) + + ((numMethods+1) * sizeof(struct objc_method))); + + if (mlist == NULL) { + return NULL; + } + + mlist->method_count = 0; + mlist->method_next = NULL; + + return mlist; +} + +/* + * XXX: This functions should be renamed to avoid name classes with + * the actual ObjC runtime + */ + +Ivar_t class_getInstanceVariable(Class aClass, const char *name) +{ + if (!aClass || !name) + return NULL; + + for (; aClass != Nil; aClass = aClass->super_class) + { + int i; + + if (!aClass->ivars) + continue; + + for (i = 0; i < aClass->ivars->ivar_count; i++) + { + if (!strcmp(aClass->ivars->ivar_list[i].ivar_name, name)) + return &aClass->ivars->ivar_list[i]; + } + } + + return NULL; +} + +Ivar_t object_getInstanceVariable(id obj, const char *name, void **out) +{ + Ivar_t var = NULL; + + if (obj && name) + { + void **varIndex = NULL; + + if ((var = class_getInstanceVariable(obj->class_pointer, name))) + varIndex = (void **)((char *)obj + var->ivar_offset); + + if (out) + *out = *varIndex; + } + + return var; +} + +Ivar_t object_setInstanceVariable(id obj, const char *name, void *value) +{ + Ivar_t var = NULL; + + if (obj && name) + { + void **varIndex; + + if ((var = class_getInstanceVariable(obj->class_pointer, name))) + { + varIndex = (void **)((char *)obj + var->ivar_offset); + + *varIndex = value; + } + } + + return var; +} + + +#else /* !GNU_RUNTIME */ + +static int dummy __attribute__((__unused__)); + +#endif /* !GNU_RUNTIME */ diff --git a/Objective-C/PyObjC/objc_support.h b/Objective-C/PyObjC/objc_support.h new file mode 100644 index 0000000..a9b4b28 --- /dev/null +++ b/Objective-C/PyObjC/objc_support.h @@ -0,0 +1,46 @@ +/* Copyright (c) 1996,97,98 by Lele Gaifax. All Rights Reserved + * Copyright (2) 2003 Ronald Oussoren + * + * This software may be used and distributed freely for any purpose + * provided that this notice is included unchanged on any and all + * copies. The author does not warrant or guarantee this software in + * any way. + * + * This file is part of the PyObjC package. + * + * RCSfile: objc_support.h,v + * Revision: 1.16 + * Date: 1998/08/18 15:35:57 + * + * Created Tue Sep 10 14:11:38 1996. + * + * TODO: the functions exported by this file should be changed, the names + * should start with 'PyObjC' and should be the same as the names used in + * pyobjc-api.h (where appropriate). + */ + +#ifndef _objc_support_H +#define _objc_support_H + +#ifdef GNU_RUNTIME + +# include "objc-runtime-gnu.h" + +#else /* NeXTSTEP / Mac OS X */ + +# include "objc-runtime-apple.h" + +#endif + +extern ssize_t PyObjCRT_SizeOfReturnType(const char* type); +extern ssize_t PyObjCRT_SizeOfType(const char *type); +extern ssize_t PyObjCRT_AlignOfType(const char *type); +extern const char *PyObjCRT_SkipTypeSpec (const char *type); +extern const char* PyObjCRT_SkipTypeQualifiers (const char* type); + +extern int PyObjCRT_SetupClass( + Class, Class, const char*, Class, Class, ssize_t, struct objc_ivar_list*, + struct objc_protocol_list*); +extern void PyObjCRT_ClearClass(Class cls); + +#endif /* _objc_support_H */ diff --git a/Objective-C/PyObjC/objc_support.m b/Objective-C/PyObjC/objc_support.m new file mode 100644 index 0000000..862879c --- /dev/null +++ b/Objective-C/PyObjC/objc_support.m @@ -0,0 +1,505 @@ +/* Copyright (c) 1996,97,98 by Lele Gaifax. All Rights Reserved + * Copyright (c) 2002, 2003 Ronald Oussoren + * + * This software may be used and distributed freely for any purpose + * provided that this notice is included unchanged on any and all + * copies. The author does not warrant or guarantee this software in + * any way. + * + * This file is part of the PyObjC package. + * + * RCSfile: objc_support.m,v + * Revision: 1.24 + * Date: 1998/08/18 15:35:58 + * + * Created Tue Sep 10 14:16:02 1996. + */ + +#include "objc_support.h" +#include "pyobjc.h" + +#include <objc/Protocol.h> + +#include <unistd.h> + +#ifdef MACOSX +/* OSX 10.1 doesn't define LLONG_MIN, LLONG_MAX and ULLONG_MAX */ +#ifndef LLONG_MIN +#error "Mac OS X 10.1 not supported" +#endif +#endif + +#import <Foundation/NSInvocation.h> +#import <Foundation/NSData.h> +#import <Foundation/NSValue.h> +#import <Foundation/NSDecimalNumber.h> + +#ifdef MACOSX +#include <CoreFoundation/CFNumber.h> +#endif /* MACOSX */ + + +/* Define in order to throw exceptions when a typespec cannot be parsed. */ +#undef STRICT_TYPE_PARSING + + +#ifndef MAX +static inline ssize_t +MAX(ssize_t x, ssize_t y) +{ + return x > y ? x : y; +} +#endif + +static inline ssize_t +ROUND(ssize_t v, ssize_t a) +{ + if (v % a == 0) { + return v; + } else { + return v + a - (v % a); + } +} + + +const char* +PyObjCRT_SkipTypeQualifiers (const char* type) +{ + while ( + *type == _C_CONST || + *type == _C_IN || + *type == _C_INOUT || + *type == _C_OUT || + *type == _C_BYCOPY || + *type == _C_ONEWAY) { + type++; + } + while (*type && isdigit(*type)) type++; + return type; +} + + +const char * +PyObjCRT_SkipTypeSpec (const char *type) +{ + type = PyObjCRT_SkipTypeQualifiers (type); + + switch (*type) { + /* The following are one character type codes */ + case _C_UNDEF: + case _C_CLASS: + case _C_SEL: + case _C_CHR: + case _C_UCHR: + case _C_CHARPTR: +#ifdef _C_ATOM + case _C_ATOM: +#endif +#ifdef _C_BOOL + case _C_BOOL: +#endif + case _C_SHT: + case _C_USHT: + case _C_INT: + case _C_UINT: + case _C_LNG: + case _C_ULNG: + case _C_FLT: + case _C_DBL: + case _C_VOID: + case _C_LNGLNG: + case _C_ULNGLNG: + case _C_BFLD: /* Not really 1 character, but close enough */ + ++type; + break; + + case _C_ID: + ++type; +#ifdef MACOSX + if (*type == '"') { + /* embedded field name in an ivar_type */ + type=strchr(type+1, '"'); + if (type != NULL) { + type++; + } + } +#endif + break; + + case _C_ARY_B: + /* skip digits, typespec and closing ']' */ + + while (isdigit (*++type)); + type = PyObjCRT_SkipTypeSpec (type); + assert (type == NULL || *type == _C_ARY_E); + if (type) type++; + break; + + case _C_STRUCT_B: + /* skip name, and elements until closing '}' */ + while (*type != _C_STRUCT_E && *type++ != '='); + while (type && *type != _C_STRUCT_E) { + if (*type == '"') { + /* embedded field names */ + type = strchr(type+1, '"'); + if (type != NULL) { + type++; + } else { + return NULL; + } + } + type = PyObjCRT_SkipTypeSpec (type); + } + if (type) type++; + break; + + case _C_UNION_B: + /* skip name, and elements until closing ')' */ + while (*type != _C_UNION_E && *type++ != '='); + while (type && *type != _C_UNION_E) { + type = PyObjCRT_SkipTypeSpec (type); + } + if (type) type++; + break; + + case _C_PTR: + case _C_CONST: + case _C_IN: + case _C_INOUT: + case _C_OUT: + case _C_BYCOPY: + case _C_ONEWAY: + + /* Just skip the following typespec */ + type = PyObjCRT_SkipTypeSpec (type+1); + break; + + + default: +#ifdef STRICT_TYPE_PARSING + [[NSException exceptionWithName: @"PyObjCRT_SkipTypeSpec" + reason: [NSString stringWithFormat: @"Unhandled type: '%c'", *type] + userInfo: NULL] raise]; +#else + NSLog (@"PyObjCRT_SkipTypeSpec: Unhandled type: '%c'", *type); +#endif + return NULL; + } + + /* The compiler inserts a number after the actual signature, + * this number may or may not be usefull depending on the compiler + * version. We never use it. + */ + while (type && *type && isdigit(*type)) type++; + return type; +} + +/* +Return the alignment of an object specified by type +*/ + +/* +* On MacOS X, the elements of a struct are aligned differently inside the +* struct than outside. That is, the maximum alignment of any struct field +* (except the first) is 4, doubles outside of a struct have an alignment of +* 8. +* +* Other platform don't seem to have this inconsistency. +* +* XXX: sizeof_struct, alignof_struct and {de,}pythonify_c_struct should +* probably be moved to platform dependend files. As long as this is the +* only platform dependent code this isn't worth the effort. +*/ +#ifdef MACOSX + +static inline ssize_t +PyObjC_EmbeddedAlignOfType (const char* type) +{ + ssize_t align = PyObjCRT_AlignOfType(type); + +#ifdef __i386__ + return align; + +#else + if (align < 4 || align == 16) { + return align; + } else { + return 4; + } +#endif +} + +#else + +static inline int +PyObjC_EmbeddedAlignOfType (const char* type) +{ + ssize_t align = PyObjCRT_AlignOfType(type); + + /* GNUstep/ix86 seems to behave like this: */ + if (align < 4) { + return align; + } else { + return 4; + } +} + +#endif + +ssize_t +PyObjCRT_AlignOfType (const char *type) +{ + switch (*type) { + case _C_ID: return __alignof__ (id); + case _C_CLASS: return __alignof__ (Class); + case _C_SEL: return __alignof__ (SEL); + case _C_CHR: return __alignof__ (char); + case _C_UCHR: return __alignof__ (unsigned char); + case _C_SHT: return __alignof__ (short); + case _C_USHT: return __alignof__ (unsigned short); +#ifdef _C_BOOL + case _C_BOOL: return __alignof__ (bool); +#endif + case _C_INT: return __alignof__ (int); + case _C_UINT: return __alignof__ (unsigned int); + case _C_LNG: return __alignof__ (long); + case _C_ULNG: return __alignof__ (unsigned long); + case _C_FLT: return __alignof__ (float); + case _C_DBL: +#if defined(__APPLE__) && defined(__i386__) + /* The ABI says natural alignment is 4 bytes, but + * GCC's __alignof__ says 8. The latter is wrong. + */ + return 4; +#else + return __alignof__ (double); +#endif + + case _C_CHARPTR: return __alignof__ (char *); +#ifdef _C_ATOM + case _C_ATOM: return __alignof__ (char *); +#endif + case _C_PTR: return __alignof__ (void *); +#if defined(__APPLE__) && defined(__i386__) + /* The ABI says natural alignment is 4 bytes, but + * GCC's __alignof__ says 8. The latter is wrong. + */ + case _C_LNGLNG: return 4; + case _C_ULNGLNG: return 4; +#else + case _C_LNGLNG: return __alignof__(long long); + case _C_ULNGLNG: return __alignof__(unsigned long long); +#endif + + case _C_ARY_B: + while (isdigit(*++type)) /* do nothing */; + return PyObjCRT_AlignOfType (type); + + case _C_STRUCT_B: + { + struct { int x; double y; } fooalign; + while(*type != _C_STRUCT_E && *type++ != '=') /* do nothing */; + if (*type != _C_STRUCT_E) { + int have_align = 0; + ssize_t align = 0; + + while (type != NULL && *type != _C_STRUCT_E) { + if (*type == '"') { + type = strchr(type+1, '"'); + if (type) type++; + } + if (have_align) { + align = MAX(align, + PyObjC_EmbeddedAlignOfType(type)); + } else { + align = PyObjCRT_AlignOfType(type); + have_align = 1; + } + type = PyObjCRT_SkipTypeSpec(type); + } + if (type == NULL) return -1; + return align; + } else { + return __alignof__ (fooalign); + } + } + + case _C_UNION_B: + { + int maxalign = 0; + type++; + while (*type != _C_UNION_E) + { + int item_align = PyObjCRT_AlignOfType(type); + if (item_align == -1) return -1; + maxalign = MAX (maxalign, item_align); + type = PyObjCRT_SkipTypeSpec (type); + } + return maxalign; + } + + case _C_CONST: + case _C_IN: + case _C_INOUT: + case _C_OUT: + case _C_BYCOPY: + case _C_ONEWAY: + return PyObjCRT_AlignOfType(type+1); + + default: +#ifdef STRICT_TYPE_PARSING + [[NSException exceptionWithName: @"PyObjCRT_SkipTypeSpec" + reason: [NSString stringWithFormat: @"Unhandled type: '%c'", *type] + userInfo: NULL] raise]; +#else + NSLog (@"PyObjCRT_SkipTypeSpec: Unhandled type: '%c'", *type); +#endif + return -1; + } +} + +/* +The aligned size if the size rounded up to the nearest alignment. +*/ + +static ssize_t +PyObjCRT_AlignedSize (const char *type) +{ + ssize_t size = PyObjCRT_SizeOfType (type); + ssize_t align = PyObjCRT_AlignOfType (type); + + if (size == -1 || align == -1) return -1; + return ROUND(size, align); +} + +/* +return the size of an object specified by type +*/ + +ssize_t +PyObjCRT_SizeOfType (const char *type) +{ + ssize_t itemSize; + switch (*type) { + case _C_VOID: return 0; + case _C_ID: return sizeof(id); + case _C_CLASS: return sizeof(Class); + case _C_SEL: return sizeof(SEL); + case _C_CHR: return sizeof(char); + case _C_UCHR: return sizeof(unsigned char); + case _C_SHT: return sizeof(short); + case _C_USHT: return sizeof(unsigned short); +#ifdef _C_BOOL + case _C_BOOL: return sizeof(bool); +#endif + case _C_INT: return sizeof(int); + case _C_UINT: return sizeof(unsigned int); + case _C_LNG: return sizeof(long); + case _C_ULNG: return sizeof(unsigned long); + case _C_FLT: return sizeof(float); + case _C_DBL: return sizeof(double); + case _C_LNGLNG: return sizeof(long long); + case _C_ULNGLNG: return sizeof(unsigned long long); + + case _C_PTR: + case _C_CHARPTR: +#ifdef _C_ATOM + case _C_ATOM: +#endif + return sizeof(char*); + + case _C_ARY_B: + { + ssize_t len = atoi(type+1); + ssize_t item_align; + while (isdigit(*++type)) + ; + item_align = PyObjCRT_AlignedSize(type); + if (item_align == -1) return -1; + return len*item_align; + } + break; + + case _C_STRUCT_B: + { + ssize_t acc_size = 0; + int have_align = 0; + ssize_t align; + ssize_t max_align = 0; + + while (*type != _C_STRUCT_E && *type++ != '=') + ; /* skip "<name>=" */ + while (*type != _C_STRUCT_E) { + if (*type == '"') { + type = strchr(type+1, '"'); + if (type) type++; + } + if (have_align) { + align = PyObjC_EmbeddedAlignOfType(type); + if (align == -1) return -1; + } else { + align = PyObjCRT_AlignOfType(type); + if (align == -1) return -1; + have_align = 1; + } + max_align = MAX(align, max_align); + acc_size = ROUND (acc_size, align); + + itemSize = PyObjCRT_SizeOfType (type); + if (itemSize == -1) return -1; + acc_size += itemSize; + type = PyObjCRT_SkipTypeSpec (type); + } + if (max_align) { + acc_size = ROUND(acc_size, max_align); + } + return acc_size; + } + + case _C_UNION_B: + { + ssize_t max_size = 0; + type++; + while (*type != _C_UNION_E) { + itemSize = PyObjCRT_SizeOfType (type); + if (itemSize == -1) return -1; + max_size = MAX (max_size, itemSize); + type = PyObjCRT_SkipTypeSpec (type); + } + return max_size; + } + + case _C_CONST: + case _C_IN: + case _C_INOUT: + case _C_OUT: + case _C_BYCOPY: + case _C_ONEWAY: + return PyObjCRT_SizeOfType(type+1); + + default: +#ifdef STRICT_TYPE_PARSING + [[NSException exceptionWithName: @"PyObjCRT_SkipTypeSpec" + reason: [NSString stringWithFormat: @"Unhandled type: '%c'", *type] + userInfo: NULL] raise]; +#else + NSLog (@"PyObjCRT_SkipTypeSpec: Unhandled type: '%c'", *type); +#endif + return -1; + } +} + + +ssize_t +PyObjCRT_SizeOfReturnType(const char* type) +{ + switch(*type) { + case _C_CHR: + case _C_UCHR: + case _C_SHT: + case _C_USHT: + return sizeof(int); + default: + return PyObjCRT_SizeOfType(type); + } +} diff --git a/Objective-C/PyObjC/pyobjc.h b/Objective-C/PyObjC/pyobjc.h new file mode 100644 index 0000000..6a2d6b4 --- /dev/null +++ b/Objective-C/PyObjC/pyobjc.h @@ -0,0 +1,46 @@ +/* Copyright 2007, Matthias Andreas Benkard. */ + +#ifndef __pyobjc_H +#define __pyobjc_H + +#include <stdlib.h> +#include <stdio.h> +#include "libobjcl.h" + + +#ifdef __NEXT_RUNTIME__ + +#ifndef APPLE_RUNTIME +#define APPLE_RUNTIME +#endif + +#import <objc/objc-class.h> + +#else /* !__NEXT_RUNTIME__ */ + +#ifndef GNU_RUNTIME +#define GNU_RUNTIME +#endif + +#import <objc/objc-api.h> +#ifndef __CXX__ +#define bool BOOL +#endif + +#endif /* __NEXT_RUNTIME__ */ + + +#define PyMem_Free free +#define PyMem_Malloc malloc +#define Py_ssize_t ssize_t + +#ifdef OOM_KILL +#define PyErr_NoMemory() [objcl_oom_exception raise] +#else +#define PyErr_NoMemory() NSLog (@"ERROR: Memory exhausted."); +#endif + +#include "objc_support.h" +#include "libffi_support.h" + +#endif /* __pyobjc_H */ |