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