Commits

Ronald Oussoren committed b48a121

- Disable the free-list for PyObjCObjects, the code is causing crashes with
Python 2.2 and isn't enough of a win to bother with fixing it right now.

- don't forget to update the version number and release date during a release.
- PyObjCTools.KeyValueCodingSupport is already gone, also remove its
testcases.
- Don't create a full proxy object for self during the call to __del__ of
proxied ObjC objects.

  • Participants
  • Parent commits 25a6f4a

Comments (0)

Files changed (5)

pyobjc/Doc/release-process.txt

 
 Build the release tarball and dmg:
 
+* Add the correct date to the NEWS file, and set the right version in
+  ``Modules/objc/pyobjc.h``.
+
 * Run Scripts/make_distrib.py
 
 * Create an empty disk image (named ``PyObjC X.Y``) and copy the installer

pyobjc/Lib/Foundation/test/test_keyvaluecoding.py

-import unittest
-import objc
-
-from Foundation import *
-from PyObjCTools import KeyValueCodingSupport
-
-class StraightPython(object, KeyValueCodingSupport.KeyValueCoding):
-    foo = 21
-    _bar = 42
-    baz = { "bob" : "tail" }
-    _didBar = 0
-
-    def bar(self):
-        self._didBar = 1
-        return self._bar
-    def setBar(self, aValue):
-        self._bar = aValue
-    def didBar(self): 
-        return self._didBar
-
-class PyObjCMix(NSObject):
-
-    foo = 21
-    _bar = 42
-    baz = { "bob" : "tail" }
-    _didBar = 0
-
-    def bar(self):
-        self._didBar = 1
-        return self._bar
-    def setBar(self, aValue):
-        self._bar = aValue
-
-    def didBar(self): 
-        return self._didBar
-
-    def valueForKey_(self, aKey):
-        try:
-            v = KeyValueCodingSupport.getValueForKey_(self, aKey)
-            return v
-        except KeyError:
-            zuper = super(self.__class__, self)
-            if zuper.respondsToSelector_("valueForKey:"):
-                return zuper.valueForKey_(aKey)
-
-        raise KeyError, aKey
-
-class TestKeyValueCoding(unittest.TestCase):
-    def testValueForKey(self):
-        KeyValueCodingSupport.addKeyValueBridgeToClass(PyObjCMix)
-
-        a = StraightPython()
-        b = PyObjCMix.new()
-
-        self.assertEqual(a.valueForKey_("foo"), 21)
-        self.assertEqual(b.valueForKey_("foo"), 21)
-        self.assertEqual(a.didBar(), 0)
-        self.assertEqual(b.didBar(), 0)
-        self.assertEqual(a.valueForKey_("bar"), 42)
-        self.assertEqual(b.valueForKey_("bar"), 42)
-        self.assertEqual(a.didBar(), 1)
-        self.assertEqual(b.didBar(), 1)
-
-if __name__ == '__main__':
-    unittest.main( )

pyobjc/Modules/objc/class-builder.m

 
 	delmethod = PyObjCClass_GetDelMethod(cls);
 	if (delmethod != NULL) {
-		PyObject* s = PyObjCObject_New(self);
+		PyObject* s = _PyObjCObject_NewDeallocHelper(self);
 		obj = PyObject_CallFunction(delmethod, "O", s);
-		Py_DECREF(s);
+		_PyObjCObject_FreeDeallocHelper(s);
 		if (obj == NULL) {
 			PyErr_WriteUnraisable(delmethod);
 		} else {

pyobjc/Modules/objc/objc-object.m

  * - to delete an object: obj_freelist[obj_freelist_top++] = OBJ
  * - to create an object: OBJ = obj_freelist[--obj_freelist_top];
  */
+#if 0
 #define FREELIST_SIZE 1024
 
 static PyObject* obj_freelist[FREELIST_SIZE];
 static int obj_freelist_top = 0;
+#endif
 
 
 static NSMapTable* proxy_dict = NULL;
 		((PyObjCObject*)obj)->objc_object = nil;
 	}
 
+#ifdef FREELIST_SIZE
 	/* Push self onto the freelist */
 	if (obj_freelist_top == FREELIST_SIZE) {
 		obj->ob_type->tp_free(obj);
 	} else {
 		obj_freelist[obj_freelist_top++] = obj;
+		obj->ob_refcnt = 0xDEADBEEF;
 	}
+#else
+	obj->ob_type->tp_free(obj);
+#endif
 }
 
 
 #endif
 };
 
