Author: Wim Lavrijsen <[email protected]>
Branch: reflex-support
Changeset: r55403:665ede1ab7ce
Date: 2012-06-04 16:34 -0700
http://bitbucket.org/pypy/pypy/changeset/665ede1ab7ce/
Log: allow PyObject* function arguments and returns (with their tests)
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
@@ -81,7 +81,7 @@
def finalize_call(self, space, w_obj, call_local):
pass
- def free_argument(self, arg, call_local):
+ def free_argument(self, space, arg, call_local):
pass
@@ -498,7 +498,7 @@
charpptr = rffi.cast(rffi.CCHARPP, address)
return space.wrap(rffi.charp2str(charpptr[0]))
- def free_argument(self, arg, call_local):
+ def free_argument(self, space, arg, call_local):
lltype.free(rffi.cast(rffi.CCHARPP, arg)[0], flavor='raw')
@@ -733,7 +733,7 @@
pass
return InstanceConverter.to_memory(self, space, w_obj, w_value, offset)
- def free_argument(self, arg, call_local):
+ def free_argument(self, space, arg, call_local):
capi.c_free_stdstring(rffi.cast(capi.C_OBJECT, rffi.cast(rffi.VOIDPP,
arg)[0]))
class StdStringRefConverter(InstancePtrConverter):
@@ -745,6 +745,35 @@
InstancePtrConverter.__init__(self, space, cppclass)
+class PyObjectConverter(TypeConverter):
+ _immutable_ = True
+
+ def convert_argument(self, space, w_obj, address, call_local):
+ if hasattr(space, "fake"):
+ raise NotImplementedError
+ space.getbuiltinmodule("cpyext")
+ from pypy.module.cpyext.pyobject import make_ref
+ ref = make_ref(space, w_obj)
+ x = rffi.cast(rffi.VOIDPP, address)
+ x[0] = rffi.cast(rffi.VOIDP, ref);
+ ba = rffi.cast(rffi.CCHARP, address)
+ ba[capi.c_function_arg_typeoffset()] = 'a'
+
+ def convert_argument_libffi(self, space, w_obj, argchain, call_local):
+ if hasattr(space, "fake"):
+ raise NotImplementedError
+ space.getbuiltinmodule("cpyext")
+ from pypy.module.cpyext.pyobject import make_ref
+ ref = make_ref(space, w_obj)
+ argchain.arg(rffi.cast(rffi.VOIDP, ref))
+
+ def free_argument(self, space, arg, call_local):
+ if hasattr(space, "fake"):
+ raise NotImplementedError
+ from pypy.module.cpyext.pyobject import Py_DecRef, PyObject
+ Py_DecRef(space, rffi.cast(PyObject, rffi.cast(rffi.VOIDPP, arg)[0]))
+
+
_converters = {} # builtin and custom types
_a_converters = {} # array and ptr versions of above
def get_converter(space, name, default):
@@ -855,6 +884,9 @@
_converters["std::basic_string<char>&"] = StdStringRefConverter
_converters["string&"] =
_converters["std::basic_string<char>&"]
+_converters["PyObject*"] = PyObjectConverter
+_converters["_object*"] = _converters["PyObject*"]
+
# it should be possible to generate these:
_a_converters["short int*"] = ShortPtrConverter
_a_converters["short*"] = _a_converters["short int*"]
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
@@ -336,6 +336,31 @@
raise FastCallNotPossible
+class PyObjectExecutor(PtrTypeExecutor):
+ _immutable_ = True
+
+ def wrap_result(self, space, lresult):
+ space.getbuiltinmodule("cpyext")
+ from pypy.module.cpyext.pyobject import PyObject, from_ref, make_ref,
Py_DecRef
+ result = rffi.cast(PyObject, lresult)
+ w_obj = from_ref(space, result)
+ if result:
+ Py_DecRef(space, result)
+ return w_obj
+
+ def execute(self, space, cppmethod, cppthis, num_args, args):
+ if hasattr(space, "fake"):
+ raise NotImplementedError
+ lresult = capi.c_call_l(cppmethod, cppthis, num_args, args)
+ return self.wrap_result(space, lresult)
+
+ def execute_libffi(self, space, libffifunc, argchain):
+ if hasattr(space, "fake"):
+ raise NotImplementedError
+ lresult = libffifunc.call(argchain, rffi.LONG)
+ return self.wrap_result(space, lresult)
+
+
_executors = {}
def get_executor(space, name):
# Matching of 'name' to an executor factory goes through up to four levels:
@@ -436,3 +461,6 @@
# special cases (note: CINT backend requires the simple name 'string')
_executors["std::basic_string<char>"] = StdStringExecutor
_executors["string"] =
_executors["std::basic_string<char>"]
+
+_executors["PyObject*"] = PyObjectExecutor
+_executors["_object*"] = _executors["PyObject*"]
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
@@ -228,7 +228,7 @@
conv = self.converters[j]
arg_j = lltype.direct_ptradd(rffi.cast(rffi.CCHARP, args),
j*stride)
loc_j = self._address_from_local_buffer(call_local, j)
- conv.free_argument(rffi.cast(capi.C_OBJECT, arg_j), loc_j)
+ conv.free_argument(self.space, rffi.cast(capi.C_OBJECT,
arg_j), loc_j)
capi.c_deallocate_function_args(args)
raise
return args
@@ -241,7 +241,7 @@
arg_i = lltype.direct_ptradd(rffi.cast(rffi.CCHARP, args),
i*stride)
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)
+ conv.free_argument(self.space, rffi.cast(capi.C_OBJECT, arg_i),
loc_i)
capi.c_deallocate_function_args(args)
def signature(self):
diff --git a/pypy/module/cppyy/test/Makefile b/pypy/module/cppyy/test/Makefile
--- a/pypy/module/cppyy/test/Makefile
+++ b/pypy/module/cppyy/test/Makefile
@@ -1,5 +1,5 @@
dicts = example01Dict.so datatypesDict.so advancedcppDict.so
advancedcpp2Dict.so \
-overloadsDict.so stltypesDict.so operatorsDict.so fragileDict.so \
+overloadsDict.so stltypesDict.so operatorsDict.so fragileDict.so
crossingDict.so \
std_streamsDict.so
all : $(dicts)
diff --git a/pypy/module/cppyy/test/crossing.cxx
b/pypy/module/cppyy/test/crossing.cxx
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/crossing.cxx
@@ -0,0 +1,16 @@
+#include "crossing.h"
+#include <stdlib.h>
+
+extern "C" long bar_unwrap(PyObject*);
+extern "C" PyObject* bar_wrap(long);
+
+
+long crossing::A::unwrap(PyObject* pyobj)
+{
+ return bar_unwrap(pyobj);
+}
+
+PyObject* crossing::A::wrap(long l)
+{
+ return bar_wrap(l);
+}
diff --git a/pypy/module/cppyy/test/crossing.h
b/pypy/module/cppyy/test/crossing.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/crossing.h
@@ -0,0 +1,12 @@
+struct _object;
+typedef _object PyObject;
+
+namespace crossing {
+
+class A {
+public:
+ long unwrap(PyObject* pyobj);
+ PyObject* wrap(long l);
+};
+
+} // namespace crossing
diff --git a/pypy/module/cppyy/test/crossing.xml
b/pypy/module/cppyy/test/crossing.xml
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/crossing.xml
@@ -0,0 +1,7 @@
+<lcgdict>
+
+ <namespace name="crossing" />
+
+ <class pattern="crossing::[A-Z]" />
+
+</lcgdict>
diff --git a/pypy/module/cppyy/test/test_crossing.py
b/pypy/module/cppyy/test/test_crossing.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/test_crossing.py
@@ -0,0 +1,104 @@
+import py, os, sys
+from pypy.conftest import gettestobjspace
+from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase
+
+currpath = py.path.local(__file__).dirpath()
+test_dct = str(currpath.join("crossingDict.so"))
+
+def setup_module(mod):
+ if sys.platform == 'win32':
+ py.test.skip("win32 not supported so far")
+ err = os.system("cd '%s' && make crossingDict.so" % currpath)
+ if err:
+ raise OSError("'make' failed (see stderr)")
+
+
+class AppTestCrossing(AppTestCpythonExtensionBase):
+ def setup_class(cls):
+ # following from AppTestCpythonExtensionBase, with cppyy added
+ cls.space = gettestobjspace(usemodules=['cpyext', 'cppyy', 'thread',
'_rawffi', '_ffi', 'array'])
+ cls.space.getbuiltinmodule("cpyext")
+ from pypy.module.imp.importing import importhook
+ importhook(cls.space, "os") # warm up reference counts
+ from pypy.module.cpyext.pyobject import RefcountState
+ state = cls.space.fromcache(RefcountState)
+ state.non_heaptypes_w[:] = []
+
+ # cppyy specific additions (not that the test_dct is loaded late
+ # to allow the generated extension module be loaded first)
+ cls.w_test_dct = cls.space.wrap(test_dct)
+ cls.w_datatypes = cls.space.appexec([], """():
+ import cppyy, cpyext""")
+
+ def setup_method(self, func):
+ AppTestCpythonExtensionBase.setup_method(self, func)
+
+ if hasattr(self, 'cmodule'):
+ return
+
+ import os, ctypes
+
+ init = """
+ if (Py_IsInitialized())
+ Py_InitModule("bar", methods);
+ """
+ body = """
+ long bar_unwrap(PyObject* arg)
+ {
+ return PyLong_AsLong(arg);
+ }
+ PyObject* bar_wrap(long l)
+ {
+ return PyLong_FromLong(l);
+ }
+ static PyMethodDef methods[] = {
+ { NULL }
+ };
+ """
+
+ modname = self.import_module(name='bar', init=init, body=body,
load_it=False)
+ from pypy.module.imp.importing import get_so_extension
+ soext = get_so_extension(self.space)
+ fullmodname = os.path.join(modname, 'bar' + soext)
+ self.cmodule = ctypes.CDLL(fullmodname, ctypes.RTLD_GLOBAL)
+
+ def test00_base_class(self):
+ """Test from cpyext; only here to see whether the imported class
works"""
+
+ import sys
+ init = """
+ if (Py_IsInitialized())
+ Py_InitModule("foo", NULL);
+ """
+ self.import_module(name='foo', init=init)
+ assert 'foo' in sys.modules
+
+ def test01_crossing_dict(self):
+ """Test availability of all needed classes in the dict"""
+
+ import cppyy
+ cppyy.load_reflection_info(self.test_dct)
+
+ assert cppyy.gbl.crossing == cppyy.gbl.crossing
+ crossing = cppyy.gbl.crossing
+
+ assert crossing.A == crossing.A
+
+ def test02_send_pyobject(self):
+ """Test sending a true pyobject to C++"""
+
+ import cppyy
+ crossing = cppyy.gbl.crossing
+
+ a = crossing.A()
+ assert a.unwrap(13) == 13
+
+ def test03_send_and_receive_pyobject(self):
+ """Test receiving a true pyobject from C++"""
+
+ import cppyy
+ crossing = cppyy.gbl.crossing
+
+ a = crossing.A()
+
+ assert a.wrap(41) == 41
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
@@ -7,6 +7,9 @@
from pypy.module.cppyy import interp_cppyy, capi
+# load cpyext early, or its global vars are counted as leaks in the test
+# (note that the module is not otherwise used in the test itself)
+import pypy.module.cpyext
currpath = py.path.local(__file__).dirpath()
test_dct = str(currpath.join("example01Dict.so"))
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit