Commits

Ronald Oussoren committed f07c7a6

Another step closer to having a functional 64-bit build.

This version of PyObjC runs most of the unittests, but there are test failures
and crashes as well.

closure_pool.m is too simple right now, it should use a pool of closures to
avoid memory fragmentation. Furthermore one closure per page of memory is
overkill.

Comments (0)

Files changed (9)

pyobjc-core/Lib/objc/test/test_metadata.py

         self.assertRaises(ValueError, o.reverseArray_count_, objc.NULL, 0)
 
         a = (1.0, 2.0, 3.0, 4.0, 5.0)
+        n, v = o.nullreverseArray_count_(a, 4)
+        self.assertEquals(n, 1)
+        self.assertEquals(a, (1.0, 2.0, 3.0, 4.0, 5.0))
+        self.assertEquals(v, (4.0, 3.0, 2.0, 1.0))
+
+        a = (1.0, 2.0, 3.0, 4.0, 5.0)
         n, v = o.nullreverseArray_count_(a, 5)
         self.assertEquals(n, 1)
         self.assertEquals(a, (1.0, 2.0, 3.0, 4.0, 5.0))

pyobjc-core/Modules/objc/OC_PythonObject.m

 
 #include "pyobjc.h"
 #include "compile.h" /* From Python */
+#include <dlfcn.h>
 
 #include <stdarg.h>
 

pyobjc-core/Modules/objc/OC_PythonUnicode.m

 	 * needed, but the test below isn't good enough. Be heavy handed to
 	 * make sure we're right, rather than crashing sometimes anyway.
 	 */