+/*
+ *  Allocate a proxy object for use during the call of __del__,
+ *  this isn't a full-featured proxy object.
+ */
+PyObject* 
+_PyObjCObject_NewDeallocHelper(id objc_object)
+{
+	Class cls; 
+	PyObject* res;
+	PyTypeObject* cls_type;
+
+	cls = GETISA(objc_object);
+	cls_type = (PyTypeObject*)PyObjCClass_New(cls);
+	if (cls_type == NULL) {
+		return NULL;
+	}
+
+#ifdef FREELIST_SIZE
+	if (obj_freelist_top == 0) {
+		res = cls_type->tp_alloc(cls_type, 0);
+		if (res == NULL) {
+			return NULL;
+		}
+	} else {
+		res = obj_freelist[obj_freelist_top-1];
+		obj_freelist_top -= 1;
+		if (res->ob_refcnt != 0xDEADBEEF) abort();
+		res->ob_refcnt = 1;
+		res->ob_type = cls_type;
+	}
+#else
+	res = cls_type->tp_alloc(cls_type, 0);
+	if (res == NULL) {
+		return NULL;
+	}
+#endif
+
+	PyObjCClass_CheckMethodList((PyObject*)res->ob_type, 1);
+	
+	((PyObjCObject*)res)->objc_object = objc_object;
+	((PyObjCObject*)res)->flags = 0;
+	return res;
+}
+
+/*
+ * Free the object allocated using '_PyObCObject_NewDeallocHelper'. If the
+ * object has a refcnt > 1 when calling this function, the object is 
+ * promoted to a full proxy object. This should only happen when someone
+ * revives the object, it is unclear whether the ObjC runtime will accept
+ * reviveing.
+ */
+void
+_PyObjCObject_FreeDeallocHelper(PyObject* obj)
+{
+	if (obj->ob_refcnt != 1) {
+		/* Someone revived this object, hopefully 
+		 * Objective-C can deal with this.
+		 */
+		id objc_object = PyObjCObject_GetObject(obj);
+
+		Py_DECREF(obj);
+
+		if (strcmp(GETISA(objc_object)->name, 
+						"NSAutoreleasePool") != 0) {
+			/* NSAutoreleasePool doesn't like retain */
+			[objc_object retain];
+		}
+
+		if (register_proxy(obj) < 0) {
+			NSLog(@"Couldn't register revived proxy object!");
+		}
+		return;
+	}
+
+#ifdef FREELIST_SIZE
+	if (obj_freelist_top == FREELIST_SIZE) {
+		obj->ob_type->tp_free(obj);
+	} else {
+		obj_freelist[obj_freelist_top++] = obj;
+		obj->ob_refcnt = 0xDEADBEEF;
+	}
+#else
+	obj->ob_type->tp_free(obj);
+#endif
+
+}
 
 
 PyObject* 
 		return NULL;
 	}
 
+#ifdef FREELIST_SIZE
 	if (obj_freelist_top == 0) {
 		res = cls_type->tp_alloc(cls_type, 0);
 		if (res == NULL) {
 	} else {
 		res = obj_freelist[obj_freelist_top-1];
 		obj_freelist_top -= 1;
+		if (res->ob_refcnt != 0xDEADBEEF) abort();
 		res->ob_refcnt = 1;
 		res->ob_type = cls_type;
 	}
+#else
+	res = cls_type->tp_alloc(cls_type, 0);
+	if (res == NULL) {
+		return NULL;
+	}
+#endif
 
 	/* This should be in the tp_alloc for the new class, but 
 	 * adding a tp_alloc to PyObjCClass_Type doesn't seem to help

pyobjc/Modules/objc/pyobjc.h

 id 	  PyObjCObject_GetObject(PyObject* object);
 void 	  PyObjCObject_ClearObject(PyObject* object);
 #define   PyObjCObject_GetObject(object) (((PyObjCObject*)(object))->objc_object)
+void _PyObjCObject_FreeDeallocHelper(PyObject* obj);
+PyObject* _PyObjCObject_NewDeallocHelper(id objc_object);
 
 
 /* in class-descriptor.m */