[pypy-svn] r72603 - in pypy/branch/cpython-extension/pypy/module/cpyext: . test

xoraxax at codespeak.net xoraxax at codespeak.net
Tue Mar 23 01:52:20 CET 2010


Author: xoraxax
Date: Tue Mar 23 01:52:18 2010
New Revision: 72603

Modified:
   pypy/branch/cpython-extension/pypy/module/cpyext/api.py
   pypy/branch/cpython-extension/pypy/module/cpyext/macros.py
   pypy/branch/cpython-extension/pypy/module/cpyext/methodobject.py
   pypy/branch/cpython-extension/pypy/module/cpyext/object.py
   pypy/branch/cpython-extension/pypy/module/cpyext/test/test_cpyext.py
   pypy/branch/cpython-extension/pypy/module/cpyext/typeobject.py
Log:
Reworked memory handling, please review.

Modified: pypy/branch/cpython-extension/pypy/module/cpyext/api.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/api.py	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/api.py	Tue Mar 23 01:52:18 2010
@@ -45,16 +45,17 @@
 
 
 class ApiFunction:
-    def __init__(self, argtypes, restype, callable, borrowed):
+    def __init__(self, argtypes, restype, callable, borrowed, dont_deref):
         self.argtypes = argtypes
         self.restype = restype
         self.functype = lltype.Ptr(lltype.FuncType(argtypes, restype))
         self.callable = callable
         self.borrowed = borrowed
+        self.dont_deref = dont_deref
 
-def cpython_api(argtypes, restype, borrowed=False):
+def cpython_api(argtypes, restype, borrowed=False, dont_deref=False):
     def decorate(func):
-        api_function = ApiFunction(argtypes, restype, func, borrowed)
+        api_function = ApiFunction(argtypes, restype, func, borrowed, dont_deref)
         FUNCTIONS[func.func_name] = api_function
         func.api_func = api_function
         return func
@@ -177,6 +178,47 @@
     w_obj_type = space.type(w_obj)
     return int(space.is_w(w_obj_type, w_type) or space.is_true(space.issubtype(w_obj_type, w_type)))
 
+def make_wrapper(space, callable):
+    def wrapper(*args):
+        boxed_args = []
+        # XXX use unrolling_iterable here
+        print >>sys.stderr, callable,
+        for i, typ in enumerate(callable.api_func.argtypes):
+            arg = args[i]
+            if typ is PyObject and not callable.api_func.dont_deref:
+                arg = from_ref(space, arg)
+            boxed_args.append(arg)
+        state = space.fromcache(State)
+        try:
+            retval = callable(space, *boxed_args)
+            print >>sys.stderr, " DONE"
+        except OperationError, e:
+            e.normalize_exception(space)
+            state.exc_type = e.w_type
+            state.exc_value = e.get_w_value(space)
+        except BaseException, e:
+            state.exc_type = space.w_SystemError
+            state.exc_value = space.wrap(str(e))
+            import traceback
+            traceback.print_exc()
+
+        if state.exc_value is not None:
+            restype = callable.api_func.restype
+            if restype is lltype.Void:
+                return
+            if restype is PyObject:
+                return lltype.nullptr(PyObject.TO)
+            if restype in (Py_ssize_t, rffi.INT_real):
+                return rffi.cast(restype, -1)
+            assert False, "Unknown return type"
+
+        if callable.api_func.restype is PyObject:
+            retval = make_ref(space, retval, borrowed=callable.api_func.borrowed)
+        if callable.api_func.restype is rffi.INT_real:
+            retval = rffi.cast(rffi.INT_real, retval)
+        return retval
+    return wrapper
+
 #_____________________________________________________
 # Build the bridge DLL, Allow extension DLLs to call
 # back into Pypy space functions
@@ -279,51 +321,11 @@
         ptr.value = ctypes.cast(ll2ctypes.lltype2ctypes(make_ref(space, w_obj)),
             ctypes.c_void_p).value
 
