[pypy-commit] pypy reflex-support: basic memory ownership rules

wlav noreply at buildbot.pypy.org
Tue Jul 12 18:02:15 CEST 2011


Author: Wim Lavrijsen <WLavrijsen at lbl.gov>
Branch: reflex-support
Changeset: r45516:2a9e452cb674
Date: 2011-07-12 09:00 -0700
http://bitbucket.org/pypy/pypy/changeset/2a9e452cb674/

Log:	basic memory ownership rules

diff --git a/pypy/module/cppyy/executor.py b/pypy/module/cppyy/executor.py
--- a/pypy/module/cppyy/executor.py
+++ b/pypy/module/cppyy/executor.py
@@ -189,7 +189,7 @@
         from pypy.module.cppyy import interp_cppyy
         long_result = capi.c_call_l(func.cpptype.handle, func.method_index, cppthis, num_args, args)
         ptr_result = rffi.cast(rffi.VOIDP, long_result)
-        return interp_cppyy.W_CPPInstance(space, self.cpptype, ptr_result)
+        return interp_cppyy.W_CPPInstance(space, self.cpptype, ptr_result, False)
 
 class InstanceExecutor(InstancePtrExecutor):
     _immutable_ = True
@@ -199,8 +199,7 @@
         long_result = capi.c_call_o(
             func.cpptype.handle, func.method_index, cppthis, num_args, args, self.cpptype.handle)
         ptr_result = rffi.cast(rffi.VOIDP, long_result)
-        # TODO: take ownership of result ...
-        return interp_cppyy.W_CPPInstance(space, self.cpptype, ptr_result)
+        return interp_cppyy.W_CPPInstance(space, self.cpptype, ptr_result, True)
 
 
 _executors = {}
diff --git a/pypy/module/cppyy/interp_cppyy.py b/pypy/module/cppyy/interp_cppyy.py
--- a/pypy/module/cppyy/interp_cppyy.py
+++ b/pypy/module/cppyy/interp_cppyy.py
@@ -227,7 +227,7 @@
         except Exception, e:
             capi.c_deallocate(self.cpptype.handle, newthis)
             raise
-        return W_CPPInstance(self.space, self.cpptype, newthis)
+        return W_CPPInstance(self.space, self.cpptype, newthis, True)
 
 
 class W_CPPOverload(Wrappable):
@@ -521,10 +521,11 @@
 class W_CPPInstance(Wrappable):
     _immutable_fields_ = ["cppclass"]
 
-    def __init__(self, space, cppclass, rawobject):
+    def __init__(self, space, cppclass, rawobject, python_owns):
         self.space = space
         self.cppclass = cppclass
         self.rawobject = rawobject
+        self.python_owns = python_owns
 
     def _nullcheck(self):
         if not self.rawobject:
@@ -535,8 +536,13 @@
         return overload.call(self.rawobject, args_w)
 
     def destruct(self):
-        capi.c_destruct(self.cppclass.handle, self.rawobject)
-        self.rawobject = NULL_VOIDP
+        if self.rawobject:
+            capi.c_destruct(self.cppclass.handle, self.rawobject)
+            self.rawobject = NULL_VOIDP
+
+    def __del__(self):
+        if self.python_owns:
+            self.destruct()
 
 W_CPPInstance.typedef = TypeDef(
     'CPPInstance',
diff --git a/pypy/module/cppyy/test/example01.cxx b/pypy/module/cppyy/test/example01.cxx
--- a/pypy/module/cppyy/test/example01.cxx
+++ b/pypy/module/cppyy/test/example01.cxx
@@ -7,12 +7,28 @@
 #include "example01.h"
 
 //===========================================================================
-payload::payload(double d) : m_data(d) {}
-payload::payload(const payload& p) : m_data(p.m_data) {}
+payload::payload(double d) : m_data(d) {
+    count++;
+}
+payload::payload(const payload& p) : m_data(p.m_data) {
+    count++;
+}
+payload& payload::operator=(const payload& p) {
+    if (this != &p) {
+        m_data = p.m_data;
+    }
+    return *this;
+}
+payload::~payload() {
+    count--;
+}
 
 double payload::getData() { return m_data; }
 void payload::setData(double d) { m_data = d; }
 
+// class-level data
+int payload::count = 0;
+
 
 //===========================================================================
 example01::example01() : m_somedata(-99) {
diff --git a/pypy/module/cppyy/test/example01.h b/pypy/module/cppyy/test/example01.h
--- a/pypy/module/cppyy/test/example01.h
+++ b/pypy/module/cppyy/test/example01.h
@@ -2,10 +2,15 @@
 public:
     payload(double d);
     payload(const payload& p);
+    payload& operator=(const payload& e);
+    ~payload();
 
     double getData();
     void setData(double d);
 
+public:        // class-level data
+    static int count;
+
 private:
     double m_data;
 };
diff --git a/pypy/module/cppyy/test/test_cppyy.py b/pypy/module/cppyy/test/test_cppyy.py
--- a/pypy/module/cppyy/test/test_cppyy.py
+++ b/pypy/module/cppyy/test/test_cppyy.py
@@ -111,6 +111,40 @@
         e2.destruct()
         assert t.invoke(t.get_overload("getCount")) == 0
 
+        e2.destruct()
+        assert t.invoke(t.get_overload("getCount")) == 0
+
+    def test_example01memory(self):
+        """Test memory destruction and integrity."""
+
+        import gc
+
+        t = self.example01
+
+        assert t.invoke(t.get_overload("getCount")) == 0
+
+        e1 = t.construct(7)
+        assert t.invoke(t.get_overload("getCount")) == 1
+        res = e1.invoke(t.get_overload("addDataToInt"), 4)
+        assert res == 11
+        res = e1.invoke(t.get_overload("addDataToInt"), -4)
+        assert res == 3
+        e1 = None
+        gc.collect()
+        assert t.invoke(t.get_overload("getCount")) == 0
+
+        e1 = t.construct(7)
+        e2 = t.construct(8)
+        assert t.invoke(t.get_overload("getCount")) == 2
+        e1 = None
+        gc.collect()
+        assert t.invoke(t.get_overload("getCount")) == 1
+	e2.destruct()
+        assert t.invoke(t.get_overload("getCount")) == 0
+        e2 = None
+        gc.collect()
+        assert t.invoke(t.get_overload("getCount")) == 0
+
     def test_example01method_double(self):
         """Test passing of a double and returning of double on a method"""
 
diff --git a/pypy/module/cppyy/test/test_pythonify.py b/pypy/module/cppyy/test/test_pythonify.py
--- a/pypy/module/cppyy/test/test_pythonify.py
+++ b/pypy/module/cppyy/test/test_pythonify.py
@@ -199,3 +199,44 @@
 
         assert cppyy.gbl.ns_example01.globalAddOneToInt(4) == 5
         assert cppyy.gbl.ns_example01.globalAddOneToInt(4) == 5
+
+    def test09_memory(self):
+        import cppyy, gc
+        example01_class = cppyy.gbl.example01
+        payload_class = cppyy.gbl.payload
+
+        pl = payload_class(3.14)
+        assert payload_class.count == 1
+        assert round(pl.getData()-3.14, 8) == 0
+
+        pl2 = example01_class.staticCopyCyclePayload(pl, 38.)
+        assert payload_class.count == 2
+        assert pl2.getData() == 38.
+        pl2 = None
+        gc.collect()
+        assert payload_class.count == 1
+
+        e = example01_class(14)
+
+        pl2 = e.copyCyclePayload(pl)
+        assert payload_class.count == 2
+        assert round(pl2.getData()-14., 8) == 0
+        pl2 = None
+        gc.collect()
+        assert payload_class.count == 1
+
+        pl = None
+        e = None
+        gc.collect()
+        assert payload_class.count == 0
+        assert example01_class.getCount() == 0
+
+        pl = payload_class(3.14)
+        pl_a = example01_class.staticCyclePayload(pl, 66.)
+        pl_a.getData() == 66.
+        assert payload_class.count == 1
+        pl = None
+        gc.collect()
+        assert payload_class.count == 0
+
+        # TODO: need ReferenceError on touching pl_a


More information about the pypy-commit mailing list