Author: Wim Lavrijsen <[email protected]>
Branch: reflex-support
Changeset: r54953:ed7ed7f16a5b
Date: 2012-05-07 15:11 -0700
http://bitbucket.org/pypy/pypy/changeset/ed7ed7f16a5b/

Log:    initial support for void** and object** as function arguments

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
@@ -21,6 +21,13 @@
         return rawobject
     return capi.C_NULL_OBJECT
 
+def set_rawobject(space, w_obj, address):
+    from pypy.module.cppyy.interp_cppyy import W_CPPInstance
+    cppinstance = space.interp_w(W_CPPInstance, w_obj, can_be_None=True)
+    if cppinstance:
+        assert lltype.typeOf(cppinstance._rawobject) == capi.C_OBJECT
+        cppinstance._rawobject = rffi.cast(capi.C_OBJECT, address)
+
 def get_rawobject_nonnull(space, w_obj):
     from pypy.module.cppyy.interp_cppyy import W_CPPInstance
     cppinstance = space.interp_w(W_CPPInstance, w_obj, can_be_None=True)
@@ -53,7 +60,7 @@
     def _is_abstract(self, space):
         raise OperationError(space.w_TypeError, space.wrap("no converter 
available"))
 
-    def convert_argument(self, space, w_obj, address):
+    def convert_argument(self, space, w_obj, address, call_local):
         self._is_abstract(space)
 
     def convert_argument_libffi(self, space, w_obj, argchain):
@@ -70,7 +77,10 @@
     def to_memory(self, space, w_obj, w_value, offset):
         self._is_abstract(space)
 
-    def free_argument(self, arg):
+    def finalize_call(self, space, w_obj, call_local):
+        pass
+
+    def free_argument(self, arg, call_local):
         pass
 
 
@@ -181,7 +191,7 @@
     _mixin_ = True
     _immutable_ = True
 
-    def convert_argument(self, space, w_obj, address):
+    def convert_argument(self, space, w_obj, address, call_local):
         x = rffi.cast(self.c_ptrtype, address)
         x[0] = self._unwrap_object(space, w_obj)
 
@@ -189,7 +199,7 @@
     _mixin_ = True
     _immutable_ = True
 
-    def convert_argument(self, space, w_obj, address):
+    def convert_argument(self, space, w_obj, address, call_local):
         x = rffi.cast(self.c_ptrtype, address)
         x[0] = self._unwrap_object(space, w_obj)
         ba = rffi.cast(rffi.CCHARP, address)
@@ -203,7 +213,7 @@
     def __init__(self, space, name):
         self.name = name
 
-    def convert_argument(self, space, w_obj, address):
+    def convert_argument(self, space, w_obj, address, call_local):
         raise OperationError(space.w_TypeError,
                              space.wrap('no converter available for type "%s"' 
% self.name))
 
@@ -219,7 +229,7 @@
                                  space.wrap("boolean value should be bool, or 
integer 1 or 0"))
         return arg
 
-    def convert_argument(self, space, w_obj, address):
+    def convert_argument(self, space, w_obj, address, call_local):
         x = rffi.cast(rffi.LONGP, address)
         x[0] = self._unwrap_object(space, w_obj)
 
@@ -262,7 +272,7 @@
                                  space.wrap("char expected, got string of size 
%d" % len(value)))
         return value[0] # turn it into a "char" to the annotator
 
-    def convert_argument(self, space, w_obj, address):
+    def convert_argument(self, space, w_obj, address, call_local):
         x = rffi.cast(rffi.CCHARP, address)
         x[0] = self._unwrap_object(space, w_obj)
 
@@ -360,7 +370,7 @@
     libffitype = libffi.types.pointer
     typecode = 'r'
 
-    def convert_argument(self, space, w_obj, address):
+    def convert_argument(self, space, w_obj, address, call_local):
         x = rffi.cast(self.c_ptrtype, address)
         x[0] = self._unwrap_object(space, w_obj)
         ba = rffi.cast(rffi.CCHARP, address)
@@ -383,7 +393,7 @@
     libffitype = libffi.types.pointer
     typecode = 'r'
 
-    def convert_argument(self, space, w_obj, address):
+    def convert_argument(self, space, w_obj, address, call_local):
         x = rffi.cast(self.c_ptrtype, address)
         x[0] = self._unwrap_object(space, w_obj)
         ba = rffi.cast(rffi.CCHARP, address)
@@ -478,7 +488,7 @@
 class CStringConverter(TypeConverter):
     _immutable_ = True
 
-    def convert_argument(self, space, w_obj, address):
+    def convert_argument(self, space, w_obj, address, call_local):
         x = rffi.cast(rffi.LONGP, address)
         arg = space.str_w(w_obj)
         x[0] = rffi.cast(rffi.LONG, rffi.str2charp(arg))
@@ -490,14 +500,14 @@
         charpptr = rffi.cast(rffi.CCHARPP, address)
         return space.wrap(rffi.charp2str(charpptr[0]))
 
-    def free_argument(self, arg):
+    def free_argument(self, arg, call_local):
         lltype.free(rffi.cast(rffi.CCHARPP, arg)[0], flavor='raw')
 
 
 class VoidPtrConverter(TypeConverter):
     _immutable_ = True
 
-    def convert_argument(self, space, w_obj, address):
+    def convert_argument(self, space, w_obj, address, call_local):
         x = rffi.cast(rffi.VOIDPP, address)
         x[0] = rffi.cast(rffi.VOIDP, get_rawobject(space, w_obj))
         ba = rffi.cast(rffi.CCHARP, address)
@@ -507,21 +517,26 @@
         argchain.arg(get_rawobject(space, w_obj))
         return lltype.nullptr(rffi.VOIDP.TO)
 
-
 class VoidPtrPtrConverter(TypeConverter):
     _immutable_ = True
 
-    def convert_argument(self, space, w_obj, address):
+    def convert_argument(self, space, w_obj, address, call_local):
+        r = rffi.cast(rffi.VOIDPP, call_local)
+        r[0] = rffi.cast(rffi.VOIDP, get_rawobject(space, w_obj))
         x = rffi.cast(rffi.VOIDPP, address)
-        x[0] = rffi.cast(rffi.VOIDP, get_rawobject(space, w_obj))
+        x[0] = rffi.cast(rffi.VOIDP, call_local)
+        address = rffi.cast(capi.C_OBJECT, address)
         ba = rffi.cast(rffi.CCHARP, address)
-        ba[capi.c_function_arg_typeoffset()] = 'p'
+        ba[capi.c_function_arg_typeoffset()] = 'a'
 
+    def finalize_call(self, space, w_obj, call_local):
+        r = rffi.cast(rffi.VOIDPP, call_local)
+        set_rawobject(space, w_obj, r[0])
 
 class VoidPtrRefConverter(TypeConverter):
     _immutable_ = True
 
-    def convert_argument(self, space, w_obj, address):
+    def convert_argument(self, space, w_obj, address, call_local):
         x = rffi.cast(rffi.VOIDPP, address)
         x[0] = rffi.cast(rffi.VOIDP, get_rawobject(space, w_obj))
         ba = rffi.cast(rffi.CCHARP, address)
@@ -631,7 +646,7 @@
                              space.wrap("cannot pass %s as %s" %
                              (space.type(w_obj).getname(space, "?"), 
self.cppclass.name)))
 
-    def convert_argument(self, space, w_obj, address):
+    def convert_argument(self, space, w_obj, address, call_local):
         x = rffi.cast(rffi.VOIDPP, address)
         x[0] = rffi.cast(rffi.VOIDP, self._unwrap_object(space, w_obj))
         address = rffi.cast(capi.C_OBJECT, address)
@@ -665,6 +680,32 @@
         self._is_abstract(space)
 
 
+class InstancePtrPtrConverter(InstancePtrConverter):
+    _immutable_ = True
+
+    def convert_argument(self, space, w_obj, address, call_local):
+        r = rffi.cast(rffi.VOIDPP, call_local)
+        r[0] = rffi.cast(rffi.VOIDP, self._unwrap_object(space, w_obj))
+        x = rffi.cast(rffi.VOIDPP, address)
+        x[0] = rffi.cast(rffi.VOIDP, call_local)
+        address = rffi.cast(capi.C_OBJECT, address)
+        ba = rffi.cast(rffi.CCHARP, address)
+        ba[capi.c_function_arg_typeoffset()] = 'o'
+
+    def from_memory(self, space, w_obj, w_pycppclass, offset):
+        self._is_abstract(space)
+
+    def to_memory(self, space, w_obj, w_value, offset):
+        self._is_abstract(space)
+
+    def finalize_call(self, space, w_obj, call_local):
+        from pypy.module.cppyy.interp_cppyy import W_CPPInstance
+        obj = space.interpclass_w(w_obj)
+        assert isinstance(obj, W_CPPInstance)
+        r = rffi.cast(rffi.VOIDPP, call_local)
+        obj._rawobject = rffi.cast(capi.C_OBJECT, r[0])
+
+
 class StdStringConverter(InstanceConverter):
     _immutable_ = True
 
@@ -694,7 +735,7 @@
             pass
         return InstanceConverter.to_memory(self, space, w_obj, w_value, offset)
 
-    def free_argument(self, arg):
+    def free_argument(self, arg, call_local):
         capi.c_free_stdstring(rffi.cast(capi.C_OBJECT, rffi.cast(rffi.VOIDPP, 
arg)[0]))
 
 class StdStringRefConverter(InstancePtrConverter):
@@ -753,6 +794,8 @@
         cppclass = space.interp_w(W_CPPClass, cppclass, can_be_None=False)
         if compound == "*" or compound == "&":
             return InstancePtrConverter(space, cppclass)
+        elif compound == "**":
+            return InstancePtrPtrConverter(space, cppclass)
         elif compound == "":
             return InstanceConverter(space, cppclass)
     elif capi.c_is_enum(clean_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
@@ -127,6 +127,9 @@
         self.executor = None
         self._libffifunc = None
 
+    def _address_from_local_buffer(self, call_local, index):
+        return lltype.direct_ptradd(rffi.cast(rffi.CCHARP, call_local), 
index*rffi.sizeof(rffi.VOIDP))
+
     @jit.unroll_safe
     def call(self, cppthis, args_w):
         jit.promote(self)
@@ -140,20 +143,27 @@
         if self.arg_converters is None:
             self._setup(cppthis)
 
+        call_local = lltype.malloc(rffi.CArray(rffi.VOIDP), len(args_w), 
flavor='raw')
+
         if self._libffifunc:
             try:
-                return self.do_fast_call(cppthis, args_w)
+                result = self.do_fast_call(cppthis, args_w, call_local)
+                lltype.free(call_local, flavor='raw')
+                return result
             except FastCallNotPossible:
                 pass          # can happen if converters or executor does not 
implement ffi
+            except:
+                lltype.free(call_local, flavor='raw')
+                raise
 
-        args = self.prepare_arguments(args_w)
+        args = self.prepare_arguments(args_w, call_local)
         try:
             return self.executor.execute(self.space, self.cppmethod, cppthis, 
len(args_w), args)
         finally:
-            self.free_arguments(args, len(args_w))
+            self.finalize_call(args, args_w, call_local)
 
     @jit.unroll_safe
-    def do_fast_call(self, cppthis, args_w):
+    def do_fast_call(self, cppthis, args_w, call_local):
         jit.promote(self)
         argchain = libffi.ArgChain()
         argchain.arg(cppthis)
@@ -196,7 +206,7 @@
                 self._libffifunc = libffifunc
 
     @jit.unroll_safe
-    def prepare_arguments(self, args_w):
+    def prepare_arguments(self, args_w, call_local):
         jit.promote(self)
         args = capi.c_allocate_function_args(len(args_w))
         stride = capi.c_function_arg_sizeof()
@@ -205,25 +215,31 @@
             w_arg = args_w[i]
             try:
                 arg_i = lltype.direct_ptradd(rffi.cast(rffi.CCHARP, args), 
i*stride)
-                conv.convert_argument(self.space, w_arg, 
rffi.cast(capi.C_OBJECT, arg_i))
+                loc_i = self._address_from_local_buffer(call_local, i)
+                conv.convert_argument(self.space, w_arg, 
rffi.cast(capi.C_OBJECT, arg_i), loc_i)
             except:
                 # fun :-(
                 for j in range(i):
                     conv = self.arg_converters[j]
                     arg_j = lltype.direct_ptradd(rffi.cast(rffi.CCHARP, args), 
j*stride)
-                    conv.free_argument(rffi.cast(capi.C_OBJECT, arg_j))
+                    loc_j = self._address_from_local_buffer(call_local, j)
+                    conv.free_argument(rffi.cast(capi.C_OBJECT, arg_j), loc_j)
                 capi.c_deallocate_function_args(args)
+                lltype.free(call_local, flavor='raw')
                 raise
         return args
 
     @jit.unroll_safe
-    def free_arguments(self, args, nargs):
+    def finalize_call(self, args, args_w, call_local):
         stride = capi.c_function_arg_sizeof()
-        for i in range(nargs):
+        for i in range(len(args_w)):
             conv = self.arg_converters[i]
             arg_i = lltype.direct_ptradd(rffi.cast(rffi.CCHARP, args), 
i*stride)
-            conv.free_argument(rffi.cast(capi.C_OBJECT, arg_i))
+            loc_i = self._address_from_local_buffer(call_local, i)
+            conv.finalize_call(self.space, args_w[i], loc_i)
+            conv.free_argument(rffi.cast(capi.C_OBJECT, arg_i), loc_i)
         capi.c_deallocate_function_args(args)
+        lltype.free(call_local, flavor='raw')
 
     def signature(self):
         return capi.c_method_signature(self.scope, self.index)
diff --git a/pypy/module/cppyy/test/datatypes.cxx 
b/pypy/module/cppyy/test/datatypes.cxx
--- a/pypy/module/cppyy/test/datatypes.cxx
+++ b/pypy/module/cppyy/test/datatypes.cxx
@@ -1,5 +1,7 @@
 #include "datatypes.h"
 
+#include <iostream>
+
 
 //===========================================================================
 cppyy_test_data::cppyy_test_data() : m_owns_arrays(false)
@@ -143,6 +145,15 @@
 void cppyy_test_data::set_double_c(const double& d)          { m_double = d; }
 void cppyy_test_data::set_enum(what w)                       { m_enum   = w; }
 
+void cppyy_test_data::set_pod_val(cppyy_test_pod p)            { m_pod = p; }
+void cppyy_test_data::set_pod_ptr_in(cppyy_test_pod* pp)       { m_pod = *pp; }
+void cppyy_test_data::set_pod_ptr_out(cppyy_test_pod* pp)      { *pp = m_pod; }
+void cppyy_test_data::set_pod_ref(const cppyy_test_pod& rp)    { m_pod = rp; }
+void cppyy_test_data::set_pod_ptrptr_in(cppyy_test_pod** ppp)  { m_pod = 
**ppp; }
+void cppyy_test_data::set_pod_void_ptrptr_in(void** pp)        { m_pod = 
**((cppyy_test_pod**)pp); }
+void cppyy_test_data::set_pod_ptrptr_out(cppyy_test_pod** ppp) { *ppp = 
&m_pod; }
+void cppyy_test_data::set_pod_void_ptrptr_out(void** pp)       { 
*((cppyy_test_pod**)pp) = &m_pod; }
+
 char                cppyy_test_data::s_char   = 's';
 unsigned char       cppyy_test_data::s_uchar  = 'u';
 short               cppyy_test_data::s_short  = -101;
diff --git a/pypy/module/cppyy/test/datatypes.h 
b/pypy/module/cppyy/test/datatypes.h
--- a/pypy/module/cppyy/test/datatypes.h
+++ b/pypy/module/cppyy/test/datatypes.h
@@ -85,6 +85,15 @@
     void set_double_c(const double& d);
     void set_enum(what w);
 
+    void set_pod_val(cppyy_test_pod);
+    void set_pod_ptr_in(cppyy_test_pod*);
+    void set_pod_ptr_out(cppyy_test_pod*);
+    void set_pod_ref(const cppyy_test_pod&);
+    void set_pod_ptrptr_in(cppyy_test_pod**);
+    void set_pod_void_ptrptr_in(void**);
+    void set_pod_ptrptr_out(cppyy_test_pod**);
+    void set_pod_void_ptrptr_out(void**);
+
 public:
 // basic types
     bool                 m_bool;
diff --git a/pypy/module/cppyy/test/test_datatypes.py 
b/pypy/module/cppyy/test/test_datatypes.py
--- a/pypy/module/cppyy/test/test_datatypes.py
+++ b/pypy/module/cppyy/test/test_datatypes.py
@@ -456,3 +456,71 @@
 
         assert c.get_pod_ptrref().m_int == 666
         assert c.get_pod_ptrref().m_double == 3.14
+
+    def test13_object_arguments(self):
+        """Test setting and returning of a POD through arguments"""
+
+        import cppyy
+
+        c = cppyy.gbl.cppyy_test_data()
+        assert c.m_pod.m_int == 888
+        assert c.m_pod.m_double == 3.14
+
+        p = cppyy.gbl.cppyy_test_pod()
+        p.m_int = 123
+        assert p.m_int == 123
+        p.m_double = 321.
+        assert p.m_double == 321.
+
+        c.set_pod_val(p)
+        assert c.m_pod.m_int == 123
+        assert c.m_pod.m_double == 321.
+
+        c = cppyy.gbl.cppyy_test_data()
+        c.set_pod_ptr_in(p)
+        assert c.m_pod.m_int == 123
+        assert c.m_pod.m_double == 321.
+
+        c = cppyy.gbl.cppyy_test_data()
+        c.set_pod_ptr_out(p)
+        assert p.m_int == 888
+        assert p.m_double == 3.14
+
+        p.m_int = 555
+        p.m_double = 666.
+
+        c = cppyy.gbl.cppyy_test_data()
+        c.set_pod_ref(p)
+        assert c.m_pod.m_int == 555
+        assert c.m_pod.m_double == 666.
+
+        c = cppyy.gbl.cppyy_test_data()
+        c.set_pod_ptrptr_in(p)
+        assert c.m_pod.m_int == 555
+        assert c.m_pod.m_double == 666.
+        assert p.m_int == 555
+        assert p.m_double == 666.
+
+        c = cppyy.gbl.cppyy_test_data()
+        c.set_pod_void_ptrptr_in(p)
+        assert c.m_pod.m_int == 555
+        assert c.m_pod.m_double == 666.
+        assert p.m_int == 555
+        assert p.m_double == 666.
+
+        c = cppyy.gbl.cppyy_test_data()
+        c.set_pod_ptrptr_out(p)
+        assert c.m_pod.m_int == 888
+        assert c.m_pod.m_double == 3.14
+        assert p.m_int == 888
+        assert p.m_double == 3.14
+
+        p.m_int = 777
+        p.m_double = 888.
+
+        c = cppyy.gbl.cppyy_test_data()
+        c.set_pod_void_ptrptr_out(p)
+        assert c.m_pod.m_int == 888
+        assert c.m_pod.m_double == 3.14
+        assert p.m_int == 888
+        assert p.m_double == 3.14
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to