-    def make_wrapper(callable):
-        def wrapper(*args):
-            boxed_args = []
-            # XXX use unrolling_iterable here
-            print >>sys.stderr, callable,
-            for i, typ in enumerate(callable.api_func.argtypes):
-                arg = args[i]
-                if typ is PyObject:
-                    arg = from_ref(space, arg)
-                boxed_args.append(arg)
-            state = space.fromcache(State)
-            try:
-                retval = callable(space, *boxed_args)
-                print >>sys.stderr, " DONE"
-            except OperationError, e:
-                e.normalize_exception(space)
-                state.exc_type = e.w_type
-                state.exc_value = e.get_w_value(space)
-            except BaseException, e:
-                state.exc_type = space.w_SystemError
-                state.exc_value = space.wrap(str(e))
-                import traceback
-                traceback.print_exc()
-
-            if state.exc_value is not None:
-                restype = callable.api_func.restype
-                if restype is lltype.Void:
-                    return
-                if restype is PyObject:
-                    return lltype.nullptr(PyObject.TO)
-                if restype in (Py_ssize_t, rffi.INT_real):
-                    return rffi.cast(restype, -1)
-                assert False, "Unknown return type"
-
-            if callable.api_func.restype is PyObject:
-                retval = make_ref(space, retval, borrowed=callable.api_func.borrowed)
-            if callable.api_func.restype is rffi.INT_real:
-                retval = rffi.cast(rffi.INT_real, retval)
-            return retval
-        return wrapper
-
     # implement structure initialization code
     for name, func in FUNCTIONS.iteritems():
         pypyAPI[structindex[name]] = ctypes.cast(
-            ll2ctypes.lltype2ctypes(llhelper(func.functype, make_wrapper(func.callable))),
+            ll2ctypes.lltype2ctypes(llhelper(func.functype,
+                make_wrapper(space, func.callable))),
             ctypes.c_void_p)
 
     return modulename.new(ext='')

Modified: pypy/branch/cpython-extension/pypy/module/cpyext/macros.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/macros.py	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/macros.py	Tue Mar 23 01:52:18 2010
@@ -7,15 +7,15 @@
 # XXX Optimize these functions and put them into macro definitions
 @cpython_api([PyObject], lltype.Void)
 def Py_DECREF(space, w_obj):
+    print "DECREF", w_obj
     state = space.fromcache(State)
     obj = state.py_objects_w2r[w_obj]
     obj.c_obj_refcnt -= 1
     if obj.c_obj_refcnt == 0:
-        del state.py_objects_w2r[w_obj]
         ptr = ctypes.addressof(obj._obj._storage)
+        _Py_Dealloc(space, w_obj)
+        del state.py_objects_w2r[w_obj]
         del state.py_objects_r2w[ptr]
-        # XXX this will likely be somewhere else when we have grown a type object
-        lltype.free(obj, flavor='raw')
     else:
         assert obj.c_obj_refcnt > 0
     return
@@ -26,3 +26,19 @@
     obj = state.py_objects_w2r.get(w_obj)
     obj.c_obj_refcnt += 1
 
+
+def _Py_Dealloc(space, w_obj):
+    from pypy.module.cpyext.typeobject import PyTypeObjectPtr
+    from pypy.module.cpyext.methodobject import generic_cpy_call
+    state = space.fromcache(State)
+    w_type = space.type(w_obj)
+    pto = make_ref(space, w_type)
+    pto = rffi.cast(PyTypeObjectPtr, pto)
+    try:
+        print "Calling ", pto.c_tp_dealloc, "of", w_obj, "'s type which is", w_type
+        generic_cpy_call(space, pto.c_tp_dealloc, w_obj, decref_args=False)
+    finally:
+        # XXX uncommenting the next line gives double frees, why?
+        #Py_DECREF(space, w_type) # make_ref bumps refcount
+        pass
+

Modified: pypy/branch/cpython-extension/pypy/module/cpyext/methodobject.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/methodobject.py	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/methodobject.py	Tue Mar 23 01:52:18 2010
@@ -28,7 +28,9 @@
         raise
     return ret
 
-def generic_cpy_call(space, func, *args):
+def generic_cpy_call(space, func, *args, **kwargs):
+    decref_args = kwargs.pop("decref_args", False)
+    assert not decref_args
     boxed_args = []
     for arg in args: # XXX ur needed
         if isinstance(arg, W_Root) or arg is None:
@@ -37,13 +39,16 @@
             boxed_args.append(arg)
     result = func(*boxed_args)
     try:
-        ret = from_ref_ex(space, result)
-        Py_DECREF(space, ret)
-        return ret
+        FT = lltype.typeOf(func).TO
+        if FT.RESULT is not lltype.Void:
+            ret = from_ref_ex(space, result)
+            Py_DECREF(space, ret)
+            return ret
     finally:
-        for arg in args: # XXX ur needed
-            if arg is not None and isinstance(arg, W_Root):
-                Py_DECREF(space, arg)
+        if decref_args:
+            for arg in args: # XXX ur needed
+                if arg is not None and isinstance(arg, W_Root):
+                    Py_DECREF(space, arg)
 
 # XXX use Function as a parent class?
 class W_PyCFunctionObject(Wrappable):

Modified: pypy/branch/cpython-extension/pypy/module/cpyext/object.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/object.py	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/object.py	Tue Mar 23 01:52:18 2010
@@ -1,5 +1,6 @@
 from pypy.rpython.lltypesystem import rffi, lltype
-from pypy.module.cpyext.api import cpython_api, PyObject, make_ref
+from pypy.module.cpyext.api import cpython_api, PyObject, make_ref, from_ref
+from pypy.module.cpyext.state import State
 from pypy.module.cpyext.typeobject import PyTypeObjectPtr, W_PyCTypeObject, W_PyCObject
 from pypy.objspace.std.objectobject import W_ObjectObject
 
@@ -8,9 +9,17 @@
 def _PyObject_New(space, w_type):
     if isinstance(w_type, W_PyCTypeObject):
         w_pycobj = space.allocate_instance(W_PyCObject, w_type)
+        w_pycobj.__init__(space)
         return w_pycobj
     assert False, "Please add more cases in get_cls_for_type_object!"
 
 @cpython_api([rffi.VOIDP_real], lltype.Void)
-def PyObject_Del(space, w_obj):
-    pass # XXX move lltype.free here
+def PyObject_Del(space, obj):
+    # XXX cast object according to the basesize in pto
+    lltype.free(obj, flavor='raw')
+
+ at cpython_api([PyObject], lltype.Void, dont_deref=True)
+def PyObject_Del_cast(space, obj):
+    # XXX cast object according to the basesize in pto
+    lltype.free(obj, flavor='raw')
+

Modified: pypy/branch/cpython-extension/pypy/module/cpyext/test/test_cpyext.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/test/test_cpyext.py	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/test/test_cpyext.py	Tue Mar 23 01:52:18 2010
@@ -117,7 +117,6 @@
                                self.space.wrap('foo'))
             self.space.delitem(self.space.sys.get('modules'),
                                self.space.wrap('foo'))
-            Py_DECREF(self.space, w_mod)
         except OperationError:
             pass
         self.space.fromcache(State).print_refcounts()

Modified: pypy/branch/cpython-extension/pypy/module/cpyext/typeobject.py
==============================================================================
--- pypy/branch/cpython-extension/pypy/module/cpyext/typeobject.py	(original)
+++ pypy/branch/cpython-extension/pypy/module/cpyext/typeobject.py	Tue Mar 23 01:52:18 2010
@@ -2,6 +2,7 @@
 
 from pypy.rpython.lltypesystem import rffi, lltype
 from pypy.rpython.lltypesystem.lltype import Ptr, FuncType, Void
+from pypy.rpython.annlowlevel import llhelper
 from pypy.interpreter.gateway import ObjSpace, W_Root
 from pypy.interpreter.gateway import interp2app, unwrap_spec
 from pypy.interpreter.baseobjspace import Wrappable
@@ -11,6 +12,7 @@
 from pypy.module.cpyext.api import cpython_api, cpython_api_c, cpython_struct
 from pypy.module.cpyext.api import PyObject, PyVarObjectFields, Py_ssize_t
 from pypy.module.cpyext.api import Py_TPFLAGS_READYING, Py_TPFLAGS_READY
+from pypy.module.cpyext.api import make_wrapper
 from pypy.interpreter.module import Module
 from pypy.module.cpyext.modsupport import PyMethodDef, convert_method_defs
 from pypy.module.cpyext.state import State
@@ -204,16 +206,25 @@
             bases_w or [space.w_object], dict_w)
 
 class W_PyCObject(Wrappable):
-    pass
+    def __init__(self, space):
+        self.space = space
+
+    def __del__(self):
+        space = self.space
+        self.clear_all_weakrefs()
+        w_type = space.type(self)
+        assert isinstance(w_type, W_PyCTypeObject)
+        pto = w_type.pto
+        generic_cpy_call(space, pto.c_tp_dealloc, self)
 
- at unwrap_spec(ObjSpace, W_Root, W_Root)
-def cobject_descr_getattr(space, w_obj, w_name):
-    name = space.str_w(w_name)
-    return w_name
 
 
 def allocate_type_obj(space, w_obj):
+    from pypy.module.cpyext.object import PyObject_Del_cast
     pto = lltype.malloc(PyTypeObject, None, flavor="raw")
+    callable = PyObject_Del_cast
+    pto.c_tp_dealloc = llhelper(callable.api_func.functype,
+            make_wrapper(space, callable))
     #  XXX fill slots in pto
     return pto
 



More information about the Pypy-commit mailing list