summaryrefslogtreecommitdiff
path: root/Objective-C
diff options
context:
space:
mode:
authorMatthias Benkard <code@mail.matthias.benkard.de>2007-09-15 15:33:46 +0200
committerMatthias Benkard <code@mail.matthias.benkard.de>2007-09-15 15:33:46 +0200
commit585f55e70e44cccb0807c2bc2d1f0904c8fbc5e1 (patch)
treea94bec4ba2b3a0e298c5619d656cdd013aa2f93d /Objective-C
parentd0dd29fcf87b51280dd5c2685063ea42cf4fc115 (diff)
Add libffi support code from PyObjC.
darcs-hash:0cb8e75aa1ea694562f5087aa400840349adcac8
Diffstat (limited to 'Objective-C')
-rw-r--r--Objective-C/GNUmakefile4
-rw-r--r--Objective-C/libffi_support.h36
-rw-r--r--Objective-C/libffi_support.m1061
-rw-r--r--Objective-C/libobjcl.h4
-rw-r--r--Objective-C/libobjcl.m6
5 files changed, 1101 insertions, 10 deletions
diff --git a/Objective-C/GNUmakefile b/Objective-C/GNUmakefile
index 33b91ac..92934ed 100644
--- a/Objective-C/GNUmakefile
+++ b/Objective-C/GNUmakefile
@@ -7,12 +7,8 @@ LIBRARY_NAME = libobjcl
RPM_DISABLE_RELOCATABLE = YES
ADDITIONAL_OBJCFLAGS = -Wall -g -DVERSION=\"$(VERSION)\" -I/usr/local/include
-ifdef USE_LIBFFI
ADDITIONAL_LDFLAGS = -lffi
ADDITIONAL_OBJCFLAGS += -DUSE_LIBFFI
-else
-ADDITIONAL_LDFLAGS = -lavcall
-endif
libobjcl_OBJC_FILES = libobjcl.m objc_support.m objc-runtime-apple.m objc-runtime-gnu.m
LIBRARIES_DEPEND_UPON = $(FND_LIBS) $(GUI_LIBS) $(OBJC_LIBS) $(SYSTEM_LIBS) $(CONFIG_SYSTEM_LIBS)
diff --git a/Objective-C/libffi_support.h b/Objective-C/libffi_support.h
new file mode 100644
index 0000000..d9a7f40
--- /dev/null
+++ b/Objective-C/libffi_support.h
@@ -0,0 +1,36 @@
+#ifndef PyObjC_FFI_SUPPORT_H
+#define PyObjC_FFI_SUPPORT_H
+
+#include "ffi.h"
+
+typedef void (*PyObjCFFI_ClosureFunc)(ffi_cif*, void*, void**, void*);
+
+void PyObjCFFI_FreeCIF(ffi_cif* cif);
+ffi_cif* PyObjCFFI_CIFForSignature(PyObjCMethodSignature* signature);
+IMP PyObjCFFI_MakeClosure(PyObjCMethodSignature* signature,
+ PyObjCFFI_ClosureFunc func, void* userdata);
+void* PyObjCFFI_FreeClosure(IMP closure);
+
+IMP PyObjCFFI_MakeIMPForSignature(char* signature, PyObject* callable);
+IMP PyObjCFFI_MakeIMPForPyObjCSelector(PyObjCSelector *aSelector);
+PyObject *PyObjCFFI_Caller(PyObject *aMeth, PyObject* self, PyObject *args);
+
+int PyObjCFFI_CountArguments(
+ PyObjCMethodSignature* methinfo, Py_ssize_t argOffset,
+ Py_ssize_t* byref_in_count,
+ Py_ssize_t* byref_out_count,
+ Py_ssize_t* plain_count,
+ Py_ssize_t* argbuf_len);
+
+int PyObjCFFI_ParseArguments(
+ PyObjCMethodSignature* methinfo, Py_ssize_t argOffset,
+ PyObject* args, Py_ssize_t argbuf_cur, unsigned char* argbuf,
+ void** byref,
+ ffi_type** arglist, void** values);
+
+PyObject* PyObjCFFI_BuildResult(
+ PyObjCMethodSignature* methinfo, Py_ssize_t argOffset,
+ void* pRetval, void** byref, Py_ssize_t byref_out_count,
+ PyObject* self, int flags);
+
+#endif /* PyObjC_FFI_SUPPORT_H */
diff --git a/Objective-C/libffi_support.m b/Objective-C/libffi_support.m
new file mode 100644
index 0000000..a431fdd
--- /dev/null
+++ b/Objective-C/libffi_support.m
@@ -0,0 +1,1061 @@
+/*
+ * 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/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 */
+
+
+
+#ifndef FFI_CLOSURES
+# error "Need FFI_CLOSURES!"
+#endif
+
+#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 align(Py_ssize_t offset, Py_ssize_t alignment)
+{
+ Py_ssize_t rest = offset % alignment;
+ if (rest == 0) return offset;
+ return offset + (alignment - rest);
+}
+
+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 PyObject* array_types = NULL; /* XXX: Use NSMap */
+ PyObject* v;
+ ffi_type* type;
+ Py_ssize_t field_count;
+ Py_ssize_t i;
+ const char* key = argtype;
+
+ if (array_types == NULL) {
+ array_types = PyDict_New();
+ if (array_types == NULL) return NULL;
+ }
+
+ v = PyDict_GetItemString(array_types, (char*)argtype);
+ if (v != NULL) {
+ return (ffi_type*)PyCObject_AsVoidPtr(v);
+ }
+
+ /* 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. These 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 = PyCObject_FromVoidPtr(type, free_type);
+ if (v == NULL) {
+ free_type(type);
+ return NULL;
+ }
+
+ PyDict_SetItemString(array_types, (char*)key, v);
+ if (PyErr_Occurred()) {
+ Py_DECREF(v);
+ return NULL;
+ }
+ Py_DECREF(v);
+ return type;
+}
+
+static ffi_type*
+struct_to_ffi_type(const char* argtype)
+{
+ static PyObject* struct_types = NULL; /* XXX: Use NSMap */
+ PyObject* v;
+ ffi_type* type;
+ Py_ssize_t field_count;
+ const char* curtype;
+
+ if (struct_types == NULL) {
+ struct_types = PyDict_New();
+ if (struct_types == NULL) return NULL;
+ }
+
+ v = PyDict_GetItemString(struct_types, (char*)argtype);
+ if (v != NULL) {
+ return (ffi_type*)PyCObject_AsVoidPtr(v);
+ }
+
+ /* We don't have a type description yet, dynamicly
+ * create it.
+ */
+ field_count = num_struct_fields(argtype);
+ if (field_count == -1) {
+ PyErr_Format(PyObjCExc_InternalError,
+ "Cannot determine layout of %s", argtype);
+ 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 = PyCObject_FromVoidPtr(type, free_type);
+ if (v == NULL) {
+ free_type(type);
+ return NULL;
+ }
+
+ PyDict_SetItemString(struct_types, (char*)argtype, v);
+ if (PyErr_Occurred()) {
+ Py_DECREF(v);
+ return NULL;
+ }
+ Py_DECREF(v);
+ return type;
+}
+
+static ffi_type*
+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:
+ PyErr_Format(PyExc_NotImplementedError,
+ "Type '%#x' not supported", *argtype);
+ 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__
+#define arg_signature_to_ffi_type signature_to_ffi_type
+
+#else
+static inline ffi_type*
+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 */
+
+static inline ffi_type*
+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 */
+
+/* This function decodes its arguments into Python values, then
+ * calls the python method and finally encodes the return value
+ */
+
+typedef struct {
+ PyObject* callable;
+ PyObjCMethodSignature* methinfo;
+} _method_stub_userdata;
+
+static void
+method_stub(ffi_cif* cif __attribute__((__unused__)), void* resp, void** args, void* _userdata)
+{
+ _method_stub_userdata* userdata = (_method_stub_userdata*)_userdata;
+ PyObject* callable = userdata->callable;
+ PyObjCMethodSignature* methinfo = userdata->methinfo;
+ int isAlloc = 0;
+ Py_ssize_t i;
+ PyObject* arglist;
+ PyObject* res;
+ PyObject* v;
+ int have_output = 0;
+ const char* rettype;
+ PyObject* pyself;
+ int cookie;
+
+ PyGILState_STATE state = PyGILState_Ensure();
+
+ rettype = methinfo->rettype;
+
+ arglist = PyList_New(0);
+
+ pyself = PyObjCObject_NewTransient(*(id*)args[0], &cookie);
+ if (pyself == NULL) {
+ goto error;
+ }
+ if (PyList_Append(arglist, pyself) == -1) {
+ goto error;
+ }
+
+ /* First translate from Objective-C to python */
+
+ for (i = 2; i < methinfo->nargs; i++) {
+
+ const char* argtype = methinfo->argtype[i];
+
+ switch (*argtype) {
+ case _C_INOUT:
+ if (argtype[1] == _C_PTR) {
+ have_output ++;
+ }
+ /* FALL THROUGH */
+ case _C_IN: case _C_CONST:
+ if (argtype[1] == _C_PTR) {
+ if (*(void**)args[i]) {
+ v = pythonify_c_value(argtype+2,
+ *(void**)args[i]);
+ } else {
+ v = PyObjC_NULL;
+ Py_INCREF(v);
+ }
+ } else {
+ v = pythonify_c_value(argtype+1,
+ args[i]);
+ }
+ break;
+ case _C_OUT:
+ /* Skip output parameter */
+ if (argtype[1] == _C_PTR) {
+ have_output ++;
+ }
+ continue;
+ default:
+ v = pythonify_c_value(argtype, args[i]);
+ }
+ if (v == NULL) {
+ Py_DECREF(arglist);
+ goto error;
+ }
+ if (PyList_Append(arglist, v) == -1) {
+ Py_DECREF(v);
+ Py_DECREF(arglist);
+ goto error;
+ }
+ Py_DECREF(v);
+ }
+
+ v = PyList_AsTuple(arglist);
+ if (v == NULL) {
+ Py_DECREF(arglist);
+ PyObjCObject_ReleaseTransient(pyself, cookie);
+ goto error;
+ }
+ Py_DECREF(arglist);
+ arglist = v;
+
+ if (!callable) {
+ abort();
+ }
+
+ res = PyObject_Call(callable, arglist, NULL);
+ isAlloc = PyObjCSelector_DonatesRef(callable);
+ Py_DECREF(arglist);
+ PyObjCObject_ReleaseTransient(pyself, cookie);
+ if (res == NULL) {
+ goto error;
+ }
+
+ if (!have_output) {
+ int err;
+
+ if (*rettype != _C_VOID) {
+ err = depythonify_c_return_value(rettype, res, resp);
+
+ if (isAlloc && *rettype == _C_ID) {
+ /* Must return a 'new' instead of a borrowed
+ * reference.
+ */
+ [(*(id*)resp) retain];
+ } else if (*rettype == _C_ID && res->ob_refcnt == 1) {
+ /* make sure return value doesn't die before
+ * the caller can get its hands on it.
+ */
+ [[(*(id*)resp) retain] autorelease];
+ }
+ Py_DECREF(res);
+ if (err == -1) {
+ if (res == Py_None) {
+ PyErr_Format(PyExc_ValueError,
+ "%s: returned None, expecting "
+ "a value",
+ PyObjCRT_SELName(*(SEL*)args[1]));
+ }
+ goto error;
+ }
+ } else {
+ if (res != Py_None) {
+ PyErr_Format(PyExc_ValueError,
+ "%s: did not return None, expecting "
+ "void return value",
+ PyObjCRT_SELName(*(SEL*)args[1]));
+ goto error;
+ }
+ *((int*)resp) = 0;
+ }
+ } else {
+ /* We have some output parameters, locate them and encode
+ * their values
+ */
+ Py_ssize_t idx;
+ PyObject* real_res;
+
+ if (*rettype == _C_VOID && have_output == 1) {
+ /* Special case: the python method returned only
+ * the return value, not a tuple.
+ */
+ for (i = 2; i < methinfo->nargs; i++) {
+ const char* argtype = methinfo->argtype[i];
+ int err;
+
+ switch (*argtype) {
+ case _C_INOUT: case _C_OUT:
+ if (argtype[1] != _C_PTR) {
+ continue;
+ }
+ argtype += 2;
+ break;
+ default: continue;
+ }
+
+ err = depythonify_c_value(argtype, res, *(void**)args[i]);
+ if (err == -1) {
+ goto error;
+ }
+ if (res->ob_refcnt == 1 && argtype[0] == _C_ID) {
+ /* make sure return value doesn't die before
+ * the caller can get its hands on it.
+ */
+ [[**(id**)args[i] retain] autorelease];
+ }
+
+ break;
+ }
+
+ PyGILState_Release(state);
+ return;
+ }
+
+ if (*rettype != _C_VOID) {
+ if (!PyTuple_Check(res) || PyTuple_Size(res) != have_output+1) {
+ PyErr_Format(PyExc_TypeError,
+ "%s: Need tuple of %d arguments as result",
+ PyObjCRT_SELName(*(SEL*)args[1]), have_output+1);
+ Py_DECREF(res);
+ goto error;
+ }
+
+ real_res = PyTuple_GET_ITEM(res, 0);
+ idx = 1;
+ } else {
+ if (!PyTuple_Check(res) || PyTuple_Size(res) != have_output) {
+ PyErr_Format(PyExc_TypeError,
+ "%s: Need tuple of %d arguments as result",
+ PyObjCRT_SELName(*(SEL*)args[1]), have_output);
+ Py_DECREF(res);
+ goto error;
+ }
+ real_res = NULL;
+ idx = 0;
+ }
+
+
+ for (i = 2; i < methinfo->nargs; i++) {
+ const char* argtype = methinfo->argtype[i];
+ int err;
+
+ switch (*argtype) {
+ case _C_INOUT: case _C_OUT:
+ if (argtype[1] != _C_PTR) {
+ continue;
+ }
+ argtype += 2;
+ break;
+ default: continue;
+ }
+
+ if (*(void**)args[i] != NULL) {
+ /* The output pointer might be NULL */
+
+ v = PyTuple_GET_ITEM(res, idx++);
+ err = depythonify_c_value(argtype, v, *(void**)args[i]);
+ if (err == -1) {
+ goto error;
+ }
+ if (v->ob_refcnt == 1 && argtype[0] == _C_ID) {
+ /* make sure return value doesn't die before
+ * the caller can get its hands on it.
+ */
+ [[**(id**)args[i] retain] autorelease];
+ }
+ }
+ }
+
+ if (*rettype != _C_VOID) {
+ int err = depythonify_c_return_value(rettype,
+ real_res, resp);
+
+ if (isAlloc && *rettype == _C_ID) {
+ /* Must return a 'new' instead of a borrowed
+ * reference.
+ */
+ [(*(id*)resp) retain];
+ } else if (*rettype == _C_ID && real_res->ob_refcnt == 1) {
+ /* make sure return value doesn't die before
+ * the caller can get its hands on it.
+ */
+ [[(*(id*)resp) retain] autorelease];
+ }
+ if (err == -1) {
+ if (real_res == Py_None) {
+ PyErr_Format(PyExc_ValueError,
+ "%s: returned None, expecting "
+ "a value",
+ PyObjCRT_SELName(*(SEL*)args[1]));
+ }
+ Py_DECREF(res);
+ goto error;
+ }
+ } else {
+ if (res != Py_None) {
+ PyErr_Format(PyExc_ValueError,
+ "%s: did not return None, expecting "
+ "void return value",
+ PyObjCRT_SELName(*(SEL*)args[1]));
+ goto error;
+ }
+ *((int*)resp) = 0;
+ }
+
+
+ Py_DECREF(res);
+
+ }
+
+ PyGILState_Release(state);
+
+ return;
+
+error:
+ PyObjCErr_ToObjCWithGILState(&state);
+}
+
+/*
+ * Return an IMP that is suitable for forwarding a method with the specified
+ * signature from Objective-C to Python.
+ */
+IMP
+PyObjCFFI_MakeIMPForSignature(char* signature, PyObject* callable)
+{
+ _method_stub_userdata* stubUserdata;
+ PyObjCMethodSignature* methinfo;
+ IMP closure;
+
+ methinfo = PyObjCMethodSignature_FromSignature(signature);
+ if (methinfo == NULL) {
+ return NULL;
+ }
+
+ stubUserdata = PyMem_Malloc(sizeof(*stubUserdata));
+ if (stubUserdata == NULL) {
+ PyObjCMethodSignature_Free(methinfo);
+ return NULL;
+ }
+
+ stubUserdata->methinfo = methinfo;
+
+ if (callable) {
+ stubUserdata->callable = callable;
+ Py_INCREF(stubUserdata->callable);
+ } else {
+ stubUserdata->callable = NULL;
+ }
+
+ closure = PyObjCFFI_MakeClosure(methinfo, method_stub, stubUserdata);
+ if (closure == NULL) {
+ PyObjCMethodSignature_Free(methinfo);
+ if (stubUserdata->callable) {
+ Py_DECREF(stubUserdata->callable);
+ }
+ PyMem_Free(stubUserdata);
+ return NULL;
+ }
+
+ return closure;
+}
+
+IMP
+PyObjCFFI_MakeIMPForPyObjCSelector(PyObjCSelector *aSelector)
+{
+ if (PyObjCNativeSelector_Check(aSelector)) {
+ PyObjCNativeSelector *nativeSelector =
+ (PyObjCNativeSelector *) aSelector;
+ PyObjCRT_Method_t aMeth;
+
+ if (nativeSelector->sel_flags & PyObjCSelector_kCLASS_METHOD) {
+ aMeth = class_getClassMethod(nativeSelector->sel_class, nativeSelector->sel_selector);
+ } else {
+ aMeth = class_getInstanceMethod(nativeSelector->sel_class, nativeSelector->sel_selector);
+ }
+ return aMeth->method_imp;
+ } else {
+ PyObjCPythonSelector *pythonSelector = (PyObjCPythonSelector *) aSelector;
+ return PyObjCFFI_MakeIMPForSignature(pythonSelector->sel_signature, pythonSelector->callable);
+ }
+}
+
+/* Count the number of arguments and their total size */
+/* argument_size is not cleared and should be initialized to the amount of
+ * bufferspace that will be allocated just before the argument array
+ */
+int PyObjCFFI_CountArguments(
+ PyObjCMethodSignature* methinfo, Py_ssize_t argOffset,
+ Py_ssize_t* byref_in_count,
+ Py_ssize_t* byref_out_count,
+ Py_ssize_t* plain_count,
+ Py_ssize_t* argbuf_len)
+{
+ Py_ssize_t i;
+ Py_ssize_t itemAlign;
+ Py_ssize_t itemSize;
+
+ *byref_in_count = *byref_out_count = *plain_count = 0;
+
+ for (i = argOffset; i < methinfo->nargs; i++) {
+ const char *argtype = methinfo->argtype[i];
+
+ switch (*argtype) {
+ case _C_INOUT:
+ if (argtype[1] == _C_PTR) {
+ (*byref_out_count) ++;
+ (*byref_in_count) ++;
+ itemAlign = PyObjCRT_AlignOfType(argtype+2);
+ itemSize = PyObjCRT_SizeOfType(argtype+2);
+ if (itemSize == -1) {
+ return -1;
+ }
+ } else {
+ itemSize = PyObjCRT_SizeOfType(argtype+1);
+ itemAlign = PyObjCRT_AlignOfType(argtype+1);
+ if (itemSize == -1) {
+ return -1;
+ }
+ }
+ *argbuf_len = align(*argbuf_len, itemAlign);
+ (*argbuf_len) += itemSize;
+ break;
+
+ case _C_IN: case _C_CONST:
+ if (argtype[1] == _C_PTR) {
+ (*byref_in_count) ++;
+ itemSize = PyObjCRT_SizeOfType(argtype+2);
+ itemAlign = PyObjCRT_AlignOfType(argtype+2);
+ if (itemSize == -1) {
+ return -1;
+ }
+ } else {
+ (*plain_count) ++;
+ itemSize = PyObjCRT_SizeOfType(argtype+1);
+ itemAlign = PyObjCRT_AlignOfType(argtype+1);
+ if (itemSize == -1) {
+ return -1;
+ }
+ }
+ *argbuf_len = align(*argbuf_len, itemAlign);
+ (*argbuf_len) += itemSize;
+ break;
+
+ case _C_OUT:
+ if (argtype[1] == _C_PTR) {
+ (*byref_out_count) ++;
+ itemSize = PyObjCRT_SizeOfType(argtype+2);
+ itemAlign = PyObjCRT_AlignOfType(argtype+2);
+ if (itemSize == -1) {
+ return -1;
+ }
+ } else {
+ (*plain_count)++;
+ itemSize = PyObjCRT_SizeOfType(argtype+1);
+ itemAlign = PyObjCRT_AlignOfType(argtype+1);
+ if (itemSize == -1) {
+ return -1;
+ }
+ }
+ *argbuf_len = align(*argbuf_len, itemAlign);
+ (*argbuf_len) += itemSize;
+ break;
+
+ case _C_STRUCT_B: case _C_UNION_B: case _C_ARY_B:
+ (*plain_count)++;
+ itemSize = PyObjCRT_SizeOfType(argtype);
+ itemAlign = PyObjCRT_AlignOfType(argtype);
+ if (itemSize == -1) {
+ return -1;
+ }
+ *argbuf_len = align(*argbuf_len, itemAlign);
+ (*argbuf_len) += itemSize;
+ break;
+
+ default:
+ itemSize = PyObjCRT_SizeOfType(argtype);
+ itemAlign = PyObjCRT_AlignOfType(argtype);
+ if (itemSize == -1) {
+ return -1;
+ }
+ *argbuf_len = align(*argbuf_len, itemAlign);
+ (*argbuf_len) += itemSize;
+ (*plain_count)++;
+ break;
+ }
+ }
+ return 0;
+}
+
+int PyObjCFFI_ParseArguments(
+ PyObjCMethodSignature* methinfo, Py_ssize_t argOffset,
+ PyObject* args,
+ Py_ssize_t argbuf_cur, unsigned char* argbuf,
+ void** byref,
+ ffi_type** arglist, void** values)
+{
+ Py_ssize_t py_arg = 0;
+ Py_ssize_t i;
+ void* arg;
+
+ for (i = argOffset; i < methinfo->nargs; i++) {
+
+ int error;
+ PyObject *argument;
+ const char *argtype = methinfo->argtype[i];
+
+ if (argtype[0] == _C_OUT && argtype[1] == _C_PTR) {
+ /* Just allocate room in argbuf and set that*/
+ Py_ssize_t sz;
+
+ argbuf_cur = align(argbuf_cur,
+ PyObjCRT_AlignOfType(argtype+2));
+ arg = argbuf + argbuf_cur;
+ byref[i] = arg;
+
+ arglist[i] = &ffi_type_pointer;
+ values[i] = byref+i;
+
+ sz = PyObjCRT_SizeOfType(argtype+2);
+ argbuf_cur += sz;
+
+ /* Clear the output buffer, just in case the called
+ * function doesn't write anything into the buffer.
+ */
+ memset(arg, 0, sz);
+ } else {
+ /* Encode argument, maybe after allocating space */
+
+ if (argtype[0] == _C_OUT) argtype ++;
+
+ argument = PyTuple_GET_ITEM (args, py_arg);
+ switch (*argtype) {
+ case _C_STRUCT_B: case _C_ARY_B: case _C_UNION_B:
+ /* Allocate space and encode */
+ argbuf_cur = align(argbuf_cur,
+ PyObjCRT_AlignOfType(argtype));
+ arg = argbuf + argbuf_cur;
+ argbuf_cur += PyObjCRT_SizeOfType(argtype);
+ byref[i] = arg;
+ error = depythonify_c_value (
+ argtype,
+ argument,
+ arg);
+
+ arglist[i] = signature_to_ffi_type(argtype);
+ values[i] = arg;
+ break;
+ case _C_INOUT:
+ case _C_IN:
+ case _C_CONST:
+
+ if (argtype[1] == _C_PTR) {
+ /* Allocate space and encode */
+
+ if (argument == PyObjC_NULL) {
+ byref[i] = NULL;
+ error = 0;
+
+ } else {
+ argbuf_cur = align(argbuf_cur, PyObjCRT_AlignOfType(argtype+2));
+ arg = argbuf + argbuf_cur;
+ argbuf_cur += PyObjCRT_SizeOfType(argtype+2);
+ byref[i] = arg;
+ error = depythonify_c_value (
+ argtype+2,
+ argument,
+ arg);
+ }
+
+ arglist[i] = &ffi_type_pointer;
+ values[i] = byref + i;
+
+ } else {
+ /* just encode */
+ argbuf_cur = align(argbuf_cur, PyObjCRT_AlignOfType(argtype+1));
+ arg = argbuf + argbuf_cur;
+ argbuf_cur += PyObjCRT_SizeOfType(argtype+1);
+ error = depythonify_c_value (
+ argtype+1,
+ argument,
+ arg);
+
+ arglist[i] = signature_to_ffi_type(
+ argtype+1);
+ values[i] = arg;
+
+ }
+ break;
+ default:
+ argbuf_cur = align(argbuf_cur, PyObjCRT_AlignOfType(argtype));
+ arg = argbuf + argbuf_cur;
+ argbuf_cur += PyObjCRT_SizeOfType(argtype);
+
+ error = depythonify_c_value (
+ argtype,
+ argument,
+ arg);
+
+ arglist[i] = signature_to_ffi_type(argtype);
+ values[i] = arg;
+ }
+
+ if (error == -1) {
+ return -1;
+ }
+ py_arg++;
+ }
+ }
+ return 0;
+}
+
+/* XXX: Need to refactor to deal with 'self' */
+{
+ PyObject* objc_result = NULL;
+ PyObject* result = NULL;
+ int py_arg;
+ void* arg;
+ Py_ssize_t i;
+
+ if ( (*methinfo->rettype != _C_VOID) /* && ([methinfo isOneway] == NO) */ ) {
+ objc_result = pythonify_c_return_value (methinfo->rettype, pRetval);
+ } else {
+ Py_INCREF(Py_None);
+ objc_result = Py_None;
+ }
+
+ /* XXX: This is for selectors only, need to change this !!!! */
+
+ if (self != NULL && objc_result != self
+ && PyObjCObject_Check(self) && PyObjCObject_Check(objc_result)
+ && !(flags & PyObjCSelector_kRETURNS_UNINITIALIZED)
+ && (((PyObjCObject*)self)->flags & PyObjCObject_kUNINITIALIZED)) {
+ [PyObjCObject_GetObject(objc_result) release];
+ PyObjCObject_ClearObject(self);
+ }
+
+ if (byref_out_count == 0) {
+ return objc_result;
+
+ } else {
+
+ if (*methinfo->rettype == _C_VOID) {
+ if (byref_out_count > 1) {
+ result = PyTuple_New(byref_out_count);
+ if (result == NULL) {
+ return NULL;
+ }
+ } else {
+ result = NULL;
+ }
+ Py_DECREF(objc_result);
+ py_arg = 0;
+ } else {
+ result = PyTuple_New(byref_out_count+1);
+ if (result == NULL) {
+ return NULL;
+ }
+ PyTuple_SET_ITEM(result, 0, objc_result);
+ py_arg = 1;
+ }
+ objc_result = NULL;
+
+ for (i = argOffset; i < methinfo->nargs; i++) {
+ const char *argtype = methinfo->argtype[i];
+ PyObject* v;
+
+ switch (*argtype) {
+ case _C_INOUT:
+ case _C_OUT:
+ if (argtype[1] == _C_PTR) {
+ arg = byref[i];
+
+ if (arg == NULL) {
+ v = PyObjC_NULL;
+ Py_INCREF(v);
+ } else {
+ v = pythonify_c_value(argtype+2, arg);
+ }
+ if (!v) goto error_cleanup;
+
+ if (result != NULL) {
+ if (PyTuple_SetItem(result,
+ py_arg++, v) < 0) {
+
+ Py_DECREF(v);
+ goto error_cleanup;
+ }
+ } else {
+ result = v;
+ }
+ }
+ break;
+ }
+ }
+ }
+ return result;
+
+error_cleanup:
+ Py_XDECREF(result);
+ return NULL;
+}
diff --git a/Objective-C/libobjcl.h b/Objective-C/libobjcl.h
index 5ca49f4..b2c012b 100644
--- a/Objective-C/libobjcl.h
+++ b/Objective-C/libobjcl.h
@@ -5,9 +5,6 @@
#ifdef USE_LIBFFI
#include <ffi.h>
-#else
-#include <vacall.h>
-#include <avcall.h>
#endif
@@ -54,7 +51,6 @@ void
objcl_invoke_with_types (void *receiver,
SEL method_selector,
char *(types[]),
- size_t arg_sizes[],
id *exception,
void *return_value,
int argc,
diff --git a/Objective-C/libobjcl.m b/Objective-C/libobjcl.m
index bd1e410..3bcdf4b 100644
--- a/Objective-C/libobjcl.m
+++ b/Objective-C/libobjcl.m
@@ -260,8 +260,7 @@ objcl_invoke_method (OBJCL_OBJ_DATA receiver,
void
objcl_invoke_with_types (void *receiver,
SEL method_selector,
- char *(types[]),
- size_t arg_sizes[],
+ char *types[],
id *exception,
void *return_value,
int argc,
@@ -271,6 +270,9 @@ objcl_invoke_with_types (void *receiver,
IMP method;
int i;
+ char *return_type = types[0];
+ char **arg_types = types + 1;
+
*exception = NULL;
#ifdef __NEXT_RUNTIME__