+	/* FIXME2: in rare occasions we're trying to acquire the GIL during 
+	 * shutdown and if we're very unlucky this can happen after the 
+	 * GILState machinery has shut down...
+	 */
 #if 0
 	if ([self retainCount] == 1) {
 #endif

pyobjc-core/Modules/objc/closure_pool.h

+/*
+ * Closure require special memmory support on x86_64 and PPC64: executation must be
+ * explicitly enabled for the memory used for closure.
+ */
+#ifndef PyObjC_CLOSURE_POOL
+#define PyObjC_CLOSURE_POOL
+
+extern ffi_closure* PyObjC_malloc_closure(void);
+extern int PyObjC_free_closure(ffi_closure* cl);
+
+
+#endif /* PyObjC_CLOSURE_POOL */

pyobjc-core/Modules/objc/closure_pool.m

+/*
+ * First a trivial implementation, if this works out I'll write a more memory-efficient one
+ */
+#include "pyobjc.h"
+
+#include <sys/mman.h>
+
+ffi_closure* 
+PyObjC_malloc_closure(void)
+{
+	ffi_closure* page = mmap(NULL, sizeof(ffi_closure*),
+		PROT_READ|PROT_WRITE|PROT_EXEC,
+		MAP_PRIVATE|MAP_ANON, -1, 0);
+	if (page == (void*)-1) {
+		PyErr_NoMemory();
+		return NULL;
+	}
+	return page;
+}
+
+int
+PyObjC_free_closure(ffi_closure* cl)
+{
+	int rv = munmap(cl, sizeof(ffi_closure));
+	if (rv == -1) {
+		PyErr_NoMemory();
+		return -1;
+	}
+}

pyobjc-core/Modules/objc/libffi_support.m

 
 		case 'd': case 'i': case 'D':
 			/* INT */
+			if (*format == 'D') {
+				typecode = _C_LNG;
+			} 
+
 			if (typecode == _C_LNG_LNG) {
 				byref[curarg] = PyMem_Malloc(sizeof(long long));
 			
 		case 'o': case 'u': case 'x':
 		case 'X': case 'U': case 'O':
 			/* UNSIGNED */
+			if (*format == 'U' || *format == 'X') {
+				typecode = _C_LNG;
+			}
+
 			if (typecode == _C_LNG_LNG) {
 				byref[curarg] = PyMem_Malloc(sizeof(long long));
 				typecode = _C_ULNG_LNG;
 					sel_getName(*(SEL*)args[1]));
 				goto error;
 			}
-			*((int*)resp) = 0;
+			//*((int*)resp) = 0;
 		}
 
 	} else {
 	 * of bytes of storage needed for them. Note that arguments 0 and 1
 	 * are self and the selector, no need to count those.
 	 */
-	argbuf_len = resultSize;
+	argbuf_len = resultSize + 32;
 	r = PyObjCFFI_CountArguments(
 		methinfo, 2, 
 		&byref_in_count, 
 		arglist[1] = &ffi_type_pointer;
 		values[1] = &theSel;
 		msgResult = argbuf;
-		argbuf_cur = resultSize;
+		argbuf_cur = resultSize + 32;
 		
 	} else {
 		objc_superSetReceiver(super, self_obj);
 
 
 	/* And finally create the actual closure */
-	cl = PyMem_Malloc(sizeof(*cl));
+	/*cl = PyMem_Malloc(sizeof(*cl));*/
+	cl = PyObjC_malloc_closure();
 	if (cl == NULL) {
 		PyObjCFFI_FreeCIF(cif);
-		PyErr_NoMemory();
+		/*PyErr_NoMemory();*/
 		return NULL;
 	}
 
 	cl = (ffi_closure*)closure;
 	retval = cl->user_data;
 	PyObjCFFI_FreeCIF(cl->cif);
-	PyMem_Free(cl);
+	PyObjC_free_closure(cl); /* XXX: error handling */
 
 	return retval;
 }

pyobjc-core/Modules/objc/pyobjc.h

 #include "pyobjc-api.h"
 #include "registry.h"
 #include "corefoundation.h"
+#include "closure_pool.h"
 
 extern PyObject* PyObjCMethodAccessor_New(PyObject* base, int class_method);
 
    Note that the first version is slightly saver (see the documentation
    for with-statements for the details).
 
+- PyObjC can now run in 64-bit mode.
+
+  (at least somewhat, there are still hard crashes but most of the 
+  unittests now pass).
 
 Version 2.0.1 (...)
 -------------------

pyobjc-core/libffi-src/tests/testsuite/libffi.call/array.c

+/* Area:	ffi_call
+   Purpose:	Check strlen function call.
+   Limitations:	none.
+   PR:		none.
+   Originator:	From the original ffitest.c  */
+
+/* { dg-do run } */
+#include "ffitest.h"
+
+static int array_reverse(float *s, int len)
+{
+	int i;
+
+	for (i = 0; i < len/2;i++) {
+		float tmp = s[i];
+		s[i] = s[len-1-i];
+		s[len-1-i] = tmp;
+	}
+	return 1;
+}
+
+int main (void)
+{
+  ffi_cif cif;
+  ffi_type *args[MAX_ARGS];
+  void *values[MAX_ARGS];
+
+  int rint;
+  float value[] = { 1.0, 2.0, 3.0, 4.0, 5.0 };
+
+  struct X {
+	  int rint;
+	  float* input;
+	  int count;
+  } valbuf;
+
+  valbuf.input = value;
+  valbuf.count = 5;
+
+  args[0] = &ffi_type_pointer;
+  args[1] = &ffi_type_sint;
+  values[0] = (void*) &valbuf.input;
+  values[1] = (void*) &valbuf.count;
+
+  /* Initialize the cif */
+  CHECK(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, 
+		     &ffi_type_sint, args) == FFI_OK);
+
+  printf("%f\n", valbuf.input[0]);
+  
+  ffi_call(&cif, FFI_FN(array_reverse), &valbuf.rint, values);
+
+  printf("%f\n", valbuf.input[0]);
+  CHECK(valbuf.rint == 1);
+  CHECK(valbuf.count == 5);
+  CHECK(valbuf.input[0] == 5.0);
+  CHECK(valbuf.input[1] == 4.0);
+  CHECK(valbuf.input[2] == 3.0);
+  CHECK(valbuf.input[3] == 2.0);
+  CHECK(valbuf.input[4] == 1.0);
+
+  return 0;
+}
+