Author: Wim Lavrijsen <[email protected]>
Branch: reflex-support
Changeset: r47192:2aee950f746f
Date: 2011-09-09 14:25 -0700
http://bitbucket.org/pypy/pypy/changeset/2aee950f746f/
Log: object identity conservation
diff --git a/pypy/module/cppyy/capi/__init__.py
b/pypy/module/cppyy/capi/__init__.py
--- a/pypy/module/cppyy/capi/__init__.py
+++ b/pypy/module/cppyy/capi/__init__.py
@@ -5,8 +5,12 @@
#import cint_capi as backend
+C_NULL_VOIDP = lltype.nullptr(rffi.VOIDP.TO)
+
C_TYPEHANDLE = rffi.LONG
+C_NULL_TYPEHANDLE = rffi.cast(C_TYPEHANDLE, C_NULL_VOIDP)
C_OBJECT = rffi.VOIDP
+C_NULL_OBJECT = C_NULL_VOIDP
C_METHPTRGETTER = lltype.FuncType([C_OBJECT], rffi.VOIDP)
C_METHPTRGETTER_PTR = lltype.Ptr(C_METHPTRGETTER)
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
@@ -266,6 +266,10 @@
ptr_result = rffi.cast(rffi.VOIDP, long_result)
return interp_cppyy.new_instance(space, w_returntype, self.cpptype,
ptr_result, True)
+ def execute_libffi(self, space, w_returntype, libffifunc, argchain):
+ from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
+ raise FastCallNotPossible
+
_executors = {}
def get_executor(space, name):
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
@@ -7,16 +7,15 @@
from pypy.rpython.lltypesystem import rffi, lltype
-from pypy.rlib import libffi, rdynload
+from pypy.rlib import libffi, rdynload, rweakref
from pypy.rlib import jit, debug
from pypy.module.cppyy import converter, executor, helper
+
class FastCallNotPossible(Exception):
pass
-NULL_VOIDP = lltype.nullptr(rffi.VOIDP.TO)
-
def _direct_ptradd(ptr, offset): # TODO: factor out with convert.py
address = rffi.cast(rffi.CCHARP, ptr)
return rffi.cast(rffi.VOIDP, lltype.direct_ptradd(address, offset))
@@ -32,7 +31,7 @@
class State(object):
def __init__(self, space):
self.cpptype_cache = {
- "void" : W_CPPType(space, "void", rffi.cast(capi.C_TYPEHANDLE,
NULL_VOIDP)) }
+ "void" : W_CPPType(space, "void", capi.C_NULL_TYPEHANDLE) }
self.cpptemplatetype_cache = {}
@unwrap_spec(name=str)
@@ -254,7 +253,7 @@
cppinstance.cppclass.handle, self.scope_handle,
cppinstance.rawobject)
cppthis = _direct_ptradd(cppinstance.rawobject, offset)
else:
- cppthis = NULL_VOIDP
+ cppthis = capi.C_NULL_OBJECT
return cppthis
@jit.unroll_safe
@@ -556,8 +555,9 @@
def destruct(self):
assert isinstance(self, W_CPPInstance)
if self.rawobject:
+ memory_regulator.unregister(self)
capi.c_destruct(self.cppclass.handle, self.rawobject)
- self.rawobject = NULL_VOIDP
+ self.rawobject = capi.C_NULL_OBJECT
def __del__(self):
if self.python_owns:
@@ -574,13 +574,43 @@
)
W_CPPInstance.typedef.acceptable_as_base_class = True
-def new_instance(space, w_type, cpptype, rawptr, owns):
+
+class MemoryRegulator:
+ # TODO: (?) An object address is not unique if e.g. the class has a
+ # public data member of class type at the start of its definition and
+ # has no virtual functions. A _key class that hashes on address and
+ # type would be better, but my attempt failed in the rtyper, claiming
+ # a call on None ("None()") and needed a default ctor. (??)
+ # Note that for now, the associated test carries an m_padding to make
+ # a difference in the addresses.
+ def __init__(self):
+ self.objects = rweakref.RWeakValueDictionary(int, W_CPPInstance)
+
+ def register(self, obj):
+ int_address = int(rffi.cast(rffi.LONG, obj.rawobject))
+ self.objects.set(int_address, obj)
+
+ def unregister(self, obj):
+ int_address = int(rffi.cast(rffi.LONG, obj.rawobject))
+ self.objects.set(int_address, None)
+
+ def retrieve(self, address):
+ int_address = int(rffi.cast(rffi.LONG, address))
+ return self.objects.get(int_address)
+
+memory_regulator = MemoryRegulator()
+
+
+def new_instance(space, w_type, cpptype, rawobject, python_owns):
+ obj = memory_regulator.retrieve(rawobject)
+ if obj and obj.cppclass == cpptype:
+ return obj
w_cppinstance = space.allocate_instance(W_CPPInstance, w_type)
cppinstance = space.interp_w(W_CPPInstance, w_cppinstance,
can_be_None=False)
- W_CPPInstance.__init__(cppinstance, space, cpptype, rawptr, owns)
+ W_CPPInstance.__init__(cppinstance, space, cpptype, rawobject, python_owns)
+ memory_regulator.register(cppinstance)
return w_cppinstance
-
@unwrap_spec(cppinstance=W_CPPInstance)
def addressof(space, cppinstance):
address = rffi.cast(rffi.LONG, cppinstance.rawobject)
@@ -591,4 +621,9 @@
rawobject = rffi.cast(rffi.VOIDP, address)
w_cpptype = space.findattr(w_type, space.wrap("_cpp_proxy"))
cpptype = space.interp_w(W_CPPType, w_cpptype, can_be_None=False)
+
+ obj = memory_regulator.retrieve(rawobject)
+ if obj and obj.cppclass == cpptype:
+ return obj
+
return new_instance(space, w_type, cpptype, rawobject, owns)
diff --git a/pypy/module/cppyy/test/advancedcpp.cxx
b/pypy/module/cppyy/test/advancedcpp.cxx
--- a/pypy/module/cppyy/test/advancedcpp.cxx
+++ b/pypy/module/cppyy/test/advancedcpp.cxx
@@ -60,7 +60,7 @@
double my_global_array[500];
-// for life-line testing
+// for life-line and identity testing
int some_class_with_data::some_data::s_num_data = 0;
diff --git a/pypy/module/cppyy/test/advancedcpp.h
b/pypy/module/cppyy/test/advancedcpp.h
--- a/pypy/module/cppyy/test/advancedcpp.h
+++ b/pypy/module/cppyy/test/advancedcpp.h
@@ -256,7 +256,7 @@
//===========================================================================
-class some_class_with_data { // for life-line testing
+class some_class_with_data { // for life-line and identity testing
public:
class some_data {
public:
@@ -275,6 +275,7 @@
return m_data;
}
+ int m_padding;
some_data m_data;
};
diff --git a/pypy/module/cppyy/test/advancedcpp.xml
b/pypy/module/cppyy/test/advancedcpp.xml
--- a/pypy/module/cppyy/test/advancedcpp.xml
+++ b/pypy/module/cppyy/test/advancedcpp.xml
@@ -26,6 +26,9 @@
<class name="some_abstract_class" />
<class name="some_concrete_class" />
+ <class name="some_convertible" />
+ <class name="some_class_with_data" />
+ <class name="some_class_with_data::some_data" />
<class name="pointer_pass" />
diff --git a/pypy/module/cppyy/test/advancedcpp_LinkDef.h
b/pypy/module/cppyy/test/advancedcpp_LinkDef.h
--- a/pypy/module/cppyy/test/advancedcpp_LinkDef.h
+++ b/pypy/module/cppyy/test/advancedcpp_LinkDef.h
@@ -40,6 +40,9 @@
#pragma link C++ class some_abstract_class;
#pragma link C++ class some_concrete_class;
+#pragma link C++ class some_convertible;
+#pragma link C++ class some_class_with_data;
+#pragma link C++ class some_class_with_data::some_data;
#pragma link C++ class pointer_pass;
diff --git a/pypy/module/cppyy/test/test_advancedcpp.py
b/pypy/module/cppyy/test/test_advancedcpp.py
--- a/pypy/module/cppyy/test/test_advancedcpp.py
+++ b/pypy/module/cppyy/test/test_advancedcpp.py
@@ -357,7 +357,38 @@
assert o == cppyy.bind_object(addr, o.__class__)
#assert o == cppyy.bind_object(addr, "some_concrete_class")
- def test10_multi_methods(self):
+ def test10_object_identity(self):
+ """Test object identity"""
+
+ import cppyy
+ some_concrete_class = cppyy.gbl.some_concrete_class
+ some_class_with_data = cppyy.gbl.some_class_with_data
+
+ o = some_concrete_class()
+ addr = cppyy.addressof(o)
+
+ o2 = cppyy.bind_object(addr, some_concrete_class)
+ assert o is o2
+
+ o3 = cppyy.bind_object(addr, some_class_with_data)
+ assert not o is o3
+
+ d1 = some_class_with_data()
+ d2 = d1.gime_copy()
+ assert not d1 is d2
+
+ dd1a = d1.gime_data()
+ dd1b = d1.gime_data()
+ assert dd1a is dd1b
+
+ dd2 = d2.gime_data()
+ assert not dd1a is dd2
+ assert not dd1b is dd2
+
+ d2.destruct()
+ d1.destruct()
+
+ def test11_multi_methods(self):
"""Test calling of methods from multiple inheritance"""
import cppyy
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
@@ -237,6 +237,7 @@
pl_a = example01_class.staticCyclePayload(pl, 66.)
pl_a.getData() == 66.
assert payload_class.count == 1
+ pl_a = None
pl = None
gc.collect()
assert payload_class.count == 0
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit