Author: Wim Lavrijsen <wlavrij...@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 _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit