[pypy-commit] pypy reflex-support: allow lookup and creation of pythonized classes at the interpreter level to finish dynamic return type implementation

wlav noreply at buildbot.pypy.org
Wed Mar 14 14:27:02 CET 2012


Author: Wim Lavrijsen <WLavrijsen at lbl.gov>
Branch: reflex-support
Changeset: r53554:907ef031f4a4
Date: 2012-03-14 04:01 -0700
http://bitbucket.org/pypy/pypy/changeset/907ef031f4a4/

Log:	allow lookup and creation of pythonized classes at the interpreter
	level to finish dynamic return type implementation

diff --git a/pypy/module/cppyy/__init__.py b/pypy/module/cppyy/__init__.py
--- a/pypy/module/cppyy/__init__.py
+++ b/pypy/module/cppyy/__init__.py
@@ -8,6 +8,8 @@
         '_resolve_name'          : 'interp_cppyy.resolve_name',
         '_type_byname'           : 'interp_cppyy.type_byname',
         '_template_byname'       : 'interp_cppyy.template_byname',
+        '_set_class_generator'   : 'interp_cppyy.set_class_generator',
+        '_register_class'        : 'interp_cppyy.register_class',
         'CPPInstance'            : 'interp_cppyy.W_CPPInstance',
         'addressof'              : 'interp_cppyy.addressof',
         'bind_object'            : 'interp_cppyy.bind_object',
diff --git a/pypy/module/cppyy/converter.py b/pypy/module/cppyy/converter.py
--- a/pypy/module/cppyy/converter.py
+++ b/pypy/module/cppyy/converter.py
@@ -532,7 +532,7 @@
     def from_memory(self, space, w_obj, w_type, offset):
         address = rffi.cast(capi.C_OBJECT, self._get_raw_address(space, w_obj, offset))
         from pypy.module.cppyy import interp_cppyy
-        return interp_cppyy.new_instance(space, w_type, self.cpptype, address, True, False)
+        return interp_cppyy.wrap_cppobject_nocast(space, w_type, self.cpptype, address, True, False)
 
     def to_memory(self, space, w_obj, w_value, offset):
         address = rffi.cast(rffi.VOIDPP, self._get_raw_address(space, w_obj, offset))
@@ -544,7 +544,7 @@
     def from_memory(self, space, w_obj, w_type, offset):
         address = rffi.cast(capi.C_OBJECT, self._get_raw_address(space, w_obj, offset))
         from pypy.module.cppyy import interp_cppyy
-        return interp_cppyy.new_instance(space, w_type, self.cpptype, address, False, False)
+        return interp_cppyy.wrap_cppobject_nocast(space, w_type, self.cpptype, address, False, False)
 
     def to_memory(self, space, w_obj, w_value, offset):
         self._is_abstract(space)
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
@@ -248,12 +248,12 @@
         from pypy.module.cppyy import interp_cppyy
         long_result = capi.c_call_l(cppmethod, cppthis, num_args, args)
         ptr_result = rffi.cast(capi.C_OBJECT, long_result)
-        return interp_cppyy.new_instance(space, w_returntype, self.cpptype, ptr_result, False, False)
+        return interp_cppyy.wrap_cppobject(space, w_returntype, self.cpptype, ptr_result, False, False)
 
     def execute_libffi(self, space, w_returntype, libffifunc, argchain):
         from pypy.module.cppyy import interp_cppyy
         ptr_result = rffi.cast(capi.C_OBJECT, libffifunc.call(argchain, rffi.VOIDP))
-        return interp_cppyy.new_instance(space, w_returntype, self.cpptype, ptr_result, False, False)
+        return interp_cppyy.wrap_cppobject(space, w_returntype, self.cpptype, ptr_result, False, False)
 
 class InstancePtrPtrExecutor(InstancePtrExecutor):
     _immutable_ = True
@@ -263,7 +263,7 @@
         voidp_result = capi.c_call_r(cppmethod, cppthis, num_args, args)
         ref_address = rffi.cast(rffi.VOIDPP, voidp_result)
         ptr_result = rffi.cast(capi.C_OBJECT, ref_address[0])
-        return interp_cppyy.new_instance(space, w_returntype, self.cpptype, ptr_result, False, False)
+        return interp_cppyy.wrap_cppobject(space, w_returntype, self.cpptype, ptr_result, False, False)
 
     def execute_libffi(self, space, w_returntype, libffifunc, argchain):
         from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
@@ -276,7 +276,7 @@
         from pypy.module.cppyy import interp_cppyy
         long_result = capi.c_call_o(cppmethod, cppthis, num_args, args, self.cpptype.handle)
         ptr_result = rffi.cast(capi.C_OBJECT, long_result)
-        return interp_cppyy.new_instance(space, w_returntype, self.cpptype, ptr_result, False, True)
+        return interp_cppyy.wrap_cppobject(space, w_returntype, self.cpptype, ptr_result, False, True)
 
     def execute_libffi(self, space, w_returntype, libffifunc, argchain):
         from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
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
@@ -30,6 +30,8 @@
         self.r_cppscope_cache = {
             "void" : W_CPPType(space, "void", capi.C_NULL_TYPE) }
         self.r_cpptemplate_cache = {}
+        self.type_registry = {}
+        self.w_clgen_callback = None
 
 @unwrap_spec(name=str)
 def resolve_name(space, name):
@@ -80,6 +82,18 @@
 
     return None
 
+ at unwrap_spec(w_callback=W_Root)
+def set_class_generator(space, w_callback):
+    state = space.fromcache(State)
+    state.w_clgen_callback = w_callback
+
+ at unwrap_spec(w_type=W_Root)
+def register_class(space, w_type):
+    w_cpptype = space.findattr(w_type, space.wrap("_cpp_proxy"))
+    cpptype = space.interp_w(W_CPPType, w_cpptype, can_be_None=False)
+    state = space.fromcache(State)
+    state.type_registry[cpptype.handle] = w_type
+
 
 class W_CPPLibrary(Wrappable):
     _immutable_ = True
@@ -225,7 +239,7 @@
         except Exception:
             capi.c_deallocate(self.cpptype.handle, newthis)
             raise
-        return new_instance(self.space, w_type, self.cpptype, newthis, False, True)
+        return wrap_new_cppobject_nocast(self.space, w_type, self.cpptype, newthis, False, True)
 
 
 class W_CPPOverload(Wrappable):
@@ -637,23 +651,34 @@
 memory_regulator = MemoryRegulator()
 
 
-def new_instance(space, w_type, cpptype, rawobject, isref, python_owns):
-    obj_actual = rawobject
-    actual = cpptype.handle
+def wrap_new_cppobject_nocast(space, w_type, cpptype, rawobject, isref, python_owns):
+    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, rawobject, isref, python_owns)
+    memory_regulator.register(cppinstance)
+    return w_cppinstance
+
+def wrap_cppobject_nocast(space, w_type, cpptype, rawobject, isref, python_owns):
+    obj = memory_regulator.retrieve(rawobject)
+    if obj and obj.cppclass == cpptype:
+         return obj
+    return wrap_new_cppobject_nocast(space, w_type, cpptype, rawobject, isref, python_owns)
+
+def wrap_cppobject(space, w_type, cpptype, rawobject, isref, python_owns):
     if rawobject:
         actual = capi.c_get_object_type(cpptype.handle, rawobject)
         if actual != cpptype.handle:
             offset = capi.c_base_offset(actual, cpptype.handle, rawobject)
-            obj_actual = capi.direct_ptradd(rawobject, offset)
-            # TODO: fix-up w_type to be w_actual_type
-    obj = memory_regulator.retrieve(obj_actual)
-    if obj and obj.cppclass.handle == actual:# == 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, obj_actual, isref, python_owns)
-    memory_regulator.register(cppinstance)
-    return w_cppinstance
+            rawobject = capi.direct_ptradd(rawobject, offset)
+            state = space.fromcache(State)
+            try:
+                w_type = state.type_registry[actual]
+            except KeyError:
+                final_name = capi.charp2str_free(capi.c_final_name(actual))
+                w_type = space.call_function(state.w_clgen_callback, space.wrap(final_name))
+            w_cpptype = space.findattr(w_type, space.wrap("_cpp_proxy"))
+            cpptype = space.interp_w(W_CPPType, w_cpptype, can_be_None=False)
+    return wrap_cppobject_nocast(space, w_type, cpptype, rawobject, isref, python_owns)
 
 @unwrap_spec(cppinstance=W_CPPInstance)
 def addressof(space, cppinstance):
@@ -665,9 +690,4 @@
     rawobject = rffi.cast(capi.C_OBJECT, 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, False, owns)
+    return wrap_cppobject_nocast(space, w_type, cpptype, rawobject, False, owns)
diff --git a/pypy/module/cppyy/pythonify.py b/pypy/module/cppyy/pythonify.py
--- a/pypy/module/cppyy/pythonify.py
+++ b/pypy/module/cppyy/pythonify.py
@@ -43,6 +43,10 @@
         return getattr(self._scope, fullname)
 
 
+def clgen_callback(name):
+    return get_cppclass(name)
+cppyy._set_class_generator(clgen_callback)
+
 def make_static_function(cpptype, func_name, cppol):
     rettype = cppol.get_returntype()
     if not rettype:                              # return builtin type
@@ -196,6 +200,7 @@
             setattr(metacpp, dm_name, pydm)
 
     _pythonize(pycpptype)
+    cppyy._register_class(pycpptype)
     return pycpptype
 
 def make_cpptemplatetype(scope, template_name):
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
@@ -20,6 +20,7 @@
    double get_base_value() { return m_db; }
 
    virtual base_class* cycle(base_class* b) { return b; }
+   virtual base_class* clone() { return new base_class; }
 
 public:
    int m_b;
@@ -31,6 +32,7 @@
    derived_class() { m_d = 2; m_dd = 2.2;}
    virtual int get_value() { return m_d; }
    double get_derived_value() { return m_dd; }
+   virtual base_class* clone() { return new derived_class; }
 
 public:
    int m_d;
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
@@ -430,3 +430,6 @@
         assert isinstance(d.cycle(b), base_class)
         assert isinstance(b.cycle(d), derived_class)
         assert isinstance(d.cycle(d), derived_class)
+
+        assert isinstance(b.clone(), base_class)      # TODO: clone() leaks
+        assert isinstance(d.clone(), derived_class)   # TODO: clone() leaks
diff --git a/pypy/module/cppyy/test/test_zjit.py b/pypy/module/cppyy/test/test_zjit.py
--- a/pypy/module/cppyy/test/test_zjit.py
+++ b/pypy/module/cppyy/test/test_zjit.py
@@ -131,6 +131,9 @@
         assert isinstance(w_type, FakeReturnType)
         return instantiate(cls)
 
+    def call_function(self, w_func, *args_w):
+        return None
+
     def _freeze_(self):
         return True
 


More information about the pypy-commit mailing list