[pypy-commit] pypy arm-backend-2: merge default
bivab
noreply at buildbot.pypy.org
Fri Jun 29 11:14:22 CEST 2012
Author: David Schneider <david.schneider at picle.org>
Branch: arm-backend-2
Changeset: r55870:eeb247a70b02
Date: 2012-06-29 11:12 +0200
http://bitbucket.org/pypy/pypy/changeset/eeb247a70b02/
Log: merge default
diff too long, truncating to 10000 out of 21315 lines
diff --git a/.hgignore b/.hgignore
--- a/.hgignore
+++ b/.hgignore
@@ -21,6 +21,16 @@
^pypy/module/cpyext/test/.+\.obj$
^pypy/module/cpyext/test/.+\.manifest$
^pypy/module/test_lib_pypy/ctypes_tests/.+\.o$
+^pypy/module/cppyy/src/.+\.o$
+^pypy/module/cppyy/bench/.+\.so$
+^pypy/module/cppyy/bench/.+\.root$
+^pypy/module/cppyy/bench/.+\.d$
+^pypy/module/cppyy/src/.+\.errors$
+^pypy/module/cppyy/test/.+_rflx\.cpp$
+^pypy/module/cppyy/test/.+\.so$
+^pypy/module/cppyy/test/.+\.rootmap$
+^pypy/module/cppyy/test/.+\.exe$
+^pypy/module/cppyy/test/.+_cint.h$
^pypy/doc/.+\.html$
^pypy/doc/config/.+\.rst$
^pypy/doc/basicblock\.asc$
diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -216,6 +216,7 @@
DFKI GmbH, Germany
Impara, Germany
Change Maker, Sweden
+ University of California Berkeley, USA
The PyPy Logo as used by http://speed.pypy.org and others was created
by Samuel Reis and is distributed on terms of Creative Commons Share Alike
diff --git a/ctypes_configure/cbuild.py b/ctypes_configure/cbuild.py
--- a/ctypes_configure/cbuild.py
+++ b/ctypes_configure/cbuild.py
@@ -372,7 +372,7 @@
self.library_dirs = list(eci.library_dirs)
self.compiler_exe = compiler_exe
self.profbased = profbased
- if not sys.platform in ('win32', 'darwin'): # xxx
+ if not sys.platform in ('win32', 'darwin', 'cygwin'): # xxx
if 'm' not in self.libraries:
self.libraries.append('m')
if 'pthread' not in self.libraries:
diff --git a/lib-python/2.7/ctypes/__init__.py b/lib-python/2.7/ctypes/__init__.py
--- a/lib-python/2.7/ctypes/__init__.py
+++ b/lib-python/2.7/ctypes/__init__.py
@@ -351,7 +351,10 @@
self._FuncPtr = _FuncPtr
if handle is None:
- self._handle = _ffi.CDLL(name, mode)
+ if flags & _FUNCFLAG_CDECL:
+ self._handle = _ffi.CDLL(name, mode)
+ else:
+ self._handle = _ffi.WinDLL(name, mode)
else:
self._handle = handle
diff --git a/lib-python/2.7/distutils/sysconfig_pypy.py b/lib-python/2.7/distutils/sysconfig_pypy.py
--- a/lib-python/2.7/distutils/sysconfig_pypy.py
+++ b/lib-python/2.7/distutils/sysconfig_pypy.py
@@ -39,11 +39,10 @@
If 'prefix' is supplied, use it instead of sys.prefix or
sys.exec_prefix -- i.e., ignore 'plat_specific'.
"""
- if standard_lib:
- raise DistutilsPlatformError(
- "calls to get_python_lib(standard_lib=1) cannot succeed")
if prefix is None:
prefix = PREFIX
+ if standard_lib:
+ return os.path.join(prefix, "lib-python", get_python_version())
return os.path.join(prefix, 'site-packages')
diff --git a/lib-python/2.7/pickle.py b/lib-python/2.7/pickle.py
--- a/lib-python/2.7/pickle.py
+++ b/lib-python/2.7/pickle.py
@@ -638,7 +638,7 @@
# else tmp is empty, and we're done
def save_dict(self, obj):
- modict_saver = self._pickle_moduledict(obj)
+ modict_saver = self._pickle_maybe_moduledict(obj)
if modict_saver is not None:
return self.save_reduce(*modict_saver)
@@ -691,26 +691,20 @@
write(SETITEM)
# else tmp is empty, and we're done
- def _pickle_moduledict(self, obj):
+ def _pickle_maybe_moduledict(self, obj):
# save module dictionary as "getattr(module, '__dict__')"
+ try:
+ name = obj['__name__']
+ if type(name) is not str:
+ return None
+ themodule = sys.modules[name]
+ if type(themodule) is not ModuleType:
+ return None
+ if themodule.__dict__ is not obj:
+ return None
+ except (AttributeError, KeyError, TypeError):
+ return None
- # build index of module dictionaries
- try:
- modict = self.module_dict_ids
- except AttributeError:
- modict = {}
- from sys import modules
- for mod in modules.values():
- if isinstance(mod, ModuleType):
- modict[id(mod.__dict__)] = mod
- self.module_dict_ids = modict
-
- thisid = id(obj)
- try:
- themodule = modict[thisid]
- except KeyError:
- return None
- from __builtin__ import getattr
return getattr, (themodule, '__dict__')
diff --git a/lib-python/stdlib-upgrade.txt b/lib-python/stdlib-upgrade.txt
new file mode 100644
--- /dev/null
+++ b/lib-python/stdlib-upgrade.txt
@@ -0,0 +1,19 @@
+Process for upgrading the stdlib to a new cpython version
+==========================================================
+
+.. note::
+
+ overly detailed
+
+1. check out the branch vendor/stdlib
+2. upgrade the files there
+3. update stdlib-versions.txt with the output of hg -id from the cpython repo
+4. commit
+5. update to default/py3k
+6. create a integration branch for the new stdlib
+ (just hg branch stdlib-$version)
+7. merge vendor/stdlib
+8. commit
+10. fix issues
+11. commit --close-branch
+12. merge to default
diff --git a/lib_pypy/_ctypes/basics.py b/lib_pypy/_ctypes/basics.py
--- a/lib_pypy/_ctypes/basics.py
+++ b/lib_pypy/_ctypes/basics.py
@@ -47,10 +47,6 @@
else:
return self.from_param(as_parameter)
- def get_ffi_param(self, value):
- cdata = self.from_param(value)
- return cdata, cdata._to_ffi_param()
-
def get_ffi_argtype(self):
if self._ffiargtype:
return self._ffiargtype
diff --git a/lib_pypy/_ctypes/function.py b/lib_pypy/_ctypes/function.py
--- a/lib_pypy/_ctypes/function.py
+++ b/lib_pypy/_ctypes/function.py
@@ -391,7 +391,7 @@
address = self._get_address()
ffiargs = [argtype.get_ffi_argtype() for argtype in argtypes]
ffires = restype.get_ffi_argtype()
- return _ffi.FuncPtr.fromaddr(address, '', ffiargs, ffires)
+ return _ffi.FuncPtr.fromaddr(address, '', ffiargs, ffires, self._flags_)
def _getfuncptr(self, argtypes, restype, thisarg=None):
if self._ptr is not None and (argtypes is self._argtypes_ or argtypes == self._argtypes_):
@@ -412,7 +412,7 @@
ptr = thisarg[0][self._com_index - 0x1000]
ffiargs = [argtype.get_ffi_argtype() for argtype in argtypes]
ffires = restype.get_ffi_argtype()
- return _ffi.FuncPtr.fromaddr(ptr, '', ffiargs, ffires)
+ return _ffi.FuncPtr.fromaddr(ptr, '', ffiargs, ffires, self._flags_)
cdll = self.dll._handle
try:
@@ -444,10 +444,6 @@
@classmethod
def _conv_param(cls, argtype, arg):
- if isinstance(argtype, _CDataMeta):
- cobj, ffiparam = argtype.get_ffi_param(arg)
- return cobj, ffiparam, argtype
-
if argtype is not None:
arg = argtype.from_param(arg)
if hasattr(arg, '_as_parameter_'):
diff --git a/lib_pypy/_ctypes/primitive.py b/lib_pypy/_ctypes/primitive.py
--- a/lib_pypy/_ctypes/primitive.py
+++ b/lib_pypy/_ctypes/primitive.py
@@ -249,6 +249,13 @@
self._buffer[0] = value
result.value = property(_getvalue, _setvalue)
+ elif tp == '?': # regular bool
+ def _getvalue(self):
+ return bool(self._buffer[0])
+ def _setvalue(self, value):
+ self._buffer[0] = bool(value)
+ result.value = property(_getvalue, _setvalue)
+
elif tp == 'v': # VARIANT_BOOL type
def _getvalue(self):
return bool(self._buffer[0])
diff --git a/lib_pypy/ctypes_support.py b/lib_pypy/ctypes_support.py
--- a/lib_pypy/ctypes_support.py
+++ b/lib_pypy/ctypes_support.py
@@ -12,6 +12,8 @@
if sys.platform == 'win32':
import _ffi
standard_c_lib = ctypes.CDLL('msvcrt', handle=_ffi.get_libc())
+elif sys.platform == 'cygwin':
+ standard_c_lib = ctypes.CDLL(ctypes.util.find_library('cygwin'))
else:
standard_c_lib = ctypes.CDLL(ctypes.util.find_library('c'))
diff --git a/lib_pypy/disassembler.py b/lib_pypy/disassembler.py
--- a/lib_pypy/disassembler.py
+++ b/lib_pypy/disassembler.py
@@ -24,6 +24,11 @@
self.lineno = lineno
self.line_starts_here = False
+ def __str__(self):
+ if self.arg is None:
+ return "%s" % (self.__class__.__name__,)
+ return "%s (%s)" % (self.__class__.__name__, self.arg)
+
def __repr__(self):
if self.arg is None:
return "<%s at %d>" % (self.__class__.__name__, self.pos)
diff --git a/pypy/annotation/annrpython.py b/pypy/annotation/annrpython.py
--- a/pypy/annotation/annrpython.py
+++ b/pypy/annotation/annrpython.py
@@ -133,44 +133,6 @@
self.build_graph_types(graph, inputcells, complete_now=False)
self.complete_helpers(policy)
return graph
-
- def annotate_helper_method(self, _class, attr, args_s, policy=None):
- """ Warning! this method is meant to be used between
- annotation and rtyping
- """
- if policy is None:
- from pypy.annotation.policy import AnnotatorPolicy
- policy = AnnotatorPolicy()
-
- assert attr != '__class__'
- classdef = self.bookkeeper.getuniqueclassdef(_class)
- attrdef = classdef.find_attribute(attr)
- s_result = attrdef.getvalue()
- classdef.add_source_for_attribute(attr, classdef.classdesc)
- self.bookkeeper
- assert isinstance(s_result, annmodel.SomePBC)
- olddesc = s_result.any_description()
- desc = olddesc.bind_self(classdef)
- args = self.bookkeeper.build_args("simple_call", args_s[:])
- desc.consider_call_site(self.bookkeeper, desc.getcallfamily(), [desc],
- args, annmodel.s_ImpossibleValue, None)
- result = []
- def schedule(graph, inputcells):
- result.append((graph, inputcells))
- return annmodel.s_ImpossibleValue
-
- prevpolicy = self.policy
- self.policy = policy
- self.bookkeeper.enter(None)
- try:
- desc.pycall(schedule, args, annmodel.s_ImpossibleValue)
- finally:
- self.bookkeeper.leave()
- self.policy = prevpolicy
- [(graph, inputcells)] = result
- self.build_graph_types(graph, inputcells, complete_now=False)
- self.complete_helpers(policy)
- return graph
def complete_helpers(self, policy):
saved = self.policy, self.added_blocks
diff --git a/pypy/annotation/binaryop.py b/pypy/annotation/binaryop.py
--- a/pypy/annotation/binaryop.py
+++ b/pypy/annotation/binaryop.py
@@ -659,7 +659,7 @@
def mul((str1, int2)): # xxx do we want to support this
getbookkeeper().count("str_mul", str1, int2)
- return SomeString()
+ return SomeString(no_nul=str1.no_nul)
class __extend__(pairtype(SomeUnicodeString, SomeInteger)):
def getitem((str1, int2)):
diff --git a/pypy/annotation/bookkeeper.py b/pypy/annotation/bookkeeper.py
--- a/pypy/annotation/bookkeeper.py
+++ b/pypy/annotation/bookkeeper.py
@@ -531,8 +531,11 @@
try:
assert pyobj._freeze_()
except AttributeError:
- raise Exception("unexpected prebuilt constant: %r" % (
- pyobj,))
+ if hasattr(pyobj, '__call__'):
+ msg = "object with a __call__ is not RPython"
+ else:
+ msg = "unexpected prebuilt constant"
+ raise Exception("%s: %r" % (msg, pyobj))
result = self.getfrozen(pyobj)
self.descs[pyobj] = result
return result
diff --git a/pypy/annotation/description.py b/pypy/annotation/description.py
--- a/pypy/annotation/description.py
+++ b/pypy/annotation/description.py
@@ -514,9 +514,9 @@
continue
self.add_source_attribute(name, value, mixin=True)
- def add_sources_for_class(self, cls, mixin=False):
+ def add_sources_for_class(self, cls):
for name, value in cls.__dict__.items():
- self.add_source_attribute(name, value, mixin)
+ self.add_source_attribute(name, value)
def getallclassdefs(self):
return self._classdefs.values()
diff --git a/pypy/annotation/test/test_annrpython.py b/pypy/annotation/test/test_annrpython.py
--- a/pypy/annotation/test/test_annrpython.py
+++ b/pypy/annotation/test/test_annrpython.py
@@ -2138,6 +2138,15 @@
assert isinstance(s, annmodel.SomeString)
assert s.no_nul
+ def test_mul_str0(self):
+ def f(s):
+ return s*10
+ a = self.RPythonAnnotator()
+ s = a.build_types(f, [annmodel.SomeString(no_nul=True)])
+ assert isinstance(s, annmodel.SomeString)
+ assert s.no_nul
+
+
def test_non_none_and_none_with_isinstance(self):
class A(object):
pass
@@ -2738,20 +2747,6 @@
s = a.build_types(f, [])
assert s.knowntype == int
- def test_helper_method_annotator(self):
- def fun():
- return 21
-
- class A(object):
- def helper(self):
- return 42
-
- a = self.RPythonAnnotator()
- a.build_types(fun, [])
- a.annotate_helper_method(A, "helper", [])
- assert a.bookkeeper.getdesc(A.helper).getuniquegraph()
- assert a.bookkeeper.getdesc(A().helper).getuniquegraph()
-
def test_chr_out_of_bounds(self):
def g(n, max):
if n < max:
@@ -3769,6 +3764,37 @@
assert isinstance(s, annmodel.SomeString)
assert not s.can_be_None
+ def test_no___call__(self):
+ class X(object):
+ def __call__(self):
+ xxx
+ x = X()
+ def f():
+ return x
+ a = self.RPythonAnnotator()
+ e = py.test.raises(Exception, a.build_types, f, [])
+ assert 'object with a __call__ is not RPython' in str(e.value)
+
+ def test_os_getcwd(self):
+ import os
+ def fn():
+ return os.getcwd()
+ a = self.RPythonAnnotator()
+ s = a.build_types(fn, [])
+ assert isinstance(s, annmodel.SomeString)
+ assert s.no_nul
+
+ def test_os_getenv(self):
+ import os
+ def fn():
+ return os.environ.get('PATH')
+ a = self.RPythonAnnotator()
+ s = a.build_types(fn, [])
+ assert isinstance(s, annmodel.SomeString)
+ assert s.no_nul
+
+
+
def g(n):
return [0,1,2,n]
diff --git a/pypy/bin/py.py b/pypy/bin/py.py
--- a/pypy/bin/py.py
+++ b/pypy/bin/py.py
@@ -89,12 +89,12 @@
space.setitem(space.sys.w_dict, space.wrap('executable'),
space.wrap(argv[0]))
- # call pypy_initial_path: the side-effect is that it sets sys.prefix and
+ # call pypy_find_stdlib: the side-effect is that it sets sys.prefix and
# sys.exec_prefix
- srcdir = os.path.dirname(os.path.dirname(pypy.__file__))
- space.appexec([space.wrap(srcdir)], """(srcdir):
+ executable = argv[0]
+ space.appexec([space.wrap(executable)], """(executable):
import sys
- sys.pypy_initial_path(srcdir)
+ sys.pypy_find_stdlib(executable)
""")
# set warning control options (if any)
diff --git a/pypy/bin/rpython b/pypy/bin/rpython
old mode 100644
new mode 100755
diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py
--- a/pypy/config/pypyoption.py
+++ b/pypy/config/pypyoption.py
@@ -79,6 +79,7 @@
module_dependencies = {
'_multiprocessing': [('objspace.usemodules.rctime', True),
('objspace.usemodules.thread', True)],
+ 'cpyext': [('objspace.usemodules.array', True)],
}
module_suggests = {
# the reason you want _rawffi is for ctypes, which
diff --git a/pypy/doc/coding-guide.rst b/pypy/doc/coding-guide.rst
--- a/pypy/doc/coding-guide.rst
+++ b/pypy/doc/coding-guide.rst
@@ -610,10 +610,6 @@
>>>> cPickle.__file__
'/home/hpk/pypy-dist/lib_pypy/cPickle..py'
- >>>> import opcode
- >>>> opcode.__file__
- '/home/hpk/pypy-dist/lib-python/modified-2.7/opcode.py'
-
>>>> import os
>>>> os.__file__
'/home/hpk/pypy-dist/lib-python/2.7/os.py'
@@ -639,13 +635,9 @@
contains pure Python reimplementation of modules.
-*lib-python/modified-2.7/*
-
- The files and tests that we have modified from the CPython library.
-
*lib-python/2.7/*
- The unmodified CPython library. **Never ever check anything in there**.
+ The modified CPython library.
.. _`modify modules`:
@@ -658,16 +650,9 @@
by default and CPython has a number of places where it relies
on some classes being old-style.
-If you want to change a module or test contained in ``lib-python/2.7``
-then make sure that you copy the file to our ``lib-python/modified-2.7``
-directory first. In mercurial commandline terms this reads::
-
- $ hg cp lib-python/2.7/somemodule.py lib-python/modified-2.7/
-
-and subsequently you edit and commit
-``lib-python/modified-2.7/somemodule.py``. This copying operation is
-important because it keeps the original CPython tree clean and makes it
-obvious what we had to change.
+We just maintain those changes in place,
+to see what is changed we have a branch called `vendot/stdlib`
+wich contains the unmodified cpython stdlib
.. _`mixed module mechanism`:
.. _`mixed modules`:
diff --git a/pypy/doc/conf.py b/pypy/doc/conf.py
--- a/pypy/doc/conf.py
+++ b/pypy/doc/conf.py
@@ -45,9 +45,9 @@
# built documents.
#
# The short X.Y version.
-version = '1.8'
+version = '1.9'
# The full version, including alpha/beta/rc tags.
-release = '1.8'
+release = '1.9'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
diff --git a/pypy/doc/cppyy.rst b/pypy/doc/cppyy.rst
--- a/pypy/doc/cppyy.rst
+++ b/pypy/doc/cppyy.rst
@@ -5,8 +5,10 @@
The cppyy module provides C++ bindings for PyPy by using the reflection
information extracted from C++ header files by means of the
`Reflex package`_.
-For this to work, you have to both install Reflex and build PyPy from the
-reflex-support branch.
+For this to work, you have to both install Reflex and build PyPy from source,
+as the cppyy module is not enabled by default.
+Note that the development version of cppyy lives in the reflex-support
+branch.
As indicated by this being a branch, support for Reflex is still
experimental.
However, it is functional enough to put it in the hands of those who want
@@ -71,23 +73,33 @@
.. _`recent snapshot`: http://cern.ch/wlav/reflex-2012-05-02.tar.bz2
.. _`gccxml`: http://www.gccxml.org
-Next, get the `PyPy sources`_, select the reflex-support branch, and build
-pypy-c.
+Next, get the `PyPy sources`_, optionally select the reflex-support branch,
+and build it.
For the build to succeed, the ``$ROOTSYS`` environment variable must point to
-the location of your ROOT (or standalone Reflex) installation::
+the location of your ROOT (or standalone Reflex) installation, or the
+``root-config`` utility must be accessible through ``PATH`` (e.g. by adding
+``$ROOTSYS/bin`` to ``PATH``).
+In case of the former, include files are expected under ``$ROOTSYS/include``
+and libraries under ``$ROOTSYS/lib``.
+Then run the translation to build ``pypy-c``::
$ hg clone https://bitbucket.org/pypy/pypy
$ cd pypy
- $ hg up reflex-support
+ $ hg up reflex-support # optional
$ cd pypy/translator/goal
+
+ # This example shows python, but using pypy-c is faster and uses less memory
$ python translate.py -O jit --gcrootfinder=shadowstack targetpypystandalone.py --withmod-cppyy
This will build a ``pypy-c`` that includes the cppyy module, and through that,
Reflex support.
Of course, if you already have a pre-built version of the ``pypy`` interpreter,
you can use that for the translation rather than ``python``.
+If not, you may want `to obtain a binary distribution`_ to speed up the
+translation step.
.. _`PyPy sources`: https://bitbucket.org/pypy/pypy/overview
+.. _`to obtain a binary distribution`: http://doc.pypy.org/en/latest/getting-started.html#download-a-pre-built-pypy
Basic example
@@ -115,7 +127,7 @@
code::
$ genreflex MyClass.h
- $ g++ -fPIC -rdynamic -O2 -shared -I$ROOTSYS/include MyClass_rflx.cpp -o libMyClassDict.so
+ $ g++ -fPIC -rdynamic -O2 -shared -I$ROOTSYS/include MyClass_rflx.cpp -o libMyClassDict.so -L$ROOTSYS/lib -lReflex
Now you're ready to use the bindings.
Since the bindings are designed to look pythonistic, it should be
@@ -139,6 +151,51 @@
That's all there is to it!
+Automatic class loader
+======================
+There is one big problem in the code above, that prevents its use in a (large
+scale) production setting: the explicit loading of the reflection library.
+Clearly, if explicit load statements such as these show up in code downstream
+from the ``MyClass`` package, then that prevents the ``MyClass`` author from
+repackaging or even simply renaming the dictionary library.
+
+The solution is to make use of an automatic class loader, so that downstream
+code never has to call ``load_reflection_info()`` directly.
+The class loader makes use of so-called rootmap files, which ``genreflex``
+can produce.
+These files contain the list of available C++ classes and specify the library
+that needs to be loaded for their use.
+By convention, the rootmap files should be located next to the reflection info
+libraries, so that they can be found through the normal shared library search
+path.
+They can be concatenated together, or consist of a single rootmap file per
+library.
+For example::
+
+ $ genreflex MyClass.h --rootmap=libMyClassDict.rootmap --rootmap-lib=libMyClassDict.so
+ $ g++ -fPIC -rdynamic -O2 -shared -I$ROOTSYS/include MyClass_rflx.cpp -o libMyClassDict.so -L$ROOTSYS/lib -lReflex
+
+where the first option (``--rootmap``) specifies the output file name, and the
+second option (``--rootmap-lib``) the name of the reflection library where
+``MyClass`` will live.
+It is necessary to provide that name explicitly, since it is only in the
+separate linking step where this name is fixed.
+If the second option is not given, the library is assumed to be libMyClass.so,
+a name that is derived from the name of the header file.
+
+With the rootmap file in place, the above example can be rerun without explicit
+loading of the reflection info library::
+
+ $ pypy-c
+ >>>> import cppyy
+ >>>> myinst = cppyy.gbl.MyClass(42)
+ >>>> print myinst.GetMyInt()
+ 42
+ >>>> # etc. ...
+
+As a caveat, note that the class loader is currently limited to classes only.
+
+
Advanced example
================
The following snippet of C++ is very contrived, to allow showing that such
@@ -171,7 +228,7 @@
std::string m_name;
};
- Base1* BaseFactory(const std::string& name, int i, double d) {
+ Base2* BaseFactory(const std::string& name, int i, double d) {
return new Derived(name, i, d);
}
@@ -213,7 +270,7 @@
Now the reflection info can be generated and compiled::
$ genreflex MyAdvanced.h --selection=MyAdvanced.xml
- $ g++ -fPIC -rdynamic -O2 -shared -I$ROOTSYS/include MyAdvanced_rflx.cpp -o libAdvExDict.so
+ $ g++ -fPIC -rdynamic -O2 -shared -I$ROOTSYS/include MyAdvanced_rflx.cpp -o libAdvExDict.so -L$ROOTSYS/lib -lReflex
and subsequently be used from PyPy::
@@ -237,7 +294,7 @@
A couple of things to note, though.
If you look back at the C++ definition of the ``BaseFactory`` function,
-you will see that it declares the return type to be a ``Base1``, yet the
+you will see that it declares the return type to be a ``Base2``, yet the
bindings return an object of the actual type ``Derived``?
This choice is made for a couple of reasons.
First, it makes method dispatching easier: if bound objects are always their
@@ -319,6 +376,11 @@
The C++ side will not see any overridden methods on the python side, as
cross-inheritance is planned but not yet supported.
+* **memory**: C++ instances created by calling their constructor from python
+ are owned by python.
+ You can check/change the ownership with the _python_owns flag that every
+ bound instance carries.
+
* **methods**: Are represented as python methods and work as expected.
They are first class objects and can be bound to an instance.
Virtual C++ methods work as expected.
@@ -361,6 +423,11 @@
If a pointer is a global variable, the C++ side can replace the underlying
object and the python side will immediately reflect that.
+* **PyObject***: Arguments and return types of ``PyObject*`` can be used, and
+ passed on to CPython API calls.
+ Since these CPython-like objects need to be created and tracked (this all
+ happens through ``cpyext``) this interface is not particularly fast.
+
* **static data members**: Are represented as python property objects on the
class and the meta-class.
Both read and write access is as expected.
@@ -429,7 +496,9 @@
int m_i;
};
- template class std::vector<MyClass>;
+ #ifdef __GCCXML__
+ template class std::vector<MyClass>; // explicit instantiation
+ #endif
If you know for certain that all symbols will be linked in from other sources,
you can also declare the explicit template instantiation ``extern``.
@@ -440,8 +509,9 @@
internal namespace, rather than in the iterator classes.
One way to handle this, is to deal with this once in a macro, then reuse that
macro for all ``vector`` classes.
-Thus, the header above needs this, instead of just the explicit instantiation
-of the ``vector<MyClass>``::
+Thus, the header above needs this (again protected with
+``#ifdef __GCCXML__``), instead of just the explicit instantiation of the
+``vector<MyClass>``::
#define STLTYPES_EXPLICIT_INSTANTIATION_DECL(STLTYPE, TTYPE) \
template class std::STLTYPE< TTYPE >; \
@@ -462,11 +532,9 @@
$ cat MyTemplate.xml
<lcgdict>
<class pattern="std::vector<*>" />
- <class pattern="__gnu_cxx::__normal_iterator<*>" />
- <class pattern="__gnu_cxx::new_allocator<*>" />
+ <class pattern="std::vector<*>::iterator" />
<class pattern="std::_Vector_base<*>" />
<class pattern="std::_Vector_base<*>::_Vector_impl" />
- <class pattern="std::allocator<*>" />
<function name="__gnu_cxx::operator=="/>
<function name="__gnu_cxx::operator!="/>
@@ -475,8 +543,8 @@
Run the normal ``genreflex`` and compilation steps::
- $ genreflex MyTemplate.h --selection=MyTemplate.xm
- $ g++ -fPIC -rdynamic -O2 -shared -I$ROOTSYS/include MyTemplate_rflx.cpp -o libTemplateDict.so
+ $ genreflex MyTemplate.h --selection=MyTemplate.xml
+ $ g++ -fPIC -rdynamic -O2 -shared -I$ROOTSYS/include MyTemplate_rflx.cpp -o libTemplateDict.so -L$ROOTSYS/lib -lReflex
Note: this is a dirty corner that clearly could do with some automation,
even if the macro already helps.
@@ -550,7 +618,9 @@
There are a couple of minor differences between PyCintex and cppyy, most to do
with naming.
The one that you will run into directly, is that PyCintex uses a function
-called ``loadDictionary`` rather than ``load_reflection_info``.
+called ``loadDictionary`` rather than ``load_reflection_info`` (it has the
+same rootmap-based class loader functionality, though, making this point
+somewhat moot).
The reason for this is that Reflex calls the shared libraries that contain
reflection info "dictionaries."
However, in python, the name `dictionary` already has a well-defined meaning,
diff --git a/pypy/doc/cpython_differences.rst b/pypy/doc/cpython_differences.rst
--- a/pypy/doc/cpython_differences.rst
+++ b/pypy/doc/cpython_differences.rst
@@ -85,13 +85,6 @@
_winreg
- Note that only some of these modules are built-in in a typical
- CPython installation, and the rest is from non built-in extension
- modules. This means that e.g. ``import parser`` will, on CPython,
- find a local file ``parser.py``, while ``import sys`` will not find a
- local file ``sys.py``. In PyPy the difference does not exist: all
- these modules are built-in.
-
* Supported by being rewritten in pure Python (possibly using ``ctypes``):
see the `lib_pypy/`_ directory. Examples of modules that we
support this way: ``ctypes``, ``cPickle``, ``cmath``, ``dbm``, ``datetime``...
@@ -324,5 +317,10 @@
type and vice versa. For builtin types, a dictionary will be returned that
cannot be changed (but still looks and behaves like a normal dictionary).
+* the ``__len__`` or ``__length_hint__`` special methods are sometimes
+ called by CPython to get a length estimate to preallocate internal arrays.
+ So far, PyPy never calls ``__len__`` for this purpose, and never calls
+ ``__length_hint__`` at all.
+
.. include:: _ref.txt
diff --git a/pypy/doc/extending.rst b/pypy/doc/extending.rst
--- a/pypy/doc/extending.rst
+++ b/pypy/doc/extending.rst
@@ -23,7 +23,7 @@
* Write them in RPython as mixedmodule_, using *rffi* as bindings.
-* Write them in C++ and bind them through Reflex_ (EXPERIMENTAL)
+* Write them in C++ and bind them through Reflex_
.. _ctypes: #CTypes
.. _\_ffi: #LibFFI
diff --git a/pypy/doc/getting-started-python.rst b/pypy/doc/getting-started-python.rst
--- a/pypy/doc/getting-started-python.rst
+++ b/pypy/doc/getting-started-python.rst
@@ -50,10 +50,10 @@
libz-dev libbz2-dev libncurses-dev libexpat1-dev \
libssl-dev libgc-dev python-sphinx python-greenlet
- On a Fedora box these are::
+ On a Fedora-16 box these are::
[user at fedora-or-rh-box ~]$ sudo yum install \
- gcc make python-devel libffi-devel pkg-config \
+ gcc make python-devel libffi-devel pkgconfig \
zlib-devel bzip2-devel ncurses-devel expat-devel \
openssl-devel gc-devel python-sphinx python-greenlet
@@ -103,10 +103,12 @@
executable. The executable behaves mostly like a normal Python interpreter::
$ ./pypy-c
- Python 2.7.2 (0e28b379d8b3, Feb 09 2012, 19:41:03)
- [PyPy 1.8.0 with GCC 4.4.3] on linux2
+ Python 2.7.2 (341e1e3821ff, Jun 07 2012, 15:40:31)
+ [PyPy 1.9.0 with GCC 4.4.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
- And now for something completely different: ``this sentence is false''
+ And now for something completely different: ``RPython magically makes you rich
+ and famous (says so on the tin)''
+
>>>> 46 - 4
42
>>>> from test import pystone
@@ -220,7 +222,6 @@
./include/
./lib_pypy/
./lib-python/2.7
- ./lib-python/modified-2.7
./site-packages/
The hierarchy shown above is relative to a PREFIX directory. PREFIX is
diff --git a/pypy/doc/getting-started.rst b/pypy/doc/getting-started.rst
--- a/pypy/doc/getting-started.rst
+++ b/pypy/doc/getting-started.rst
@@ -53,10 +53,10 @@
PyPy is ready to be executed as soon as you unpack the tarball or the zip
file, with no need to install it in any specific location::
- $ tar xf pypy-1.8-linux.tar.bz2
- $ ./pypy-1.8/bin/pypy
- Python 2.7.2 (0e28b379d8b3, Feb 09 2012, 19:41:03)
- [PyPy 1.8.0 with GCC 4.4.3] on linux2
+ $ tar xf pypy-1.9-linux.tar.bz2
+ $ ./pypy-1.9/bin/pypy
+ Python 2.7.2 (341e1e3821ff, Jun 07 2012, 15:40:31)
+ [PyPy 1.9.0 with GCC 4.4.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
And now for something completely different: ``it seems to me that once you
settle on an execution / object model and / or bytecode format, you've already
@@ -76,14 +76,14 @@
$ curl -O https://raw.github.com/pypa/pip/master/contrib/get-pip.py
- $ ./pypy-1.8/bin/pypy distribute_setup.py
+ $ ./pypy-1.9/bin/pypy distribute_setup.py
- $ ./pypy-1.8/bin/pypy get-pip.py
+ $ ./pypy-1.9/bin/pypy get-pip.py
- $ ./pypy-1.8/bin/pip install pygments # for example
+ $ ./pypy-1.9/bin/pip install pygments # for example
-3rd party libraries will be installed in ``pypy-1.8/site-packages``, and
-the scripts in ``pypy-1.8/bin``.
+3rd party libraries will be installed in ``pypy-1.9/site-packages``, and
+the scripts in ``pypy-1.9/bin``.
Installing using virtualenv
---------------------------
diff --git a/pypy/doc/how-to-release.rst b/pypy/doc/how-to-release.rst
--- a/pypy/doc/how-to-release.rst
+++ b/pypy/doc/how-to-release.rst
@@ -23,7 +23,9 @@
some of the next updates may be done before or after branching; make
sure things are ported back to the trunk and to the branch as
necessary
-* update pypy/doc/contributor.txt (and possibly LICENSE)
+* update pypy/doc/contributor.rst (and possibly LICENSE)
+* rename pypy/doc/whatsnew_head.rst to whatsnew_VERSION.rst
+ and create a fresh whatsnew_head.rst after the release
* update README
* change the tracker to have a new release tag to file bugs against
* go to pypy/tool/release and run:
diff --git a/pypy/doc/index.rst b/pypy/doc/index.rst
--- a/pypy/doc/index.rst
+++ b/pypy/doc/index.rst
@@ -15,7 +15,7 @@
* `FAQ`_: some frequently asked questions.
-* `Release 1.8`_: the latest official release
+* `Release 1.9`_: the latest official release
* `PyPy Blog`_: news and status info about PyPy
@@ -75,7 +75,7 @@
.. _`Getting Started`: getting-started.html
.. _`Papers`: extradoc.html
.. _`Videos`: video-index.html
-.. _`Release 1.8`: http://pypy.org/download.html
+.. _`Release 1.9`: http://pypy.org/download.html
.. _`speed.pypy.org`: http://speed.pypy.org
.. _`RPython toolchain`: translation.html
.. _`potential project ideas`: project-ideas.html
@@ -120,9 +120,9 @@
Windows, on top of .NET, and on top of Java.
To dig into PyPy it is recommended to try out the current
Mercurial default branch, which is always working or mostly working,
-instead of the latest release, which is `1.8`__.
+instead of the latest release, which is `1.9`__.
-.. __: release-1.8.0.html
+.. __: release-1.9.0.html
PyPy is mainly developed on Linux and Mac OS X. Windows is supported,
but platform-specific bugs tend to take longer before we notice and fix
diff --git a/pypy/doc/release-1.9.0.rst b/pypy/doc/release-1.9.0.rst
new file mode 100644
--- /dev/null
+++ b/pypy/doc/release-1.9.0.rst
@@ -0,0 +1,111 @@
+====================
+PyPy 1.9 - Yard Wolf
+====================
+
+We're pleased to announce the 1.9 release of PyPy. This release brings mostly
+bugfixes, performance improvements, other small improvements and overall
+progress on the `numpypy`_ effort.
+It also brings an improved situation on Windows and OS X.
+
+You can download the PyPy 1.9 release here:
+
+ http://pypy.org/download.html
+
+.. _`numpypy`: http://pypy.org/numpydonate.html
+
+
+What is PyPy?
+=============
+
+PyPy is a very compliant Python interpreter, almost a drop-in replacement for
+CPython 2.7. It's fast (`pypy 1.9 and cpython 2.7.2`_ performance comparison)
+due to its integrated tracing JIT compiler.
+
+This release supports x86 machines running Linux 32/64, Mac OS X 64 or
+Windows 32. Windows 64 work is still stalling, we would welcome a volunteer
+to handle that.
+
+.. _`pypy 1.9 and cpython 2.7.2`: http://speed.pypy.org
+
+
+Thanks to our donors
+====================
+
+But first of all, we would like to say thank you to all people who
+donated some money to one of our four calls:
+
+ * `NumPy in PyPy`_ (got so far $44502 out of $60000, 74%)
+
+ * `Py3k (Python 3)`_ (got so far $43563 out of $105000, 41%)
+
+ * `Software Transactional Memory`_ (got so far $21791 of $50400, 43%)
+
+ * as well as our general PyPy pot.
+
+Thank you all for proving that it is indeed possible for a small team of
+programmers to get funded like that, at least for some
+time. We want to include this thank you in the present release
+announcement even though most of the work is not finished yet. More
+precisely, neither Py3k nor STM are ready to make it in an official release
+yet: people interested in them need to grab and (attempt to) translate
+PyPy from the corresponding branches (respectively ``py3k`` and
+``stm-thread``).
+
+.. _`NumPy in PyPy`: http://pypy.org/numpydonate.html
+.. _`Py3k (Python 3)`: http://pypy.org/py3donate.html
+.. _`Software Transactional Memory`: http://pypy.org/tmdonate.html
+
+Highlights
+==========
+
+* This release still implements Python 2.7.2.
+
+* Many bugs were corrected for Windows 32 bit. This includes new
+ functionality to test the validity of file descriptors; and
+ correct handling of the calling convensions for ctypes. (Still not
+ much progress on Win64.) A lot of work on this has been done by Matti Picus
+ and Amaury Forgeot d'Arc.
+
+* Improvements in ``cpyext``, our emulator for CPython C extension modules.
+ For example PyOpenSSL should now work. We thank various people for help.
+
+* Sets now have strategies just like dictionaries. This means for example
+ that a set containing only ints will be more compact (and faster).
+
+* A lot of progress on various aspects of ``numpypy``. See the `numpy-status`_
+ page for the automatic report.
+
+* It is now possible to create and manipulate C-like structures using the
+ PyPy-only ``_ffi`` module. The advantage over using e.g. ``ctypes`` is that
+ ``_ffi`` is very JIT-friendly, and getting/setting of fields is translated
+ to few assembler instructions by the JIT. However, this is mostly intended
+ as a low-level backend to be used by more user-friendly FFI packages, and
+ the API might change in the future. Use it at your own risk.
+
+* The non-x86 backends for the JIT are progressing but are still not
+ merged (ARMv7 and PPC64).
+
+* JIT hooks for inspecting the created assembler code have been improved.
+ See `JIT hooks documentation`_ for details.
+
+* ``select.kqueue`` has been added (BSD).
+
+* Handling of keyword arguments has been drastically improved in the best-case
+ scenario: proxy functions which simply forwards ``*args`` and ``**kwargs``
+ to another function now performs much better with the JIT.
+
+* List comprehension has been improved.
+
+.. _`numpy-status`: http://buildbot.pypy.org/numpy-status/latest.html
+.. _`JIT hooks documentation`: http://doc.pypy.org/en/latest/jit-hooks.html
+
+JitViewer
+=========
+
+There will be a corresponding 1.9 release of JitViewer which is guaranteed
+to work with PyPy 1.9. See the `JitViewer docs`_ for details.
+
+.. _`JitViewer docs`: http://bitbucket.org/pypy/jitviewer
+
+Cheers,
+The PyPy Team
diff --git a/pypy/doc/test/test_whatsnew.py b/pypy/doc/test/test_whatsnew.py
--- a/pypy/doc/test/test_whatsnew.py
+++ b/pypy/doc/test/test_whatsnew.py
@@ -16,6 +16,7 @@
startrev = parseline(line)
elif line.startswith('.. branch:'):
branches.add(parseline(line))
+ branches.discard('default')
return startrev, branches
def get_merged_branches(path, startrev, endrev):
@@ -51,6 +52,10 @@
.. branch: hello
qqq www ttt
+
+.. branch: default
+
+"default" should be ignored and not put in the set of documented branches
"""
startrev, branches = parse_doc(s)
assert startrev == '12345'
diff --git a/pypy/doc/whatsnew-1.9.rst b/pypy/doc/whatsnew-1.9.rst
--- a/pypy/doc/whatsnew-1.9.rst
+++ b/pypy/doc/whatsnew-1.9.rst
@@ -5,8 +5,12 @@
.. this is the revision just after the creation of the release-1.8.x branch
.. startrev: a4261375b359
+.. branch: default
+* Working hash function for numpy types.
+
.. branch: array_equal
.. branch: better-jit-hooks-2
+Improved jit hooks
.. branch: faster-heapcache
.. branch: faster-str-decode-escape
.. branch: float-bytes
@@ -16,9 +20,14 @@
.. branch: jit-frame-counter
Put more debug info into resops.
.. branch: kill-geninterp
+Kill "geninterp", an old attempt to statically turn some fixed
+app-level code to interp-level.
.. branch: kqueue
Finished select.kqueue.
.. branch: kwargsdict-strategy
+Special dictionary strategy for dealing with \*\*kwds. Now having a simple
+proxy ``def f(*args, **kwds): return x(*args, **kwds`` should not make
+any allocations at all.
.. branch: matrixmath-dot
numpypy can now handle matrix multiplication.
.. branch: merge-2.7.2
@@ -29,13 +38,19 @@
cpyext: Better support for PyEval_SaveThread and other PyTreadState_*
functions.
.. branch: numppy-flatitter
+flatitier for numpy
.. branch: numpy-back-to-applevel
+reuse more of original numpy
.. branch: numpy-concatenate
+concatenation support for numpy
.. branch: numpy-indexing-by-arrays-bool
+indexing by bool arrays
.. branch: numpy-record-dtypes
+record dtypes on numpy has been started
.. branch: numpy-single-jitdriver
.. branch: numpy-ufuncs2
.. branch: numpy-ufuncs3
+various refactorings regarding numpy
.. branch: numpypy-issue1137
.. branch: numpypy-out
The "out" argument was added to most of the numypypy functions.
@@ -43,8 +58,13 @@
.. branch: numpypy-ufuncs
.. branch: pytest
.. branch: safe-getargs-freelist
+CPyext improvements. For example PyOpenSSL should now work
.. branch: set-strategies
+Sets now have strategies just like dictionaries. This means a set
+containing only ints will be more compact (and faster)
.. branch: speedup-list-comprehension
+The simplest case of list comprehension is preallocating the correct size
+of the list. This speeds up select benchmarks quite significantly.
.. branch: stdlib-unification
The directory "lib-python/modified-2.7" has been removed, and its
content merged into "lib-python/2.7".
@@ -62,8 +82,13 @@
Many bugs were corrected for windows 32 bit. New functionality was added to
test validity of file descriptors, leading to the removal of the global
_invalid_parameter_handler
+.. branch: win32-kill
+Add os.kill to windows even if translating python does not have os.kill
+.. branch: win_ffi
+Handle calling conventions for the _ffi and ctypes modules
.. branch: win64-stage1
.. branch: zlib-mem-pressure
+Memory "leaks" associated with zlib are fixed.
.. branch: ffistruct
The ``ffistruct`` branch adds a very low level way to express C structures
diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst
new file mode 100644
--- /dev/null
+++ b/pypy/doc/whatsnew-head.rst
@@ -0,0 +1,18 @@
+======================
+What's new in PyPy xxx
+======================
+
+.. this is the revision of the last merge from default to release-1.9.x
+.. startrev: 8d567513d04d
+
+.. branch: default
+.. branch: app_main-refactor
+.. branch: win-ordinal
+.. branch: reflex-support
+Provides cppyy module (disabled by default) for access to C++ through Reflex.
+See doc/cppyy.rst for full details and functionality.
+.. branch: nupypy-axis-arg-check
+Check that axis arg is valid in _numpypy
+
+.. "uninteresting" branches that we should just ignore for the whatsnew:
+.. branch: slightly-shorter-c
diff --git a/pypy/interpreter/astcompiler/test/test_astbuilder.py b/pypy/interpreter/astcompiler/test/test_astbuilder.py
--- a/pypy/interpreter/astcompiler/test/test_astbuilder.py
+++ b/pypy/interpreter/astcompiler/test/test_astbuilder.py
@@ -1105,6 +1105,17 @@
assert isinstance(s, ast.Str)
assert space.eq_w(s.s, space.wrap(sentence))
+ def test_string_bug(self):
+ space = self.space
+ source = '# -*- encoding: utf8 -*-\nstuff = "x \xc3\xa9 \\n"\n'
+ info = pyparse.CompileInfo("<test>", "exec")
+ tree = self.parser.parse_source(source, info)
+ assert info.encoding == "utf8"
+ s = ast_from_node(space, tree, info).body[0].value
+ assert isinstance(s, ast.Str)
+ expected = ['x', ' ', chr(0xc3), chr(0xa9), ' ', '\n']
+ assert space.eq_w(s.s, space.wrap(''.join(expected)))
+
def test_number(self):
def get_num(s):
node = self.get_first_expr(s)
diff --git a/pypy/interpreter/buffer.py b/pypy/interpreter/buffer.py
--- a/pypy/interpreter/buffer.py
+++ b/pypy/interpreter/buffer.py
@@ -44,6 +44,9 @@
# May be overridden. No bounds checks.
return ''.join([self.getitem(i) for i in range(start, stop, step)])
+ def get_raw_address(self):
+ raise ValueError("no raw buffer")
+
# __________ app-level support __________
def descr_len(self, space):
diff --git a/pypy/interpreter/pyparser/parsestring.py b/pypy/interpreter/pyparser/parsestring.py
--- a/pypy/interpreter/pyparser/parsestring.py
+++ b/pypy/interpreter/pyparser/parsestring.py
@@ -97,7 +97,8 @@
return space.wrap(v)
need_encoding = (encoding is not None and
- encoding != "utf-8" and encoding != "iso-8859-1")
+ encoding != "utf-8" and encoding != "utf8" and
+ encoding != "iso-8859-1")
assert 0 <= ps <= q
substr = s[ps : q]
if rawmode or '\\' not in s[ps:]:
@@ -129,19 +130,18 @@
builder = StringBuilder(len(s))
ps = 0
end = len(s)
- while 1:
- ps2 = ps
- while ps < end and s[ps] != '\\':
+ while ps < end:
+ if s[ps] != '\\':
+ # note that the C code has a label here.
+ # the logic is the same.
if recode_encoding and ord(s[ps]) & 0x80:
w, ps = decode_utf8(space, s, ps, end, recode_encoding)
+ # Append bytes to output buffer.
builder.append(w)
- ps2 = ps
else:
+ builder.append(s[ps])
ps += 1
- if ps > ps2:
- builder.append_slice(s, ps2, ps)
- if ps == end:
- break
+ continue
ps += 1
if ps == end:
diff --git a/pypy/interpreter/pyparser/test/test_parsestring.py b/pypy/interpreter/pyparser/test/test_parsestring.py
--- a/pypy/interpreter/pyparser/test/test_parsestring.py
+++ b/pypy/interpreter/pyparser/test/test_parsestring.py
@@ -84,3 +84,10 @@
s = '"""' + '\\' + '\n"""'
w_ret = parsestring.parsestr(space, None, s)
assert space.str_w(w_ret) == ''
+
+ def test_bug1(self):
+ space = self.space
+ expected = ['x', ' ', chr(0xc3), chr(0xa9), ' ', '\n']
+ input = ["'", 'x', ' ', chr(0xc3), chr(0xa9), ' ', chr(92), 'n', "'"]
+ w_ret = parsestring.parsestr(space, 'utf8', ''.join(input))
+ assert space.str_w(w_ret) == ''.join(expected)
diff --git a/pypy/jit/backend/arm/test/test_ztranslation.py b/pypy/jit/backend/arm/test/test_ztranslation.py
--- a/pypy/jit/backend/arm/test/test_ztranslation.py
+++ b/pypy/jit/backend/arm/test/test_ztranslation.py
@@ -74,7 +74,7 @@
#
from pypy.rpython.lltypesystem import lltype, rffi
from pypy.rlib.libffi import types, CDLL, ArgChain
- from pypy.rlib.test.test_libffi import get_libm_name
+ from pypy.rlib.test.test_clibffi import get_libm_name
libm_name = get_libm_name(sys.platform)
jitdriver2 = JitDriver(greens=[], reds = ['i', 'func', 'res', 'x'])
def libffi_stuff(i, j):
diff --git a/pypy/jit/backend/llsupport/gc.py b/pypy/jit/backend/llsupport/gc.py
--- a/pypy/jit/backend/llsupport/gc.py
+++ b/pypy/jit/backend/llsupport/gc.py
@@ -577,7 +577,6 @@
def __init__(self, gc_ll_descr):
self.llop1 = gc_ll_descr.llop1
self.WB_FUNCPTR = gc_ll_descr.WB_FUNCPTR
- self.WB_ARRAY_FUNCPTR = gc_ll_descr.WB_ARRAY_FUNCPTR
self.fielddescr_tid = gc_ll_descr.fielddescr_tid
#
GCClass = gc_ll_descr.GCClass
@@ -592,6 +591,11 @@
self.jit_wb_card_page_shift = GCClass.JIT_WB_CARD_PAGE_SHIFT
self.jit_wb_cards_set_byteofs, self.jit_wb_cards_set_singlebyte = (
self.extract_flag_byte(self.jit_wb_cards_set))
+ #
+ # the x86 backend uses the following "accidental" facts to
+ # avoid one instruction:
+ assert self.jit_wb_cards_set_byteofs == self.jit_wb_if_flag_byteofs
+ assert self.jit_wb_cards_set_singlebyte == -0x80
else:
self.jit_wb_cards_set = 0
@@ -615,7 +619,7 @@
# returns a function with arguments [array, index, newvalue]
llop1 = self.llop1
funcptr = llop1.get_write_barrier_from_array_failing_case(
- self.WB_ARRAY_FUNCPTR)
+ self.WB_FUNCPTR)
funcaddr = llmemory.cast_ptr_to_adr(funcptr)
return cpu.cast_adr_to_int(funcaddr) # this may return 0
@@ -655,10 +659,11 @@
def _check_valid_gc(self):
# we need the hybrid or minimark GC for rgc._make_sure_does_not_move()
- # to work
- if self.gcdescr.config.translation.gc not in ('hybrid', 'minimark'):
+ # to work. Additionally, 'hybrid' is missing some stuff like
+ # jit_remember_young_pointer() for now.
+ if self.gcdescr.config.translation.gc not in ('minimark',):
raise NotImplementedError("--gc=%s not implemented with the JIT" %
- (gcdescr.config.translation.gc,))
+ (self.gcdescr.config.translation.gc,))
def _make_gcrootmap(self):
# to find roots in the assembler, make a GcRootMap
@@ -699,9 +704,7 @@
def _setup_write_barrier(self):
self.WB_FUNCPTR = lltype.Ptr(lltype.FuncType(
- [llmemory.Address, llmemory.Address], lltype.Void))
- self.WB_ARRAY_FUNCPTR = lltype.Ptr(lltype.FuncType(
- [llmemory.Address, lltype.Signed, llmemory.Address], lltype.Void))
+ [llmemory.Address], lltype.Void))
self.write_barrier_descr = WriteBarrierDescr(self)
def _make_functions(self, really_not_translated):
@@ -861,8 +864,7 @@
# the GC, and call it immediately
llop1 = self.llop1
funcptr = llop1.get_write_barrier_failing_case(self.WB_FUNCPTR)
- funcptr(llmemory.cast_ptr_to_adr(gcref_struct),
- llmemory.cast_ptr_to_adr(gcref_newptr))
+ funcptr(llmemory.cast_ptr_to_adr(gcref_struct))
def can_use_nursery_malloc(self, size):
return size < self.max_size_of_young_obj
diff --git a/pypy/jit/backend/llsupport/test/test_gc.py b/pypy/jit/backend/llsupport/test/test_gc.py
--- a/pypy/jit/backend/llsupport/test/test_gc.py
+++ b/pypy/jit/backend/llsupport/test/test_gc.py
@@ -276,8 +276,8 @@
repr(offset_to_length), p))
return p
- def _write_barrier_failing_case(self, adr_struct, adr_newptr):
- self.record.append(('barrier', adr_struct, adr_newptr))
+ def _write_barrier_failing_case(self, adr_struct):
+ self.record.append(('barrier', adr_struct))
def get_write_barrier_failing_case(self, FPTRTYPE):
return llhelper(FPTRTYPE, self._write_barrier_failing_case)
@@ -296,7 +296,7 @@
class TestFramework(object):
- gc = 'hybrid'
+ gc = 'minimark'
def setup_method(self, meth):
class config_(object):
@@ -402,7 +402,7 @@
#
s_hdr.tid |= gc_ll_descr.GCClass.JIT_WB_IF_FLAG
gc_ll_descr.do_write_barrier(s_gcref, r_gcref)
- assert self.llop1.record == [('barrier', s_adr, r_adr)]
+ assert self.llop1.record == [('barrier', s_adr)]
def test_gen_write_barrier(self):
gc_ll_descr = self.gc_ll_descr
diff --git a/pypy/jit/backend/llsupport/test/test_rewrite.py b/pypy/jit/backend/llsupport/test/test_rewrite.py
--- a/pypy/jit/backend/llsupport/test/test_rewrite.py
+++ b/pypy/jit/backend/llsupport/test/test_rewrite.py
@@ -205,7 +205,7 @@
def setup_method(self, meth):
class config_(object):
class translation(object):
- gc = 'hybrid'
+ gc = 'minimark'
gcrootfinder = 'asmgcc'
gctransformer = 'framework'
gcremovetypeptr = False
diff --git a/pypy/jit/backend/test/runner_test.py b/pypy/jit/backend/test/runner_test.py
--- a/pypy/jit/backend/test/runner_test.py
+++ b/pypy/jit/backend/test/runner_test.py
@@ -1141,6 +1141,79 @@
def test_virtual_ref_finish(self):
pass # VIRTUAL_REF_FINISH must not reach the backend nowadays
+ def test_arguments_to_execute_token(self):
+ # this test checks that execute_token() can be called with any
+ # variant of ints and floats as arguments
+ if self.cpu.supports_floats:
+ numkinds = 2
+ else:
+ numkinds = 1
+ seed = random.randrange(0, 10000)
+ print 'Seed is', seed # or choose it by changing the previous line
+ r = random.Random()
+ r.seed(seed)
+ for nb_args in range(50):
+ print 'Passing %d arguments to execute_token...' % nb_args
+ #
+ inputargs = []
+ values = []
+ for k in range(nb_args):
+ kind = r.randrange(0, numkinds)
+ if kind == 0:
+ inputargs.append(BoxInt())
+ values.append(r.randrange(-100000, 100000))
+ else:
+ inputargs.append(BoxFloat())
+ values.append(longlong.getfloatstorage(r.random()))
+ #
+ looptoken = JitCellToken()
+ faildescr = BasicFailDescr(42)
+ operations = []
+ retboxes = []
+ retvalues = []
+ #
+ ks = range(nb_args)
+ random.shuffle(ks)
+ for k in ks:
+ if isinstance(inputargs[k], BoxInt):
+ newbox = BoxInt()
+ x = r.randrange(-100000, 100000)
+ operations.append(
+ ResOperation(rop.INT_ADD, [inputargs[k],
+ ConstInt(x)], newbox)
+ )
+ y = values[k] + x
+ else:
+ newbox = BoxFloat()
+ x = r.random()
+ operations.append(
+ ResOperation(rop.FLOAT_ADD, [inputargs[k],
+ constfloat(x)], newbox)
+ )
+ y = longlong.getrealfloat(values[k]) + x
+ y = longlong.getfloatstorage(y)
+ kk = r.randrange(0, len(retboxes)+1)
+ retboxes.insert(kk, newbox)
+ retvalues.insert(kk, y)
+ #
+ operations.append(
+ ResOperation(rop.FINISH, retboxes, None, descr=faildescr)
+ )
+ print inputargs
+ for op in operations:
+ print op
+ self.cpu.compile_loop(inputargs, operations, looptoken)
+ #
+ fail = self.cpu.execute_token(looptoken, *values)
+ assert fail.identifier == 42
+ #
+ for k in range(len(retvalues)):
+ if isinstance(retboxes[k], BoxInt):
+ got = self.cpu.get_latest_value_int(k)
+ else:
+ got = self.cpu.get_latest_value_float(k)
+ assert got == retvalues[k]
+
def test_jump(self):
# this test generates small loops where the JUMP passes many
# arguments of various types, shuffling them around.
@@ -1994,12 +2067,12 @@
assert not excvalue
def test_cond_call_gc_wb(self):
- def func_void(a, b):
- record.append((a, b))
+ def func_void(a):
+ record.append(a)
record = []
#
S = lltype.GcStruct('S', ('tid', lltype.Signed))
- FUNC = self.FuncType([lltype.Ptr(S), lltype.Ptr(S)], lltype.Void)
+ FUNC = self.FuncType([lltype.Ptr(S)], lltype.Void)
func_ptr = llhelper(lltype.Ptr(FUNC), func_void)
funcbox = self.get_funcbox(self.cpu, func_ptr)
class WriteBarrierDescr(AbstractDescr):
@@ -2025,26 +2098,25 @@
[BoxPtr(sgcref), ConstPtr(tgcref)],
'void', descr=WriteBarrierDescr())
if cond:
- assert record == [(s, t)]
+ assert record == [s]
else:
assert record == []
def test_cond_call_gc_wb_array(self):
- def func_void(a, b, c):
- record.append((a, b, c))
+ def func_void(a):
+ record.append(a)
record = []
#
S = lltype.GcStruct('S', ('tid', lltype.Signed))
- FUNC = self.FuncType([lltype.Ptr(S), lltype.Signed, lltype.Ptr(S)],
- lltype.Void)
+ FUNC = self.FuncType([lltype.Ptr(S)], lltype.Void)
func_ptr = llhelper(lltype.Ptr(FUNC), func_void)
funcbox = self.get_funcbox(self.cpu, func_ptr)
class WriteBarrierDescr(AbstractDescr):
jit_wb_if_flag = 4096
jit_wb_if_flag_byteofs = struct.pack("i", 4096).index('\x10')
jit_wb_if_flag_singlebyte = 0x10
- jit_wb_cards_set = 0
- def get_write_barrier_from_array_fn(self, cpu):
+ jit_wb_cards_set = 0 # <= without card marking
+ def get_write_barrier_fn(self, cpu):
return funcbox.getint()
#
for cond in [False, True]:
@@ -2061,13 +2133,15 @@
[BoxPtr(sgcref), ConstInt(123), BoxPtr(sgcref)],
'void', descr=WriteBarrierDescr())
if cond:
- assert record == [(s, 123, s)]
+ assert record == [s]
else:
assert record == []
def test_cond_call_gc_wb_array_card_marking_fast_path(self):
- def func_void(a, b, c):
- record.append((a, b, c))
+ def func_void(a):
+ record.append(a)
+ if cond == 1: # the write barrier sets the flag
+ s.data.tid |= 32768
record = []
#
S = lltype.Struct('S', ('tid', lltype.Signed))
@@ -2081,34 +2155,40 @@
('card6', lltype.Char),
('card7', lltype.Char),
('data', S))
- FUNC = self.FuncType([lltype.Ptr(S), lltype.Signed, lltype.Ptr(S)],
- lltype.Void)
+ FUNC = self.FuncType([lltype.Ptr(S)], lltype.Void)
func_ptr = llhelper(lltype.Ptr(FUNC), func_void)
funcbox = self.get_funcbox(self.cpu, func_ptr)
class WriteBarrierDescr(AbstractDescr):
jit_wb_if_flag = 4096
jit_wb_if_flag_byteofs = struct.pack("i", 4096).index('\x10')
jit_wb_if_flag_singlebyte = 0x10
- jit_wb_cards_set = 8192
- jit_wb_cards_set_byteofs = struct.pack("i", 8192).index('\x20')
- jit_wb_cards_set_singlebyte = 0x20
+ jit_wb_cards_set = 32768
+ jit_wb_cards_set_byteofs = struct.pack("i", 32768).index('\x80')
+ jit_wb_cards_set_singlebyte = -0x80
jit_wb_card_page_shift = 7
def get_write_barrier_from_array_fn(self, cpu):
return funcbox.getint()
#
- for BoxIndexCls in [BoxInt, ConstInt]:
- for cond in [False, True]:
+ for BoxIndexCls in [BoxInt, ConstInt]*3:
+ for cond in [-1, 0, 1, 2]:
+ # cond=-1:GCFLAG_TRACK_YOUNG_PTRS, GCFLAG_CARDS_SET are not set
+ # cond=0: GCFLAG_CARDS_SET is never set
+ # cond=1: GCFLAG_CARDS_SET is not set, but the wb sets it
+ # cond=2: GCFLAG_CARDS_SET is already set
print
print '_'*79
print 'BoxIndexCls =', BoxIndexCls
- print 'JIT_WB_CARDS_SET =', cond
+ print 'testing cond =', cond
print
value = random.randrange(-sys.maxint, sys.maxint)
- value |= 4096
- if cond:
- value |= 8192
+ if cond >= 0:
+ value |= 4096
else:
- value &= ~8192
+ value &= ~4096
+ if cond == 2:
+ value |= 32768
+ else:
+ value &= ~32768
s = lltype.malloc(S_WITH_CARDS, immortal=True, zero=True)
s.data.tid = value
sgcref = rffi.cast(llmemory.GCREF, s.data)
@@ -2117,11 +2197,13 @@
self.execute_operation(rop.COND_CALL_GC_WB_ARRAY,
[BoxPtr(sgcref), box_index, BoxPtr(sgcref)],
'void', descr=WriteBarrierDescr())
- if cond:
+ if cond in [0, 1]:
+ assert record == [s.data]
+ else:
assert record == []
+ if cond in [1, 2]:
assert s.card6 == '\x02'
else:
- assert record == [(s.data, (9<<7) + 17, s.data)]
assert s.card6 == '\x00'
assert s.card0 == '\x00'
assert s.card1 == '\x00'
@@ -2130,6 +2212,9 @@
assert s.card4 == '\x00'
assert s.card5 == '\x00'
assert s.card7 == '\x00'
+ if cond == 1:
+ value |= 32768
+ assert s.data.tid == value
def test_force_operations_returning_void(self):
values = []
diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py
--- a/pypy/jit/backend/x86/assembler.py
+++ b/pypy/jit/backend/x86/assembler.py
@@ -10,7 +10,7 @@
from pypy.rlib.jit import AsmInfo
from pypy.jit.backend.model import CompiledLoopToken
from pypy.jit.backend.x86.regalloc import (RegAlloc, get_ebp_ofs, _get_scale,
- gpr_reg_mgr_cls, _valid_addressing_size)
+ gpr_reg_mgr_cls, xmm_reg_mgr_cls, _valid_addressing_size)
from pypy.jit.backend.x86.arch import (FRAME_FIXED_SIZE, FORCE_INDEX_OFS, WORD,
IS_X86_32, IS_X86_64)
@@ -83,6 +83,7 @@
self.float_const_abs_addr = 0
self.malloc_slowpath1 = 0
self.malloc_slowpath2 = 0
+ self.wb_slowpath = [0, 0, 0, 0]
self.memcpy_addr = 0
self.setup_failure_recovery()
self._debug = False
@@ -109,9 +110,13 @@
self.memcpy_addr = self.cpu.cast_ptr_to_int(support.memcpy_fn)
self._build_failure_recovery(False)
self._build_failure_recovery(True)
+ self._build_wb_slowpath(False)
+ self._build_wb_slowpath(True)
if self.cpu.supports_floats:
self._build_failure_recovery(False, withfloats=True)
self._build_failure_recovery(True, withfloats=True)
+ self._build_wb_slowpath(False, withfloats=True)
+ self._build_wb_slowpath(True, withfloats=True)
support.ensure_sse2_floats()
self._build_float_constants()
self._build_propagate_exception_path()
@@ -344,6 +349,82 @@
rawstart = mc.materialize(self.cpu.asmmemmgr, [])
self.stack_check_slowpath = rawstart
+ def _build_wb_slowpath(self, withcards, withfloats=False):
+ descr = self.cpu.gc_ll_descr.write_barrier_descr
+ if descr is None:
+ return
+ if not withcards:
+ func = descr.get_write_barrier_fn(self.cpu)
+ else:
+ if descr.jit_wb_cards_set == 0:
+ return
+ func = descr.get_write_barrier_from_array_fn(self.cpu)
+ if func == 0:
+ return
+ #
+ # This builds a helper function called from the slow path of
+ # write barriers. It must save all registers, and optionally
+ # all XMM registers. It takes a single argument just pushed
+ # on the stack even on X86_64. It must restore stack alignment
+ # accordingly.
+ mc = codebuf.MachineCodeBlockWrapper()
+ #
+ frame_size = (1 + # my argument, considered part of my frame
+ 1 + # my return address
+ len(gpr_reg_mgr_cls.save_around_call_regs))
+ if withfloats:
+ frame_size += 16 # X86_32: 16 words for 8 registers;
+ # X86_64: just 16 registers
+ if IS_X86_32:
+ frame_size += 1 # argument to pass to the call
+ #
+ # align to a multiple of 16 bytes
+ frame_size = (frame_size + (CALL_ALIGN-1)) & ~(CALL_ALIGN-1)
+ #
+ correct_esp_by = (frame_size - 2) * WORD
+ mc.SUB_ri(esp.value, correct_esp_by)
+ #
+ ofs = correct_esp_by
+ if withfloats:
+ for reg in xmm_reg_mgr_cls.save_around_call_regs:
+ ofs -= 8
+ mc.MOVSD_sx(ofs, reg.value)
+ for reg in gpr_reg_mgr_cls.save_around_call_regs:
+ ofs -= WORD
+ mc.MOV_sr(ofs, reg.value)
+ #
+ if IS_X86_32:
+ mc.MOV_rs(eax.value, (frame_size - 1) * WORD)
+ mc.MOV_sr(0, eax.value)
+ elif IS_X86_64:
+ mc.MOV_rs(edi.value, (frame_size - 1) * WORD)
+ mc.CALL(imm(func))
+ #
+ if withcards:
+ # A final TEST8 before the RET, for the caller. Careful to
+ # not follow this instruction with another one that changes
+ # the status of the CPU flags!
+ mc.MOV_rs(eax.value, (frame_size - 1) * WORD)
+ mc.TEST8(addr_add_const(eax, descr.jit_wb_if_flag_byteofs),
+ imm(-0x80))
+ #
+ ofs = correct_esp_by
+ if withfloats:
+ for reg in xmm_reg_mgr_cls.save_around_call_regs:
+ ofs -= 8
+ mc.MOVSD_xs(reg.value, ofs)
+ for reg in gpr_reg_mgr_cls.save_around_call_regs:
+ ofs -= WORD
+ mc.MOV_rs(reg.value, ofs)
+ #
+ # ADD esp, correct_esp_by --- but cannot use ADD, because
+ # of its effects on the CPU flags
+ mc.LEA_rs(esp.value, correct_esp_by)
+ mc.RET16_i(WORD)
+ #
+ rawstart = mc.materialize(self.cpu.asmmemmgr, [])
+ self.wb_slowpath[withcards + 2 * withfloats] = rawstart
+
@staticmethod
@rgc.no_collect
def _release_gil_asmgcc(css):
@@ -2324,102 +2405,83 @@
def genop_discard_cond_call_gc_wb(self, op, arglocs):
# Write code equivalent to write_barrier() in the GC: it checks
- # a flag in the object at arglocs[0], and if set, it calls the
- # function remember_young_pointer() from the GC. The arguments
- # to the call are in arglocs[:N]. The rest, arglocs[N:], contains
- # registers that need to be saved and restored across the call.
- # N is either 2 (regular write barrier) or 3 (array write barrier).
+ # a flag in the object at arglocs[0], and if set, it calls a
+ # helper piece of assembler. The latter saves registers as needed
+ # and call the function jit_remember_young_pointer() from the GC.
descr = op.getdescr()
if we_are_translated():
cls = self.cpu.gc_ll_descr.has_write_barrier_class()
assert cls is not None and isinstance(descr, cls)
#
opnum = op.getopnum()
- if opnum == rop.COND_CALL_GC_WB:
- N = 2
- func = descr.get_write_barrier_fn(self.cpu)
- card_marking = False
- elif opnum == rop.COND_CALL_GC_WB_ARRAY:
- N = 3
- func = descr.get_write_barrier_from_array_fn(self.cpu)
- assert func != 0
- card_marking = descr.jit_wb_cards_set != 0
- else:
- raise AssertionError(opnum)
+ card_marking = False
+ mask = descr.jit_wb_if_flag_singlebyte
+ if opnum == rop.COND_CALL_GC_WB_ARRAY and descr.jit_wb_cards_set != 0:
+ # assumptions the rest of the function depends on:
+ assert (descr.jit_wb_cards_set_byteofs ==
+ descr.jit_wb_if_flag_byteofs)
+ assert descr.jit_wb_cards_set_singlebyte == -0x80
+ card_marking = True
+ mask = descr.jit_wb_if_flag_singlebyte | -0x80
#
loc_base = arglocs[0]
self.mc.TEST8(addr_add_const(loc_base, descr.jit_wb_if_flag_byteofs),
- imm(descr.jit_wb_if_flag_singlebyte))
+ imm(mask))
self.mc.J_il8(rx86.Conditions['Z'], 0) # patched later
jz_location = self.mc.get_relative_pos()
# for cond_call_gc_wb_array, also add another fast path:
# if GCFLAG_CARDS_SET, then we can just set one bit and be done
if card_marking:
- self.mc.TEST8(addr_add_const(loc_base,
- descr.jit_wb_cards_set_byteofs),
- imm(descr.jit_wb_cards_set_singlebyte))
- self.mc.J_il8(rx86.Conditions['NZ'], 0) # patched later
- jnz_location = self.mc.get_relative_pos()
+ # GCFLAG_CARDS_SET is in this byte at 0x80, so this fact can
+ # been checked by the status flags of the previous TEST8
+ self.mc.J_il8(rx86.Conditions['S'], 0) # patched later
+ js_location = self.mc.get_relative_pos()
else:
- jnz_location = 0
+ js_location = 0
- # the following is supposed to be the slow path, so whenever possible
- # we choose the most compact encoding over the most efficient one.
- if IS_X86_32:
- limit = -1 # push all arglocs on the stack
- elif IS_X86_64:
- limit = N - 1 # push only arglocs[N:] on the stack
- for i in range(len(arglocs)-1, limit, -1):
- loc = arglocs[i]
- if isinstance(loc, RegLoc):
- self.mc.PUSH_r(loc.value)
- else:
- assert not IS_X86_64 # there should only be regs in arglocs[N:]
- self.mc.PUSH_i32(loc.getint())
- if IS_X86_64:
- # We clobber these registers to pass the arguments, but that's
- # okay, because consider_cond_call_gc_wb makes sure that any
- # caller-save registers with values in them are present in
- # arglocs[N:] too, so they are saved on the stack above and
- # restored below.
- if N == 2:
- callargs = [edi, esi]
- else:
- callargs = [edi, esi, edx]
- remap_frame_layout(self, arglocs[:N], callargs,
- X86_64_SCRATCH_REG)
+ # Write only a CALL to the helper prepared in advance, passing it as
+ # argument the address of the structure we are writing into
+ # (the first argument to COND_CALL_GC_WB).
+ helper_num = card_marking
+ if self._regalloc.xrm.reg_bindings:
+ helper_num += 2
+ if self.wb_slowpath[helper_num] == 0: # tests only
+ assert not we_are_translated()
+ self.cpu.gc_ll_descr.write_barrier_descr = descr
+ self._build_wb_slowpath(card_marking,
+ bool(self._regalloc.xrm.reg_bindings))
+ assert self.wb_slowpath[helper_num] != 0
#
- # misaligned stack in the call, but it's ok because the write barrier
- # is not going to call anything more. Also, this assumes that the
- # write barrier does not touch the xmm registers. (Slightly delicate
- # assumption, given that the write barrier can end up calling the
- # platform's malloc() from AddressStack.append(). XXX may need to
- # be done properly)
- self.mc.CALL(imm(func))
- if IS_X86_32:
- self.mc.ADD_ri(esp.value, N*WORD)
- for i in range(N, len(arglocs)):
- loc = arglocs[i]
- assert isinstance(loc, RegLoc)
- self.mc.POP_r(loc.value)
+ self.mc.PUSH(loc_base)
+ self.mc.CALL(imm(self.wb_slowpath[helper_num]))
- # if GCFLAG_CARDS_SET, then we can do the whole thing that would
- # be done in the CALL above with just four instructions, so here
- # is an inline copy of them
if card_marking:
- self.mc.JMP_l8(0) # jump to the exit, patched later
- jmp_location = self.mc.get_relative_pos()
- # patch the JNZ above
- offset = self.mc.get_relative_pos() - jnz_location
+ # The helper ends again with a check of the flag in the object.
+ # So here, we can simply write again a 'JNS', which will be
+ # taken if GCFLAG_CARDS_SET is still not set.
+ self.mc.J_il8(rx86.Conditions['NS'], 0) # patched later
+ jns_location = self.mc.get_relative_pos()
+ #
+ # patch the JS above
+ offset = self.mc.get_relative_pos() - js_location
assert 0 < offset <= 127
- self.mc.overwrite(jnz_location-1, chr(offset))
+ self.mc.overwrite(js_location-1, chr(offset))
#
+ # case GCFLAG_CARDS_SET: emit a few instructions to do
+ # directly the card flag setting
loc_index = arglocs[1]
if isinstance(loc_index, RegLoc):
- # choose a scratch register
- tmp1 = loc_index
- self.mc.PUSH_r(tmp1.value)
+ if IS_X86_64 and isinstance(loc_base, RegLoc):
+ # copy loc_index into r11
+ tmp1 = X86_64_SCRATCH_REG
+ self.mc.MOV_rr(tmp1.value, loc_index.value)
+ final_pop = False
+ else:
+ # must save the register loc_index before it is mutated
+ self.mc.PUSH_r(loc_index.value)
+ tmp1 = loc_index
+ final_pop = True
# SHR tmp, card_page_shift
self.mc.SHR_ri(tmp1.value, descr.jit_wb_card_page_shift)
# XOR tmp, -8
@@ -2427,7 +2489,9 @@
# BTS [loc_base], tmp
self.mc.BTS(addr_add_const(loc_base, 0), tmp1)
# done
- self.mc.POP_r(tmp1.value)
+ if final_pop:
+ self.mc.POP_r(loc_index.value)
+ #
elif isinstance(loc_index, ImmedLoc):
byte_index = loc_index.value >> descr.jit_wb_card_page_shift
byte_ofs = ~(byte_index >> 3)
@@ -2435,11 +2499,12 @@
self.mc.OR8(addr_add_const(loc_base, byte_ofs), imm(byte_val))
else:
raise AssertionError("index is neither RegLoc nor ImmedLoc")
- # patch the JMP above
- offset = self.mc.get_relative_pos() - jmp_location
+ #
+ # patch the JNS above
+ offset = self.mc.get_relative_pos() - jns_location
assert 0 < offset <= 127
- self.mc.overwrite(jmp_location-1, chr(offset))
- #
+ self.mc.overwrite(jns_location-1, chr(offset))
+
# patch the JZ above
offset = self.mc.get_relative_pos() - jz_location
assert 0 < offset <= 127
diff --git a/pypy/jit/backend/x86/regalloc.py b/pypy/jit/backend/x86/regalloc.py
--- a/pypy/jit/backend/x86/regalloc.py
+++ b/pypy/jit/backend/x86/regalloc.py
@@ -922,16 +922,6 @@
# or setarrayitem_gc. It avoids loading it twice from the memory.
arglocs = [self.rm.make_sure_var_in_reg(op.getarg(i), args)
for i in range(N)]
- # add eax, ecx and edx as extra "arguments" to ensure they are
- # saved and restored. Fish in self.rm to know which of these
- # registers really need to be saved (a bit of a hack). Moreover,
- # we don't save and restore any SSE register because the called
- # function, a GC write barrier, is known not to touch them.
- # See remember_young_pointer() in rpython/memory/gc/generation.py.
- for v, reg in self.rm.reg_bindings.items():
- if (reg in self.rm.save_around_call_regs
- and self.rm.stays_alive(v)):
- arglocs.append(reg)
self.PerformDiscard(op, arglocs)
self.rm.possibly_free_vars_for_op(op)
diff --git a/pypy/jit/backend/x86/rx86.py b/pypy/jit/backend/x86/rx86.py
--- a/pypy/jit/backend/x86/rx86.py
+++ b/pypy/jit/backend/x86/rx86.py
@@ -316,6 +316,13 @@
assert rexbyte == 0
return 0
+# REX prefixes: 'rex_w' generates a REX_W, forcing the instruction
+# to operate on 64-bit. 'rex_nw' doesn't, so the instruction operates
+# on 32-bit or less; the complete REX prefix is omitted if unnecessary.
+# 'rex_fw' is a special case which doesn't generate a REX_W but forces
+# the REX prefix in all cases. It is only useful on instructions which
+# have an 8-bit register argument, to force access to the "sil" or "dil"
+# registers (as opposed to "ah-dh").
rex_w = encode_rex, 0, (0x40 | REX_W), None # a REX.W prefix
rex_nw = encode_rex, 0, 0, None # an optional REX prefix
rex_fw = encode_rex, 0, 0x40, None # a forced REX prefix
@@ -496,9 +503,9 @@
AND8_rr = insn(rex_fw, '\x20', byte_register(1), byte_register(2,8), '\xC0')
OR8_rr = insn(rex_fw, '\x08', byte_register(1), byte_register(2,8), '\xC0')
- OR8_mi = insn(rex_fw, '\x80', orbyte(1<<3), mem_reg_plus_const(1),
+ OR8_mi = insn(rex_nw, '\x80', orbyte(1<<3), mem_reg_plus_const(1),
immediate(2, 'b'))
- OR8_ji = insn(rex_fw, '\x80', orbyte(1<<3), abs_, immediate(1),
+ OR8_ji = insn(rex_nw, '\x80', orbyte(1<<3), abs_, immediate(1),
immediate(2, 'b'))
NEG_r = insn(rex_w, '\xF7', register(1), '\xD8')
@@ -531,7 +538,13 @@
PUSH_r = insn(rex_nw, register(1), '\x50')
PUSH_b = insn(rex_nw, '\xFF', orbyte(6<<3), stack_bp(1))
+ PUSH_i8 = insn('\x6A', immediate(1, 'b'))
PUSH_i32 = insn('\x68', immediate(1, 'i'))
+ def PUSH_i(mc, immed):
+ if single_byte(immed):
+ mc.PUSH_i8(immed)
+ else:
+ mc.PUSH_i32(immed)
POP_r = insn(rex_nw, register(1), '\x58')
POP_b = insn(rex_nw, '\x8F', orbyte(0<<3), stack_bp(1))
diff --git a/pypy/jit/backend/x86/test/test_rx86.py b/pypy/jit/backend/x86/test/test_rx86.py
--- a/pypy/jit/backend/x86/test/test_rx86.py
+++ b/pypy/jit/backend/x86/test/test_rx86.py
@@ -183,7 +183,8 @@
def test_push32():
cb = CodeBuilder32
- assert_encodes_as(cb, 'PUSH_i32', (9,), '\x68\x09\x00\x00\x00')
+ assert_encodes_as(cb, 'PUSH_i', (0x10009,), '\x68\x09\x00\x01\x00')
+ assert_encodes_as(cb, 'PUSH_i', (9,), '\x6A\x09')
def test_sub_ji8():
cb = CodeBuilder32
diff --git a/pypy/jit/backend/x86/test/test_ztranslation.py b/pypy/jit/backend/x86/test/test_ztranslation.py
--- a/pypy/jit/backend/x86/test/test_ztranslation.py
+++ b/pypy/jit/backend/x86/test/test_ztranslation.py
@@ -69,7 +69,7 @@
#
from pypy.rpython.lltypesystem import lltype, rffi
from pypy.rlib.libffi import types, CDLL, ArgChain
- from pypy.rlib.test.test_libffi import get_libm_name
+ from pypy.rlib.test.test_clibffi import get_libm_name
libm_name = get_libm_name(sys.platform)
jitdriver2 = JitDriver(greens=[], reds = ['i', 'func', 'res', 'x'])
def libffi_stuff(i, j):
diff --git a/pypy/jit/backend/x86/tool/viewcode.py b/pypy/jit/backend/x86/tool/viewcode.py
--- a/pypy/jit/backend/x86/tool/viewcode.py
+++ b/pypy/jit/backend/x86/tool/viewcode.py
@@ -253,7 +253,7 @@
self.logentries[addr] = pieces[3]
elif line.startswith('SYS_EXECUTABLE '):
filename = line[len('SYS_EXECUTABLE '):].strip()
- if filename != self.executable_name:
+ if filename != self.executable_name and filename != '??':
self.symbols.update(load_symbols(filename))
self.executable_name = filename
diff --git a/pypy/jit/codewriter/policy.py b/pypy/jit/codewriter/policy.py
--- a/pypy/jit/codewriter/policy.py
+++ b/pypy/jit/codewriter/policy.py
@@ -48,8 +48,6 @@
mod = func.__module__ or '?'
if mod.startswith('pypy.rpython.module.'):
return True
- if mod == 'pypy.translator.goal.nanos': # more helpers
- return True
return False
def look_inside_graph(self, graph):
diff --git a/pypy/jit/metainterp/optimizeopt/fficall.py b/pypy/jit/metainterp/optimizeopt/fficall.py
--- a/pypy/jit/metainterp/optimizeopt/fficall.py
+++ b/pypy/jit/metainterp/optimizeopt/fficall.py
@@ -133,7 +133,7 @@
optimize_CALL_MAY_FORCE = optimize_CALL
def optimize_FORCE_TOKEN(self, op):
- # The handling of force_token needs a bit of exaplanation.
+ # The handling of force_token needs a bit of explanation.
# The original trace which is getting optimized looks like this:
# i1 = force_token()
# setfield_gc(p0, i1, ...)
diff --git a/pypy/jit/tl/pypyjit.py b/pypy/jit/tl/pypyjit.py
--- a/pypy/jit/tl/pypyjit.py
+++ b/pypy/jit/tl/pypyjit.py
@@ -43,6 +43,7 @@
config.objspace.usemodules._lsprof = False
#
config.objspace.usemodules._ffi = True
+#config.objspace.usemodules.cppyy = True
config.objspace.usemodules.micronumpy = False
#
set_pypy_opt_level(config, level='jit')
diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py
--- a/pypy/module/__pypy__/__init__.py
+++ b/pypy/module/__pypy__/__init__.py
@@ -3,7 +3,6 @@
from pypy.interpreter.mixedmodule import MixedModule
from pypy.module.imp.importing import get_pyc_magic
-
class BuildersModule(MixedModule):
appleveldefs = {}
@@ -43,7 +42,10 @@
'lookup_special' : 'interp_magic.lookup_special',
'do_what_I_mean' : 'interp_magic.do_what_I_mean',
'list_strategy' : 'interp_magic.list_strategy',
+ 'validate_fd' : 'interp_magic.validate_fd',
}
+ if sys.platform == 'win32':
+ interpleveldefs['get_console_cp'] = 'interp_magic.get_console_cp'
submodules = {
"builders": BuildersModule,
diff --git a/pypy/module/__pypy__/interp_magic.py b/pypy/module/__pypy__/interp_magic.py
--- a/pypy/module/__pypy__/interp_magic.py
+++ b/pypy/module/__pypy__/interp_magic.py
@@ -1,9 +1,10 @@
from pypy.interpreter.baseobjspace import ObjSpace, W_Root
-from pypy.interpreter.error import OperationError
+from pypy.interpreter.error import OperationError, wrap_oserror
from pypy.interpreter.gateway import unwrap_spec
from pypy.rlib.objectmodel import we_are_translated
from pypy.objspace.std.typeobject import MethodCache
from pypy.objspace.std.mapdict import IndexCache
+from pypy.rlib import rposix
def internal_repr(space, w_object):
return space.wrap('%r' % (w_object,))
@@ -80,3 +81,17 @@
else:
w_msg = space.wrap("Can only get the list strategy of a list")
raise OperationError(space.w_TypeError, w_msg)
+
+ at unwrap_spec(fd='c_int')
+def validate_fd(space, fd):
+ try:
+ rposix.validate_fd(fd)
+ except OSError, e:
+ raise wrap_oserror(space, e)
+
+def get_console_cp(space):
+ from pypy.rlib import rwin32 # Windows only
+ return space.newtuple([
+ space.wrap('cp%d' % rwin32.GetConsoleCP()),
+ space.wrap('cp%d' % rwin32.GetConsoleOutputCP()),
+ ])
diff --git a/pypy/module/_ffi/__init__.py b/pypy/module/_ffi/__init__.py
--- a/pypy/module/_ffi/__init__.py
+++ b/pypy/module/_ffi/__init__.py
@@ -1,4 +1,5 @@
from pypy.interpreter.mixedmodule import MixedModule
+import os
class Module(MixedModule):
@@ -10,7 +11,8 @@
'_StructDescr': 'interp_struct.W__StructDescr',
'Field': 'interp_struct.W_Field',
}
-
+ if os.name == 'nt':
+ interpleveldefs['WinDLL'] = 'interp_funcptr.W_WinDLL'
appleveldefs = {
'Structure': 'app_struct.Structure',
}
diff --git a/pypy/module/_ffi/interp_funcptr.py b/pypy/module/_ffi/interp_funcptr.py
--- a/pypy/module/_ffi/interp_funcptr.py
+++ b/pypy/module/_ffi/interp_funcptr.py
@@ -9,11 +9,57 @@
#
from pypy.rlib import jit
from pypy.rlib import libffi
+from pypy.rlib.clibffi import get_libc_name, StackCheckError
from pypy.rlib.rdynload import DLOpenError
from pypy.rlib.rarithmetic import intmask, r_uint
from pypy.rlib.objectmodel import we_are_translated
from pypy.module._ffi.type_converter import FromAppLevelConverter, ToAppLevelConverter
+import os
+if os.name == 'nt':
+ def _getfunc(space, CDLL, w_name, w_argtypes, w_restype):
+ argtypes_w, argtypes, w_restype, restype = unpack_argtypes(
+ space, w_argtypes, w_restype)
+ if space.isinstance_w(w_name, space.w_str):
+ name = space.str_w(w_name)
+ try:
+ func = CDLL.cdll.getpointer(name, argtypes, restype,
+ flags = CDLL.flags)
+ except KeyError:
+ raise operationerrfmt(
+ space.w_AttributeError,
+ "No symbol %s found in library %s", name, CDLL.name)
+
+ return W_FuncPtr(func, argtypes_w, w_restype)
+ elif space.isinstance_w(w_name, space.w_int):
+ ordinal = space.int_w(w_name)
+ try:
+ func = CDLL.cdll.getpointer_by_ordinal(
+ ordinal, argtypes, restype,
+ flags = CDLL.flags)
+ except KeyError:
+ raise operationerrfmt(
+ space.w_AttributeError,
+ "No ordinal %d found in library %s", ordinal, CDLL.name)
+ return W_FuncPtr(func, argtypes_w, w_restype)
+ else:
+ raise OperationError(space.w_TypeError, space.wrap(
+ 'function name must be a string or integer'))
+else:
+ @unwrap_spec(name=str)
+ def _getfunc(space, CDLL, w_name, w_argtypes, w_restype):
+ name = space.str_w(w_name)
+ argtypes_w, argtypes, w_restype, restype = unpack_argtypes(
+ space, w_argtypes, w_restype)
+ try:
+ func = CDLL.cdll.getpointer(name, argtypes, restype,
+ flags = CDLL.flags)
+ except KeyError:
+ raise operationerrfmt(
+ space.w_AttributeError,
+ "No symbol %s found in library %s", name, CDLL.name)
+
+ return W_FuncPtr(func, argtypes_w, w_restype)
def unwrap_ffitype(space, w_argtype, allow_void=False):
res = w_argtype.get_ffitype()
@@ -59,7 +105,10 @@
self = jit.promote(self)
argchain = self.build_argchain(space, args_w)
func_caller = CallFunctionConverter(space, self.func, argchain)
- return func_caller.do_and_wrap(self.w_restype)
+ try:
+ return func_caller.do_and_wrap(self.w_restype)
+ except StackCheckError, e:
+ raise OperationError(space.w_ValueError, space.wrap(e.message))
#return self._do_call(space, argchain)
def free_temp_buffers(self, space):
@@ -230,13 +279,14 @@
restype = unwrap_ffitype(space, w_restype, allow_void=True)
return argtypes_w, argtypes, w_restype, restype
- at unwrap_spec(addr=r_uint, name=str)
-def descr_fromaddr(space, w_cls, addr, name, w_argtypes, w_restype):
+ at unwrap_spec(addr=r_uint, name=str, flags=int)
+def descr_fromaddr(space, w_cls, addr, name, w_argtypes,
+ w_restype, flags=libffi.FUNCFLAG_CDECL):
argtypes_w, argtypes, w_restype, restype = unpack_argtypes(space,
w_argtypes,
w_restype)
addr = rffi.cast(rffi.VOIDP, addr)
- func = libffi.Func(name, argtypes, restype, addr)
+ func = libffi.Func(name, argtypes, restype, addr, flags)
return W_FuncPtr(func, argtypes_w, w_restype)
@@ -254,6 +304,7 @@
class W_CDLL(Wrappable):
def __init__(self, space, name, mode):
+ self.flags = libffi.FUNCFLAG_CDECL
self.space = space
if name is None:
self.name = "<None>"
@@ -265,18 +316,8 @@
raise operationerrfmt(space.w_OSError, '%s: %s', self.name,
e.msg or 'unspecified error')
- @unwrap_spec(name=str)
- def getfunc(self, space, name, w_argtypes, w_restype):
- argtypes_w, argtypes, w_restype, restype = unpack_argtypes(space,
- w_argtypes,
- w_restype)
- try:
- func = self.cdll.getpointer(name, argtypes, restype)
- except KeyError:
- raise operationerrfmt(space.w_AttributeError,
- "No symbol %s found in library %s", name, self.name)
-
- return W_FuncPtr(func, argtypes_w, w_restype)
+ def getfunc(self, space, w_name, w_argtypes, w_restype):
+ return _getfunc(space, self, w_name, w_argtypes, w_restype)
@unwrap_spec(name=str)
def getaddressindll(self, space, name):
@@ -284,8 +325,9 @@
address_as_uint = rffi.cast(lltype.Unsigned,
self.cdll.getaddressindll(name))
except KeyError:
- raise operationerrfmt(space.w_ValueError,
- "No symbol %s found in library %s", name, self.name)
+ raise operationerrfmt(
+ space.w_ValueError,
+ "No symbol %s found in library %s", name, self.name)
return space.wrap(address_as_uint)
@unwrap_spec(name='str_or_None', mode=int)
@@ -300,10 +342,26 @@
getaddressindll = interp2app(W_CDLL.getaddressindll),
)
+class W_WinDLL(W_CDLL):
+ def __init__(self, space, name, mode):
+ W_CDLL.__init__(self, space, name, mode)
+ self.flags = libffi.FUNCFLAG_STDCALL
+
+ at unwrap_spec(name='str_or_None', mode=int)
+def descr_new_windll(space, w_type, name, mode=-1):
+ return space.wrap(W_WinDLL(space, name, mode))
+
+
+W_WinDLL.typedef = TypeDef(
+ '_ffi.WinDLL',
+ __new__ = interp2app(descr_new_windll),
+ getfunc = interp2app(W_WinDLL.getfunc),
+ getaddressindll = interp2app(W_WinDLL.getaddressindll),
+ )
+
# ========================================================================
def get_libc(space):
- from pypy.rlib.clibffi import get_libc_name
try:
return space.wrap(W_CDLL(space, get_libc_name(), -1))
except OSError, e:
diff --git a/pypy/module/_ffi/interp_struct.py b/pypy/module/_ffi/interp_struct.py
--- a/pypy/module/_ffi/interp_struct.py
+++ b/pypy/module/_ffi/interp_struct.py
@@ -56,8 +56,7 @@
class W__StructDescr(Wrappable):
- def __init__(self, space, name):
- self.space = space
+ def __init__(self, name):
self.w_ffitype = W_FFIType('struct %s' % name, clibffi.FFI_TYPE_NULL,
w_structdescr=self)
self.fields_w = None
@@ -69,7 +68,6 @@
raise operationerrfmt(space.w_ValueError,
"%s's fields has already been defined",
self.w_ffitype.name)
- space = self.space
fields_w = space.fixedview(w_fields)
# note that the fields_w returned by compute_size_and_alignement has a
# different annotation than the original: list(W_Root) vs list(W_Field)
@@ -104,11 +102,11 @@
return W__StructInstance(self, allocate=False, autofree=True, rawmem=rawmem)
@jit.elidable_promote('0')
- def get_type_and_offset_for_field(self, name):
+ def get_type_and_offset_for_field(self, space, name):
try:
w_field = self.name2w_field[name]
except KeyError:
- raise operationerrfmt(self.space.w_AttributeError, '%s', name)
+ raise operationerrfmt(space.w_AttributeError, '%s', name)
return w_field.w_ffitype, w_field.offset
@@ -116,7 +114,7 @@
@unwrap_spec(name=str)
def descr_new_structdescr(space, w_type, name, w_fields=None):
- descr = W__StructDescr(space, name)
+ descr = W__StructDescr(name)
if w_fields is not space.w_None:
descr.define_fields(space, w_fields)
return descr
@@ -185,13 +183,15 @@
@unwrap_spec(name=str)
def getfield(self, space, name):
- w_ffitype, offset = self.structdescr.get_type_and_offset_for_field(name)
+ w_ffitype, offset = self.structdescr.get_type_and_offset_for_field(
+ space, name)
field_getter = GetFieldConverter(space, self.rawmem, offset)
return field_getter.do_and_wrap(w_ffitype)
@unwrap_spec(name=str)
def setfield(self, space, name, w_value):
- w_ffitype, offset = self.structdescr.get_type_and_offset_for_field(name)
+ w_ffitype, offset = self.structdescr.get_type_and_offset_for_field(
+ space, name)
field_setter = SetFieldConverter(space, self.rawmem, offset)
field_setter.unwrap_and_do(w_ffitype, w_value)
diff --git a/pypy/module/_ffi/test/test_funcptr.py b/pypy/module/_ffi/test/test_funcptr.py
--- a/pypy/module/_ffi/test/test_funcptr.py
+++ b/pypy/module/_ffi/test/test_funcptr.py
@@ -1,11 +1,11 @@
from pypy.conftest import gettestobjspace
-from pypy.translator.platform import platform
-from pypy.translator.tool.cbuild import ExternalCompilationInfo
-from pypy.module._rawffi.interp_rawffi import TYPEMAP
-from pypy.module._rawffi.tracker import Tracker
-from pypy.translator.platform import platform
+from pypy.rpython.lltypesystem import rffi
+from pypy.rlib.clibffi import get_libc_name
+from pypy.rlib.libffi import types
+from pypy.rlib.libffi import CDLL
+from pypy.rlib.test.test_clibffi import get_libm_name
-import os, sys, py
+import sys, py
class BaseAppTestFFI(object):
@@ -37,9 +37,6 @@
return str(platform.compile([c_file], eci, 'x', standalone=False))
def setup_class(cls):
- from pypy.rpython.lltypesystem import rffi
- from pypy.rlib.libffi import get_libc_name, CDLL, types
- from pypy.rlib.test.test_libffi import get_libm_name
space = gettestobjspace(usemodules=('_ffi', '_rawffi'))
cls.space = space
cls.w_iswin32 = space.wrap(sys.platform == 'win32')
@@ -96,7 +93,7 @@
def test_getaddressindll(self):
import sys
- from _ffi import CDLL, types
+ from _ffi import CDLL
libm = CDLL(self.libm_name)
pow_addr = libm.getaddressindll('pow')
fff = sys.maxint*2-1
@@ -105,7 +102,6 @@
assert pow_addr == self.pow_addr & fff
def test_func_fromaddr(self):
- import sys
from _ffi import CDLL, types, FuncPtr
libm = CDLL(self.libm_name)
pow_addr = libm.getaddressindll('pow')
@@ -338,6 +334,22 @@
assert sum_xy(100, 40) == 140
assert sum_xy(200, 60) == 260 % 256
+ def test_unsigned_int_args(self):
+ r"""
+ DLLEXPORT unsigned int sum_xy_ui(unsigned int x, unsigned int y)
+ {
+ return x+y;
+ }
+ """
+ import sys
+ from _ffi import CDLL, types
+ maxint32 = 2147483647
+ libfoo = CDLL(self.libfoo_name)
+ sum_xy = libfoo.getfunc('sum_xy_ui', [types.uint, types.uint],
+ types.uint)
+ assert sum_xy(maxint32, 1) == maxint32+1
+ assert sum_xy(maxint32, maxint32+2) == 0
+
def test_signed_byte_args(self):
"""
DLLEXPORT signed char sum_xy_sb(signed char x, signed char y)
@@ -553,3 +565,79 @@
skip("unix specific")
libnone = CDLL(None)
raises(AttributeError, "libnone.getfunc('I_do_not_exist', [], types.void)")
+
+ def test_calling_convention1(self):
+ if not self.iswin32:
+ skip("windows specific")
+ from _ffi import WinDLL, types
+ libm = WinDLL(self.libm_name)
+ pow = libm.getfunc('pow', [types.double, types.double], types.double)
+ try:
+ pow(2, 3)
+ except ValueError, e:
+ assert e.message.startswith('Procedure called with')
+ else:
+ assert 0, 'test must assert, wrong calling convention'
+
+ def test_calling_convention2(self):
+ if not self.iswin32:
+ skip("windows specific")
+ from _ffi import WinDLL, types
+ kernel = WinDLL('Kernel32.dll')
+ sleep = kernel.getfunc('Sleep', [types.uint], types.void)
+ sleep(10)
+
+ def test_calling_convention3(self):
+ if not self.iswin32:
+ skip("windows specific")
+ from _ffi import CDLL, types
+ wrong_kernel = CDLL('Kernel32.dll')
+ wrong_sleep = wrong_kernel.getfunc('Sleep', [types.uint], types.void)
+ try:
+ wrong_sleep(10)
+ except ValueError, e:
+ assert e.message.startswith('Procedure called with')
+ else:
+ assert 0, 'test must assert, wrong calling convention'
+
+ def test_func_fromaddr2(self):
+ if not self.iswin32:
+ skip("windows specific")
+ from _ffi import CDLL, types, FuncPtr
+ from _rawffi import FUNCFLAG_STDCALL
+ libm = CDLL(self.libm_name)
+ pow_addr = libm.getaddressindll('pow')
+ wrong_pow = FuncPtr.fromaddr(pow_addr, 'pow',
+ [types.double, types.double], types.double, FUNCFLAG_STDCALL)
+ try:
+ wrong_pow(2, 3) == 8
+ except ValueError, e:
+ assert e.message.startswith('Procedure called with')
+ else:
+ assert 0, 'test must assert, wrong calling convention'
+
+ def test_func_fromaddr3(self):
+ if not self.iswin32:
+ skip("windows specific")
+ from _ffi import WinDLL, types, FuncPtr
+ from _rawffi import FUNCFLAG_STDCALL
+ kernel = WinDLL('Kernel32.dll')
+ sleep_addr = kernel.getaddressindll('Sleep')
+ sleep = FuncPtr.fromaddr(sleep_addr, 'sleep', [types.uint],
+ types.void, FUNCFLAG_STDCALL)
+ sleep(10)
+
+ def test_by_ordinal(self):
+ """
+ int DLLEXPORT AAA_first_ordinal_function()
+ {
+ return 42;
+ }
+ """
+ if not self.iswin32:
+ skip("windows specific")
+ from _ffi import CDLL, types
+ libfoo = CDLL(self.libfoo_name)
+ f_name = libfoo.getfunc('AAA_first_ordinal_function', [], types.sint)
+ f_ordinal = libfoo.getfunc(1, [], types.sint)
+ assert f_name.getaddr() == f_ordinal.getaddr()
diff --git a/pypy/module/_ffi/test/test_struct.py b/pypy/module/_ffi/test/test_struct.py
--- a/pypy/module/_ffi/test/test_struct.py
+++ b/pypy/module/_ffi/test/test_struct.py
@@ -1,5 +1,5 @@
import sys
-from pypy.conftest import gettestobjspace
+from pypy.conftest import gettestobjspace, option
from pypy.module._ffi.test.test_funcptr import BaseAppTestFFI
from pypy.module._ffi.interp_struct import compute_size_and_alignement, W_Field
from pypy.module._ffi.interp_ffitype import app_types, W_FFIType
@@ -62,6 +62,7 @@
dummy_type.c_alignment = rffi.cast(rffi.USHORT, 0)
dummy_type.c_type = rffi.cast(rffi.USHORT, 0)
cls.w_dummy_type = W_FFIType('dummy', dummy_type)
+ cls.w_runappdirect = cls.space.wrap(option.runappdirect)
def test__StructDescr(self):
from _ffi import _StructDescr, Field, types
@@ -99,6 +100,8 @@
raises(AttributeError, "struct.setfield('missing', 42)")
def test_unknown_type(self):
+ if self.runappdirect:
+ skip('cannot use self.dummy_type with -A')
from _ffi import _StructDescr, Field
fields = [
Field('x', self.dummy_type),
diff --git a/pypy/module/_ffi/test/test_type_converter.py b/pypy/module/_ffi/test/test_type_converter.py
--- a/pypy/module/_ffi/test/test_type_converter.py
+++ b/pypy/module/_ffi/test/test_type_converter.py
@@ -126,3 +126,46 @@
# then, try to pass explicit pointers
self.check(app_types.char_p, self.space.wrap(42), 42)
self.check(app_types.unichar_p, self.space.wrap(42), 42)
+
+
+
+class DummyToAppLevelConverter(ToAppLevelConverter):
+
+ def get_all(self, w_ffitype):
+ return self.val
+
+ get_signed = get_all
+ get_unsigned = get_all
+ get_pointer = get_all
+ get_char = get_all
+ get_unichar = get_all
+ get_longlong = get_all
+ get_char_p = get_all
+ get_unichar_p = get_all
+ get_float = get_all
+ get_singlefloat = get_all
+ get_unsigned_which_fits_into_a_signed = get_all
+
+ def convert(self, w_ffitype, val):
+ self.val = val
+ return self.do_and_wrap(w_ffitype)
+
+
+class TestFromAppLevel(object):
+
+ def setup_class(cls):
+ cls.space = gettestobjspace(usemodules=('_ffi',))
+ converter = DummyToAppLevelConverter(cls.space)
+ cls.from_app_level = staticmethod(converter.convert)
+
+ def check(self, w_ffitype, val, w_expected):
+ w_v = self.from_app_level(w_ffitype, val)
+ assert self.space.eq_w(w_v, w_expected)
+
+ def test_int(self):
+ self.check(app_types.sint, 42, self.space.wrap(42))
+ self.check(app_types.sint, -sys.maxint-1, self.space.wrap(-sys.maxint-1))
+
+ def test_uint(self):
+ self.check(app_types.uint, 42, self.space.wrap(42))
+ self.check(app_types.uint, r_uint(sys.maxint+1), self.space.wrap(sys.maxint+1))
diff --git a/pypy/module/_ffi/test/test_ztranslation.py b/pypy/module/_ffi/test/test_ztranslation.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_ffi/test/test_ztranslation.py
@@ -0,0 +1,4 @@
+from pypy.objspace.fake.checkmodule import checkmodule
+
+def test__ffi_translates():
+ checkmodule('_ffi', '_rawffi')
diff --git a/pypy/module/_ffi/type_converter.py b/pypy/module/_ffi/type_converter.py
--- a/pypy/module/_ffi/type_converter.py
+++ b/pypy/module/_ffi/type_converter.py
@@ -205,7 +205,9 @@
elif w_ffitype.is_signed():
intval = self.get_signed(w_ffitype)
return space.wrap(intval)
- elif w_ffitype is app_types.ulong or w_ffitype is app_types.ulonglong:
+ elif (w_ffitype is app_types.ulonglong or
+ w_ffitype is app_types.ulong or (libffi.IS_32_BIT and
+ w_ffitype is app_types.uint)):
# Note that we the second check (for ulonglong) is meaningful only
# on 64 bit, because on 32 bit the ulonglong case would have been
# handled by the is_longlong() branch above. On 64 bit, ulonglong
diff --git a/pypy/module/_minimal_curses/fficurses.py b/pypy/module/_minimal_curses/fficurses.py
--- a/pypy/module/_minimal_curses/fficurses.py
+++ b/pypy/module/_minimal_curses/fficurses.py
@@ -8,11 +8,20 @@
from pypy.rpython.extfunc import register_external
from pypy.module._minimal_curses import interp_curses
from pypy.translator.tool.cbuild import ExternalCompilationInfo
+from sys import platform
-eci = ExternalCompilationInfo(
- includes = ['curses.h', 'term.h'],
- libraries = ['curses'],
-)
+_CYGWIN = platform == 'cygwin'
+
+if _CYGWIN:
+ eci = ExternalCompilationInfo(
+ includes = ['ncurses/curses.h', 'ncurses/term.h'],
+ libraries = ['curses'],
+ )
+else:
+ eci = ExternalCompilationInfo(
+ includes = ['curses.h', 'term.h'],
+ libraries = ['curses'],
+ )
rffi_platform.verify_eci(eci)
diff --git a/pypy/module/_socket/test/test_sock_app.py b/pypy/module/_socket/test/test_sock_app.py
--- a/pypy/module/_socket/test/test_sock_app.py
+++ b/pypy/module/_socket/test/test_sock_app.py
@@ -611,14 +611,19 @@
buf = t.recv(1)
assert buf == '?'
# test send() timeout
+ count = 0
try:
while 1:
- cli.send('foobar' * 70)
+ count += cli.send('foobar' * 70)
except timeout:
pass
- # test sendall() timeout, be sure to send data larger than the
- # socket buffer
- raises(timeout, cli.sendall, 'foobar' * 7000)
+ t.recv(count)
+ # test sendall() timeout
+ try:
+ while 1:
+ cli.sendall('foobar' * 70)
+ except timeout:
+ pass
# done
cli.close()
t.close()
diff --git a/pypy/module/_ssl/__init__.py b/pypy/module/_ssl/__init__.py
--- a/pypy/module/_ssl/__init__.py
+++ b/pypy/module/_ssl/__init__.py
@@ -31,5 +31,6 @@
def startup(self, space):
from pypy.rlib.ropenssl import init_ssl
init_ssl()
- from pypy.module._ssl.interp_ssl import setup_ssl_threads
- setup_ssl_threads()
+ if space.config.objspace.usemodules.thread:
+ from pypy.module._ssl.thread_lock import setup_ssl_threads
+ setup_ssl_threads()
diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py
--- a/pypy/module/_ssl/interp_ssl.py
+++ b/pypy/module/_ssl/interp_ssl.py
@@ -789,7 +789,11 @@
def _ssl_seterror(space, ss, ret):
assert ret <= 0
- if ss and ss.ssl:
+ if ss is None:
+ errval = libssl_ERR_peek_last_error()
+ errstr = rffi.charp2str(libssl_ERR_error_string(errval, None))
+ return ssl_error(space, errstr, errval)
+ elif ss.ssl:
err = libssl_SSL_get_error(ss.ssl, ret)
else:
err = SSL_ERROR_SSL
@@ -880,38 +884,3 @@
libssl_X509_free(x)
finally:
libssl_BIO_free(cert)
-
-# this function is needed to perform locking on shared data
-# structures. (Note that OpenSSL uses a number of global data
-# structures that will be implicitly shared whenever multiple threads
-# use OpenSSL.) Multi-threaded applications will crash at random if
-# it is not set.
-#
-# locking_function() must be able to handle up to CRYPTO_num_locks()
-# different mutex locks. It sets the n-th lock if mode & CRYPTO_LOCK, and
-# releases it otherwise.
-#
-# filename and line are the file number of the function setting the
-# lock. They can be useful for debugging.
-_ssl_locks = []
-
-def _ssl_thread_locking_function(mode, n, filename, line):
- n = intmask(n)
- if n < 0 or n >= len(_ssl_locks):
- return
-
- if intmask(mode) & CRYPTO_LOCK:
- _ssl_locks[n].acquire(True)
- else:
- _ssl_locks[n].release()
-
-def _ssl_thread_id_function():
- from pypy.module.thread import ll_thread
- return rffi.cast(rffi.LONG, ll_thread.get_ident())
-
-def setup_ssl_threads():
- from pypy.module.thread import ll_thread
- for i in range(libssl_CRYPTO_num_locks()):
- _ssl_locks.append(ll_thread.allocate_lock())
- libssl_CRYPTO_set_locking_callback(_ssl_thread_locking_function)
- libssl_CRYPTO_set_id_callback(_ssl_thread_id_function)
diff --git a/pypy/module/_ssl/test/test_ztranslation.py b/pypy/module/_ssl/test/test_ztranslation.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_ssl/test/test_ztranslation.py
@@ -0,0 +1,4 @@
+from pypy.objspace.fake.checkmodule import checkmodule
+
+def test__ffi_translates():
+ checkmodule('_ssl')
diff --git a/pypy/module/_ssl/thread_lock.py b/pypy/module/_ssl/thread_lock.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_ssl/thread_lock.py
@@ -0,0 +1,80 @@
+from pypy.rlib.ropenssl import *
+from pypy.rpython.lltypesystem import lltype, rffi
+from pypy.translator.tool.cbuild import ExternalCompilationInfo
+
+# CRYPTO_set_locking_callback:
+#
+# this function is needed to perform locking on shared data
+# structures. (Note that OpenSSL uses a number of global data
+# structures that will be implicitly shared whenever multiple threads
+# use OpenSSL.) Multi-threaded applications will crash at random if
+# it is not set.
+#
+# locking_function() must be able to handle up to CRYPTO_num_locks()
+# different mutex locks. It sets the n-th lock if mode & CRYPTO_LOCK, and
+# releases it otherwise.
+#
+# filename and line are the file number of the function setting the
+# lock. They can be useful for debugging.
+
+
+# This logic is moved to C code so that the callbacks can be invoked
+# without caring about the GIL.
+
+separate_module_source = """
+
+#include <openssl/crypto.h>
+
+static unsigned int _ssl_locks_count = 0;
+static struct RPyOpaque_ThreadLock *_ssl_locks;
+
+static unsigned long _ssl_thread_id_function(void) {
+ return RPyThreadGetIdent();
+}
+
+static void _ssl_thread_locking_function(int mode, int n, const char *file,
+ int line) {
+ if ((_ssl_locks == NULL) ||
+ (n < 0) || ((unsigned)n >= _ssl_locks_count))
+ return;
+
+ if (mode & CRYPTO_LOCK) {
+ RPyThreadAcquireLock(_ssl_locks + n, 1);
+ } else {
+ RPyThreadReleaseLock(_ssl_locks + n);
+ }
+}
+
+int _PyPy_SSL_SetupThreads(void)
+{
+ unsigned int i;
+ _ssl_locks_count = CRYPTO_num_locks();
+ _ssl_locks = calloc(_ssl_locks_count, sizeof(struct RPyOpaque_ThreadLock));
+ if (_ssl_locks == NULL)
+ return 0;
+ for (i=0; i<_ssl_locks_count; i++) {
+ if (RPyThreadLockInit(_ssl_locks + i) == 0)
+ return 0;
+ }
+ CRYPTO_set_locking_callback(_ssl_thread_locking_function);
+ CRYPTO_set_id_callback(_ssl_thread_id_function);
+ return 1;
+}
+"""
+
+
+eci = ExternalCompilationInfo(
+ separate_module_sources=[separate_module_source],
+ post_include_bits=[
+ "int _PyPy_SSL_SetupThreads(void);"],
+ export_symbols=['_PyPy_SSL_SetupThreads'],
+)
+
+_PyPy_SSL_SetupThreads = rffi.llexternal('_PyPy_SSL_SetupThreads',
+ [], rffi.INT,
+ compilation_info=eci)
+
+def setup_ssl_threads():
+ result = _PyPy_SSL_SetupThreads()
+ if rffi.cast(lltype.Signed, result) == 0:
+ raise MemoryError
diff --git a/pypy/module/array/interp_array.py b/pypy/module/array/interp_array.py
--- a/pypy/module/array/interp_array.py
+++ b/pypy/module/array/interp_array.py
@@ -164,6 +164,8 @@
data[index] = char
array._charbuf_stop()
+ def get_raw_address(self):
+ return self.array._charbuf_start()
def make_array(mytype):
W_ArrayBase = globals()['W_ArrayBase']
diff --git a/pypy/module/cStringIO/interp_stringio.py b/pypy/module/cStringIO/interp_stringio.py
--- a/pypy/module/cStringIO/interp_stringio.py
+++ b/pypy/module/cStringIO/interp_stringio.py
@@ -221,7 +221,8 @@
}
W_InputType.typedef = TypeDef(
- "cStringIO.StringI",
+ "StringI",
+ __module__ = "cStringIO",
__doc__ = "Simple type for treating strings as input file streams",
closed = GetSetProperty(descr_closed, cls=W_InputType),
softspace = GetSetProperty(descr_softspace,
@@ -232,7 +233,8 @@
)
W_OutputType.typedef = TypeDef(
- "cStringIO.StringO",
+ "StringO",
+ __module__ = "cStringIO",
__doc__ = "Simple type for output to strings.",
truncate = interp2app(W_OutputType.descr_truncate),
write = interp2app(W_OutputType.descr_write),
diff --git a/pypy/module/cppyy/__init__.py b/pypy/module/cppyy/__init__.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/__init__.py
@@ -0,0 +1,22 @@
+from pypy.interpreter.mixedmodule import MixedModule
+
+class Module(MixedModule):
+ """ """
+
+ interpleveldefs = {
+ '_load_dictionary' : 'interp_cppyy.load_dictionary',
+ '_resolve_name' : 'interp_cppyy.resolve_name',
+ '_scope_byname' : 'interp_cppyy.scope_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',
+ }
+
+ appleveldefs = {
+ 'gbl' : 'pythonify.gbl',
+ 'load_reflection_info' : 'pythonify.load_reflection_info',
+ 'add_pythonization' : 'pythonify.add_pythonization',
+ }
diff --git a/pypy/module/cppyy/bench/Makefile b/pypy/module/cppyy/bench/Makefile
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/bench/Makefile
@@ -0,0 +1,29 @@
+all: bench02Dict_reflex.so
+
+ROOTSYS := ${ROOTSYS}
+
+ifeq ($(ROOTSYS),)
+ genreflex=genreflex
+ cppflags=
+else
+ genreflex=$(ROOTSYS)/bin/genreflex
+ cppflags=-I$(ROOTSYS)/include -L$(ROOTSYS)/lib
+endif
+
+PLATFORM := $(shell uname -s)
+ifeq ($(PLATFORM),Darwin)
+ cppflags+=-dynamiclib -single_module -arch x86_64
+endif
+
+ifeq ($(shell $(genreflex) --help | grep -- --with-methptrgetter),)
+ genreflexflags=
+ cppflags2=-O3 -fPIC
+else
+ genreflexflags=--with-methptrgetter
+ cppflags2=-Wno-pmf-conversions -O3 -fPIC
+endif
+
+
+bench02Dict_reflex.so: bench02.h bench02.cxx bench02.xml
+ $(genreflex) bench02.h $(genreflexflags) --selection=bench02.xml -I$(ROOTSYS)/include
+ g++ -o $@ bench02.cxx bench02_rflx.cpp -I$(ROOTSYS)/include -shared -lReflex -lHistPainter `root-config --libs` $(cppflags) $(cppflags2)
diff --git a/pypy/module/cppyy/bench/bench02.cxx b/pypy/module/cppyy/bench/bench02.cxx
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/bench/bench02.cxx
@@ -0,0 +1,79 @@
+#include "bench02.h"
+
+#include "TROOT.h"
+#include "TApplication.h"
+#include "TDirectory.h"
+#include "TInterpreter.h"
+#include "TSystem.h"
+#include "TBenchmark.h"
+#include "TStyle.h"
+#include "TError.h"
+#include "Getline.h"
+#include "TVirtualX.h"
+
+#include "Api.h"
+
+#include <iostream>
+
+TClass *TClass::GetClass(const char*, Bool_t, Bool_t) {
+ static TClass* dummy = new TClass("__dummy__", kTRUE);
+ return dummy; // is deleted by gROOT at shutdown
+}
+
+class TTestApplication : public TApplication {
+public:
+ TTestApplication(
+ const char* acn, Int_t* argc, char** argv, Bool_t bLoadLibs = kTRUE);
+ virtual ~TTestApplication();
+};
+
+TTestApplication::TTestApplication(
+ const char* acn, int* argc, char** argv, bool do_load) : TApplication(acn, argc, argv) {
+ if (do_load) {
+ // follow TRint to minimize differences with CINT
+ ProcessLine("#include <iostream>", kTRUE);
+ ProcessLine("#include <_string>", kTRUE); // for std::string iostream.
+ ProcessLine("#include <vector>", kTRUE); // needed because they're used within the
+ ProcessLine("#include <pair>", kTRUE); // core ROOT dicts and CINT won't be able
+ // to properly unload these files
+ }
+
+ // save current interpreter context
+ gInterpreter->SaveContext();
+ gInterpreter->SaveGlobalsContext();
+
+ // prevent crashes on accessing history
+ Gl_histinit((char*)"-");
+
+ // prevent ROOT from exiting python
+ SetReturnFromRun(kTRUE);
+}
+
+TTestApplication::~TTestApplication() {}
+
+static const char* appname = "pypy-cppyy";
+
+Bench02RootApp::Bench02RootApp() {
+ gROOT->SetBatch(kTRUE);
+ if (!gApplication) {
+ int argc = 1;
+ char* argv[1]; argv[0] = (char*)appname;
+ gApplication = new TTestApplication(appname, &argc, argv, kFALSE);
+ }
+}
+
+Bench02RootApp::~Bench02RootApp() {
+ // TODO: ROOT globals cleanup ... (?)
+}
+
+void Bench02RootApp::report() {
+ std::cout << "gROOT is: " << gROOT << std::endl;
+ std::cout << "gApplication is: " << gApplication << std::endl;
+}
+
+void Bench02RootApp::close_file(TFile* f) {
+ std::cout << "closing file " << f->GetName() << " ... " << std::endl;
+ f->Write();
+ f->Close();
+ std::cout << "... file closed" << std::endl;
+}
diff --git a/pypy/module/cppyy/bench/bench02.h b/pypy/module/cppyy/bench/bench02.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/bench/bench02.h
@@ -0,0 +1,72 @@
+#include "TString.h"
+
+#include "TCanvas.h"
+#include "TFile.h"
+#include "TProfile.h"
+#include "TNtuple.h"
+#include "TH1F.h"
+#include "TH2F.h"
+#include "TRandom.h"
+#include "TRandom3.h"
+
+#include "TROOT.h"
+#include "TApplication.h"
+#include "TSystem.h"
+
+#include "TArchiveFile.h"
+#include "TBasket.h"
+#include "TBenchmark.h"
+#include "TBox.h"
+#include "TBranchRef.h"
+#include "TBrowser.h"
+#include "TClassGenerator.h"
+#include "TClassRef.h"
+#include "TClassStreamer.h"
+#include "TContextMenu.h"
+#include "TEntryList.h"
+#include "TEventList.h"
+#include "TF1.h"
+#include "TFileCacheRead.h"
+#include "TFileCacheWrite.h"
+#include "TFileMergeInfo.h"
+#include "TFitResult.h"
+#include "TFolder.h"
+//#include "TFormulaPrimitive.h"
+#include "TFunction.h"
+#include "TFrame.h"
+#include "TGlobal.h"
+#include "THashList.h"
+#include "TInetAddress.h"
+#include "TInterpreter.h"
+#include "TKey.h"
+#include "TLegend.h"
+#include "TMethodCall.h"
+#include "TPluginManager.h"
+#include "TProcessUUID.h"
+#include "TSchemaRuleSet.h"
+#include "TStyle.h"
+#include "TSysEvtHandler.h"
+#include "TTimer.h"
+#include "TView.h"
+//#include "TVirtualCollectionProxy.h"
+#include "TVirtualFFT.h"
+#include "TVirtualHistPainter.h"
+#include "TVirtualIndex.h"
+#include "TVirtualIsAProxy.h"
+#include "TVirtualPadPainter.h"
+#include "TVirtualRefProxy.h"
+#include "TVirtualStreamerInfo.h"
+#include "TVirtualViewer3D.h"
+
+#include <typeinfo>
+#include <ostream>
+
+
+class Bench02RootApp {
+public:
+ Bench02RootApp();
+ ~Bench02RootApp();
+
+ void report();
+ void close_file(TFile* f);
+};
diff --git a/pypy/module/cppyy/bench/bench02.xml b/pypy/module/cppyy/bench/bench02.xml
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/bench/bench02.xml
@@ -0,0 +1,41 @@
+<lcgdict>
+
+ <selection>
+
+ <!-- ROOT classes -->
+ <class pattern="T[A-Z]*" />
+ <class pattern="ROOT::T[A-Z]*" />
+ <class pattern="ROOT::Fit::*" />
+
+ <!-- ROOT globals -->
+ <variable name="gROOT" />
+ <variable name="gSystem" />
+ <variable name="gRandom" />
+
+ <!-- STL classes actually used -->
+ <class name="std::string" />
+ <class name="std::ostream" />
+ <class name="std::type_info" />
+ <class pattern="std::vector<*>" />
+ <class pattern="std::_Vector_base<*>" />
+
+ <!-- helper -->
+ <class name="Bench02RootApp" />
+
+ </selection>
+
+ <exclusion>
+
+ <struct pattern="TString::*" />
+ <class name="TString" >
+ <field name="fRep" transient="true"/>
+ </class>
+
+ <class name="TUUID::uuid_time_t" />
+
+ <class name="TClass::TNameMapNode" />
+ <class name="TFileOpenHandle" />
+
+ </exclusion>
+
+</lcgdict>
diff --git a/pypy/module/cppyy/bench/hsimple.C b/pypy/module/cppyy/bench/hsimple.C
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/bench/hsimple.C
@@ -0,0 +1,109 @@
+#include <TFile.h>
+#include <TNtuple.h>
+#include <TH2.h>
+#include <TProfile.h>
+#include <TCanvas.h>
+#include <TFrame.h>
+#include <TROOT.h>
+#include <TSystem.h>
+#include <TRandom3.h>
+#include <TBenchmark.h>
+#include <TInterpreter.h>
+
+TFile *hsimple(Int_t get=0)
+{
+// This program creates :
+// - a one dimensional histogram
+// - a two dimensional histogram
+// - a profile histogram
+// - a memory-resident ntuple
+//
+// These objects are filled with some random numbers and saved on a file.
+// If get=1 the macro returns a pointer to the TFile of "hsimple.root"
+// if this file exists, otherwise it is created.
+// The file "hsimple.root" is created in $ROOTSYS/tutorials if the caller has
+// write access to this directory, otherwise the file is created in $PWD
+
+ TString filename = "hsimple.root";
+ TString dir = gSystem->UnixPathName(gInterpreter->GetCurrentMacroName());
+ dir.ReplaceAll("hsimple.C","");
+ dir.ReplaceAll("/./","/");
+ TFile *hfile = 0;
+ if (get) {
+ // if the argument get =1 return the file "hsimple.root"
+ // if the file does not exist, it is created
+ TString fullPath = dir+"hsimple.root";
+ if (!gSystem->AccessPathName(fullPath,kFileExists)) {
+ hfile = TFile::Open(fullPath); //in $ROOTSYS/tutorials
+ if (hfile) return hfile;
+ }
+ //otherwise try $PWD/hsimple.root
+ if (!gSystem->AccessPathName("hsimple.root",kFileExists)) {
+ hfile = TFile::Open("hsimple.root"); //in current dir
+ if (hfile) return hfile;
+ }
+ }
+ //no hsimple.root file found. Must generate it !
+ //generate hsimple.root in $ROOTSYS/tutorials if we have write access
+ if (!gSystem->AccessPathName(dir,kWritePermission)) {
+ filename = dir+"hsimple.root";
+ } else if (!gSystem->AccessPathName(".",kWritePermission)) {
+ //otherwise generate hsimple.root in the current directory
+ } else {
+ printf("you must run the script in a directory with write access\n");
+ return 0;
+ }
+ hfile = (TFile*)gROOT->FindObject(filename); if (hfile) hfile->Close();
+ hfile = new TFile(filename,"RECREATE","Demo ROOT file with histograms");
+
+ // Create some histograms, a profile histogram and an ntuple
+ TH1F *hpx = new TH1F("hpx","This is the px distribution",100,-4,4);
+ hpx->SetFillColor(48);
+ TH2F *hpxpy = new TH2F("hpxpy","py vs px",40,-4,4,40,-4,4);
+ TProfile *hprof = new TProfile("hprof","Profile of pz versus px",100,-4,4,0,20);
+ TNtuple *ntuple = new TNtuple("ntuple","Demo ntuple","px:py:pz:random:i");
+
+ gBenchmark->Start("hsimple");
+
+ // Create a new canvas.
+ TCanvas *c1 = new TCanvas("c1","Dynamic Filling Example",200,10,700,500);
+ c1->SetFillColor(42);
+ c1->GetFrame()->SetFillColor(21);
+ c1->GetFrame()->SetBorderSize(6);
+ c1->GetFrame()->SetBorderMode(-1);
+
+
+ // Fill histograms randomly
+ TRandom3 random;
+ Float_t px, py, pz;
+ const Int_t kUPDATE = 1000;
+ for (Int_t i = 0; i < 50000; i++) {
+ // random.Rannor(px,py);
+ px = random.Gaus(0, 1);
+ py = random.Gaus(0, 1);
+ pz = px*px + py*py;
+ Float_t rnd = random.Rndm(1);
+ hpx->Fill(px);
+ hpxpy->Fill(px,py);
+ hprof->Fill(px,pz);
+ ntuple->Fill(px,py,pz,rnd,i);
+ if (i && (i%kUPDATE) == 0) {
+ if (i == kUPDATE) hpx->Draw();
+ c1->Modified();
+ c1->Update();
+ if (gSystem->ProcessEvents())
+ break;
+ }
+ }
+ gBenchmark->Show("hsimple");
+
+ // Save all objects in this file
+ hpx->SetFillColor(0);
+ hfile->Write();
+ hpx->SetFillColor(48);
+ c1->Modified();
+ return hfile;
+
+// Note that the file is automatically close when application terminates
+// or when the file destructor is called.
+}
diff --git a/pypy/module/cppyy/bench/hsimple.py b/pypy/module/cppyy/bench/hsimple.py
new file mode 100755
--- /dev/null
+++ b/pypy/module/cppyy/bench/hsimple.py
@@ -0,0 +1,110 @@
+#*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
+#*-*
+#*-* This program creates :
+#*-* - a one dimensional histogram
+#*-* - a two dimensional histogram
+#*-* - a profile histogram
+#*-* - a memory-resident ntuple
+#*-*
+#*-* These objects are filled with some random numbers and saved on a file.
+#*-*
+#*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
+
+_reflex = True # to keep things equal, set to False for full macro
+
+try:
+ import cppyy, random
+
+ if not hasattr(cppyy.gbl, 'gROOT'):
+ cppyy.load_reflection_info('bench02Dict_reflex.so')
+ _reflex = True
+
+ TCanvas = cppyy.gbl.TCanvas
+ TFile = cppyy.gbl.TFile
+ TProfile = cppyy.gbl.TProfile
+ TNtuple = cppyy.gbl.TNtuple
+ TH1F = cppyy.gbl.TH1F
+ TH2F = cppyy.gbl.TH2F
+ TRandom3 = cppyy.gbl.TRandom3
+
+ gROOT = cppyy.gbl.gROOT
+ gBenchmark = cppyy.gbl.TBenchmark()
+ gSystem = cppyy.gbl.gSystem
+
+except ImportError:
+ from ROOT import TCanvas, TFile, TProfile, TNtuple, TH1F, TH2F, TRandom3
+ from ROOT import gROOT, gBenchmark, gSystem
+ import random
+
+if _reflex:
+ gROOT.SetBatch(True)
+
+# Create a new ROOT binary machine independent file.
+# Note that this file may contain any kind of ROOT objects, histograms,
+# pictures, graphics objects, detector geometries, tracks, events, etc..
+# This file is now becoming the current directory.
+
+if not _reflex:
+ hfile = gROOT.FindObject('hsimple.root')
+ if hfile:
+ hfile.Close()
+ hfile = TFile('hsimple.root', 'RECREATE', 'Demo ROOT file with histograms' )
+
+# Create some histograms, a profile histogram and an ntuple
+hpx = TH1F('hpx', 'This is the px distribution', 100, -4, 4)
+hpx.SetFillColor(48)
+hpxpy = TH2F('hpxpy', 'py vs px', 40, -4, 4, 40, -4, 4)
+hprof = TProfile('hprof', 'Profile of pz versus px', 100, -4, 4, 0, 20)
+if not _reflex:
+ ntuple = TNtuple('ntuple', 'Demo ntuple', 'px:py:pz:random:i')
+
+gBenchmark.Start('hsimple')
+
+# Create a new canvas, and customize it.
+c1 = TCanvas('c1', 'Dynamic Filling Example', 200, 10, 700, 500)
+c1.SetFillColor(42)
+c1.GetFrame().SetFillColor(21)
+c1.GetFrame().SetBorderSize(6)
+c1.GetFrame().SetBorderMode(-1)
+
+# Fill histograms randomly.
+random = TRandom3()
+kUPDATE = 1000
+for i in xrange(50000):
+ # Generate random numbers
+# px, py = random.gauss(0, 1), random.gauss(0, 1)
+ px, py = random.Gaus(0, 1), random.Gaus(0, 1)
+ pz = px*px + py*py
+# rnd = random.random()
+ rnd = random.Rndm(1)
+
+ # Fill histograms
+ hpx.Fill(px)
+ hpxpy.Fill(px, py)
+ hprof.Fill(px, pz)
+ if not _reflex:
+ ntuple.Fill(px, py, pz, rnd, i)
+
+ # Update display every kUPDATE events
+ if i and i%kUPDATE == 0:
+ if i == kUPDATE:
+ hpx.Draw()
+
+ c1.Modified(True)
+ c1.Update()
+
+ if gSystem.ProcessEvents(): # allow user interrupt
+ break
+
+gBenchmark.Show( 'hsimple' )
+
+# Save all objects in this file
+hpx.SetFillColor(0)
+if not _reflex:
+ hfile.Write()
+hpx.SetFillColor(48)
+c1.Modified(True)
+c1.Update()
+
+# Note that the file is automatically closed when application terminates
+# or when the file destructor is called.
diff --git a/pypy/module/cppyy/bench/hsimple_rflx.py b/pypy/module/cppyy/bench/hsimple_rflx.py
new file mode 100755
--- /dev/null
+++ b/pypy/module/cppyy/bench/hsimple_rflx.py
@@ -0,0 +1,120 @@
+#*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
+#*-*
+#*-* This program creates :
+#*-* - a one dimensional histogram
+#*-* - a two dimensional histogram
+#*-* - a profile histogram
+#*-* - a memory-resident ntuple
+#*-*
+#*-* These objects are filled with some random numbers and saved on a file.
+#*-*
+#*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
+
+try:
+ import warnings
+ warnings.simplefilter("ignore")
+
+ import cppyy, random
+ cppyy.load_reflection_info('bench02Dict_reflex.so')
+
+ app = cppyy.gbl.Bench02RootApp()
+ TCanvas = cppyy.gbl.TCanvas
+ TFile = cppyy.gbl.TFile
+ TProfile = cppyy.gbl.TProfile
+ TNtuple = cppyy.gbl.TNtuple
+ TH1F = cppyy.gbl.TH1F
+ TH2F = cppyy.gbl.TH2F
+ TRandom = cppyy.gbl.TRandom
+except ImportError:
+ from ROOT import TCanvas, TFile, TProfile, TNtuple, TH1F, TH2F, TRandom
+ import random
+
+import math
+
+#gROOT = cppyy.gbl.gROOT
+#gBenchmark = cppyy.gbl.gBenchmark
+#gRandom = cppyy.gbl.gRandom
+#gSystem = cppyy.gbl.gSystem
+
+#gROOT.Reset()
+
+# Create a new canvas, and customize it.
+#c1 = TCanvas( 'c1', 'Dynamic Filling Example', 200, 10, 700, 500 )
+#c1.SetFillColor( 42 )
+#c1.GetFrame().SetFillColor( 21 )
+#c1.GetFrame().SetBorderSize( 6 )
+#c1.GetFrame().SetBorderMode( -1 )
+
+# Create a new ROOT binary machine independent file.
+# Note that this file may contain any kind of ROOT objects, histograms,
+# pictures, graphics objects, detector geometries, tracks, events, etc..
+# This file is now becoming the current directory.
+
+#hfile = gROOT.FindObject( 'hsimple.root' )
+#if hfile:
+# hfile.Close()
+#hfile = TFile( 'hsimple.root', 'RECREATE', 'Demo ROOT file with histograms' )
+
+# Create some histograms, a profile histogram and an ntuple
+hpx = TH1F('hpx', 'This is the px distribution', 100, -4, 4)
+hpx.Print()
+#hpxpy = TH2F( 'hpxpy', 'py vs px', 40, -4, 4, 40, -4, 4 )
+#hprof = TProfile( 'hprof', 'Profile of pz versus px', 100, -4, 4, 0, 20 )
+#ntuple = TNtuple( 'ntuple', 'Demo ntuple', 'px:py:pz:random:i' )
+
+# Set canvas/frame attributes.
+#hpx.SetFillColor( 48 )
+
+#gBenchmark.Start( 'hsimple' )
+
+# Initialize random number generator.
+#gRandom.SetSeed()
+#rannor, rndm = gRandom.Rannor, gRandom.Rndm
+
+random = TRandom()
+random.SetSeed(0)
+
+# Fill histograms randomly.
+#px, py = Double(), Double()
+kUPDATE = 1000
+for i in xrange(2500000):
+ # Generate random values.
+# px, py = random.gauss(0, 1), random.gauss(0, 1)
+ px, py = random.Gaus(0, 1), random.Gaus(0, 1)
+# pt = (px*px + py*py)**0.5
+ pt = math.sqrt(px*px + py*py)
+# pt = (px*px + py*py)
+# random = rndm(1)
+
+ # Fill histograms.
+ hpx.Fill(pt)
+# hpxpyFill( px, py )
+# hprofFill( px, pz )
+# ntupleFill( px, py, pz, random, i )
+
+ # Update display every kUPDATE events.
+# if i and i%kUPDATE == 0:
+# if i == kUPDATE:
+# hpx.Draw()
+
+# c1.Modified()
+# c1.Update()
+
+# if gSystem.ProcessEvents(): # allow user interrupt
+# break
+
+#gBenchmark.Show( 'hsimple' )
+
+hpx.Print()
+
+# Save all objects in this file.
+#hpx.SetFillColor( 0 )
+#hfile.Write()
+#hfile.Close()
+#hpx.SetFillColor( 48 )
+#c1.Modified()
+#c1.Update()
+#c1.Draw()
+
+# Note that the file is automatically closed when application terminates
+# or when the file destructor is called.
diff --git a/pypy/module/cppyy/capi/__init__.py b/pypy/module/cppyy/capi/__init__.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/capi/__init__.py
@@ -0,0 +1,450 @@
+from pypy.rpython.lltypesystem import rffi, lltype
+from pypy.rlib import jit
+
+import reflex_capi as backend
+#import cint_capi as backend
+
+identify = backend.identify
+ts_reflect = backend.ts_reflect
+ts_call = backend.ts_call
+ts_memory = backend.ts_memory
+ts_helper = backend.ts_helper
+
+_C_OPAQUE_PTR = rffi.LONG
+_C_OPAQUE_NULL = lltype.nullptr(rffi.LONGP.TO)# ALT: _C_OPAQUE_PTR.TO
+
+C_SCOPE = _C_OPAQUE_PTR
+C_NULL_SCOPE = rffi.cast(C_SCOPE, _C_OPAQUE_NULL)
+
+C_TYPE = C_SCOPE
+C_NULL_TYPE = C_NULL_SCOPE
+
+C_OBJECT = _C_OPAQUE_PTR
+C_NULL_OBJECT = rffi.cast(C_OBJECT, _C_OPAQUE_NULL)
+
+C_METHOD = _C_OPAQUE_PTR
+
+C_METHPTRGETTER = lltype.FuncType([C_OBJECT], rffi.VOIDP)
+C_METHPTRGETTER_PTR = lltype.Ptr(C_METHPTRGETTER)
+
+def direct_ptradd(ptr, offset):
+ offset = rffi.cast(rffi.SIZE_T, offset)
+ jit.promote(offset)
+ assert lltype.typeOf(ptr) == C_OBJECT
+ address = rffi.cast(rffi.CCHARP, ptr)
+ return rffi.cast(C_OBJECT, lltype.direct_ptradd(address, offset))
+
+c_load_dictionary = backend.c_load_dictionary
+
+# name to opaque C++ scope representation ------------------------------------
+_c_resolve_name = rffi.llexternal(
+ "cppyy_resolve_name",
+ [rffi.CCHARP], rffi.CCHARP,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+def c_resolve_name(name):
+ return charp2str_free(_c_resolve_name(name))
+c_get_scope_opaque = rffi.llexternal(
+ "cppyy_get_scope",
+ [rffi.CCHARP], C_SCOPE,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+c_get_template = rffi.llexternal(
+ "cppyy_get_template",
+ [rffi.CCHARP], C_TYPE,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+_c_actual_class = rffi.llexternal(
+ "cppyy_actual_class",
+ [C_TYPE, C_OBJECT], C_TYPE,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+def c_actual_class(cppclass, cppobj):
+ return _c_actual_class(cppclass.handle, cppobj)
+
+# memory management ----------------------------------------------------------
+_c_allocate = rffi.llexternal(
+ "cppyy_allocate",
+ [C_TYPE], C_OBJECT,
+ threadsafe=ts_memory,
+ compilation_info=backend.eci)
+def c_allocate(cppclass):
+ return _c_allocate(cppclass.handle)
+_c_deallocate = rffi.llexternal(
+ "cppyy_deallocate",
+ [C_TYPE, C_OBJECT], lltype.Void,
+ threadsafe=ts_memory,
+ compilation_info=backend.eci)
+def c_deallocate(cppclass, cppobject):
+ _c_deallocate(cppclass.handle, cppobject)
+_c_destruct = rffi.llexternal(
+ "cppyy_destruct",
+ [C_TYPE, C_OBJECT], lltype.Void,
+ threadsafe=ts_call,
+ compilation_info=backend.eci)
+def c_destruct(cppclass, cppobject):
+ _c_destruct(cppclass.handle, cppobject)
+
+# method/function dispatching ------------------------------------------------
+c_call_v = rffi.llexternal(
+ "cppyy_call_v",
+ [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], lltype.Void,
+ threadsafe=ts_call,
+ compilation_info=backend.eci)
+c_call_b = rffi.llexternal(
+ "cppyy_call_b",
+ [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.INT,
+ threadsafe=ts_call,
+ compilation_info=backend.eci)
+c_call_c = rffi.llexternal(
+ "cppyy_call_c",
+ [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.CHAR,
+ threadsafe=ts_call,
+ compilation_info=backend.eci)
+c_call_h = rffi.llexternal(
+ "cppyy_call_h",
+ [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.SHORT,
+ threadsafe=ts_call,
+ compilation_info=backend.eci)
+c_call_i = rffi.llexternal(
+ "cppyy_call_i",
+ [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.INT,
+ threadsafe=ts_call,
+ compilation_info=backend.eci)
+c_call_l = rffi.llexternal(
+ "cppyy_call_l",
+ [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.LONG,
+ threadsafe=ts_call,
+ compilation_info=backend.eci)
+c_call_ll = rffi.llexternal(
+ "cppyy_call_ll",
+ [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.LONGLONG,
+ threadsafe=ts_call,
+ compilation_info=backend.eci)
+c_call_f = rffi.llexternal(
+ "cppyy_call_f",
+ [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.DOUBLE,
+ threadsafe=ts_call,
+ compilation_info=backend.eci)
+c_call_d = rffi.llexternal(
+ "cppyy_call_d",
+ [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.DOUBLE,
+ threadsafe=ts_call,
+ compilation_info=backend.eci)
+
+c_call_r = rffi.llexternal(
+ "cppyy_call_r",
+ [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.VOIDP,
+ threadsafe=ts_call,
+ compilation_info=backend.eci)
+c_call_s = rffi.llexternal(
+ "cppyy_call_s",
+ [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.CCHARP,
+ threadsafe=ts_call,
+ compilation_info=backend.eci)
+
+c_constructor = rffi.llexternal(
+ "cppyy_constructor",
+ [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], lltype.Void,
+ threadsafe=ts_call,
+ compilation_info=backend.eci)
+
+_c_call_o = rffi.llexternal(
+ "cppyy_call_o",
+ [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP, C_TYPE], rffi.LONG,
+ threadsafe=ts_call,
+ compilation_info=backend.eci)
+def c_call_o(method_index, cppobj, nargs, args, cppclass):
+ return _c_call_o(method_index, cppobj, nargs, args, cppclass.handle)
+
+_c_get_methptr_getter = rffi.llexternal(
+ "cppyy_get_methptr_getter",
+ [C_SCOPE, rffi.INT], C_METHPTRGETTER_PTR,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci,
+ elidable_function=True)
+def c_get_methptr_getter(cppscope, method_index):
+ return _c_get_methptr_getter(cppscope.handle, method_index)
+
+# handling of function argument buffer ---------------------------------------
+c_allocate_function_args = rffi.llexternal(
+ "cppyy_allocate_function_args",
+ [rffi.SIZE_T], rffi.VOIDP,
+ threadsafe=ts_memory,
+ compilation_info=backend.eci)
+c_deallocate_function_args = rffi.llexternal(
+ "cppyy_deallocate_function_args",
+ [rffi.VOIDP], lltype.Void,
+ threadsafe=ts_memory,
+ compilation_info=backend.eci)
+c_function_arg_sizeof = rffi.llexternal(
+ "cppyy_function_arg_sizeof",
+ [], rffi.SIZE_T,
+ threadsafe=ts_memory,
+ compilation_info=backend.eci,
+ elidable_function=True)
+c_function_arg_typeoffset = rffi.llexternal(
+ "cppyy_function_arg_typeoffset",
+ [], rffi.SIZE_T,
+ threadsafe=ts_memory,
+ compilation_info=backend.eci,
+ elidable_function=True)
+
+# scope reflection information -----------------------------------------------
+c_is_namespace = rffi.llexternal(
+ "cppyy_is_namespace",
+ [C_SCOPE], rffi.INT,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+c_is_enum = rffi.llexternal(
+ "cppyy_is_enum",
+ [rffi.CCHARP], rffi.INT,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+
+# type/class reflection information ------------------------------------------
+_c_final_name = rffi.llexternal(
+ "cppyy_final_name",
+ [C_TYPE], rffi.CCHARP,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+def c_final_name(cpptype):
+ return charp2str_free(_c_final_name(cpptype))
+_c_scoped_final_name = rffi.llexternal(
+ "cppyy_scoped_final_name",
+ [C_TYPE], rffi.CCHARP,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+def c_scoped_final_name(cpptype):
+ return charp2str_free(_c_scoped_final_name(cpptype))
+c_has_complex_hierarchy = rffi.llexternal(
+ "cppyy_has_complex_hierarchy",
+ [C_TYPE], rffi.INT,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+_c_num_bases = rffi.llexternal(
+ "cppyy_num_bases",
+ [C_TYPE], rffi.INT,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+def c_num_bases(cppclass):
+ return _c_num_bases(cppclass.handle)
+_c_base_name = rffi.llexternal(
+ "cppyy_base_name",
+ [C_TYPE, rffi.INT], rffi.CCHARP,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+def c_base_name(cppclass, base_index):
+ return charp2str_free(_c_base_name(cppclass.handle, base_index))
+
+_c_is_subtype = rffi.llexternal(
+ "cppyy_is_subtype",
+ [C_TYPE, C_TYPE], rffi.INT,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci,
+ elidable_function=True)
+ at jit.elidable_promote()
+def c_is_subtype(derived, base):
+ if derived == base:
+ return 1
+ return _c_is_subtype(derived.handle, base.handle)
+
+_c_base_offset = rffi.llexternal(
+ "cppyy_base_offset",
+ [C_TYPE, C_TYPE, C_OBJECT, rffi.INT], rffi.SIZE_T,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci,
+ elidable_function=True)
+ at jit.elidable_promote()
+def c_base_offset(derived, base, address, direction):
+ if derived == base:
+ return 0
+ return _c_base_offset(derived.handle, base.handle, address, direction)
+
+# method/function reflection information -------------------------------------
+_c_num_methods = rffi.llexternal(
+ "cppyy_num_methods",
+ [C_SCOPE], rffi.INT,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+def c_num_methods(cppscope):
+ return _c_num_methods(cppscope.handle)
+_c_method_name = rffi.llexternal(
+ "cppyy_method_name",
+ [C_SCOPE, rffi.INT], rffi.CCHARP,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+def c_method_name(cppscope, method_index):
+ return charp2str_free(_c_method_name(cppscope.handle, method_index))
+_c_method_result_type = rffi.llexternal(
+ "cppyy_method_result_type",
+ [C_SCOPE, rffi.INT], rffi.CCHARP,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+def c_method_result_type(cppscope, method_index):
+ return charp2str_free(_c_method_result_type(cppscope.handle, method_index))
+_c_method_num_args = rffi.llexternal(
+ "cppyy_method_num_args",
+ [C_SCOPE, rffi.INT], rffi.INT,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+def c_method_num_args(cppscope, method_index):
+ return _c_method_num_args(cppscope.handle, method_index)
+_c_method_req_args = rffi.llexternal(
+ "cppyy_method_req_args",
+ [C_SCOPE, rffi.INT], rffi.INT,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+def c_method_req_args(cppscope, method_index):
+ return _c_method_req_args(cppscope.handle, method_index)
+_c_method_arg_type = rffi.llexternal(
+ "cppyy_method_arg_type",
+ [C_SCOPE, rffi.INT, rffi.INT], rffi.CCHARP,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+def c_method_arg_type(cppscope, method_index, arg_index):
+ return charp2str_free(_c_method_arg_type(cppscope.handle, method_index, arg_index))
+_c_method_arg_default = rffi.llexternal(
+ "cppyy_method_arg_default",
+ [C_SCOPE, rffi.INT, rffi.INT], rffi.CCHARP,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+def c_method_arg_default(cppscope, method_index, arg_index):
+ return charp2str_free(_c_method_arg_default(cppscope.handle, method_index, arg_index))
+_c_method_signature = rffi.llexternal(
+ "cppyy_method_signature",
+ [C_SCOPE, rffi.INT], rffi.CCHARP,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+def c_method_signature(cppscope, method_index):
+ return charp2str_free(_c_method_signature(cppscope.handle, method_index))
+
+_c_method_index = rffi.llexternal(
+ "cppyy_method_index",
+ [C_SCOPE, rffi.CCHARP], rffi.INT,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+def c_method_index(cppscope, name):
+ return _c_method_index(cppscope.handle, name)
+
+_c_get_method = rffi.llexternal(
+ "cppyy_get_method",
+ [C_SCOPE, rffi.INT], C_METHOD,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+def c_get_method(cppscope, method_index):
+ return _c_get_method(cppscope.handle, method_index)
+
+# method properties ----------------------------------------------------------
+_c_is_constructor = rffi.llexternal(
+ "cppyy_is_constructor",
+ [C_TYPE, rffi.INT], rffi.INT,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+def c_is_constructor(cppclass, method_index):
+ return _c_is_constructor(cppclass.handle, method_index)
+_c_is_staticmethod = rffi.llexternal(
+ "cppyy_is_staticmethod",
+ [C_TYPE, rffi.INT], rffi.INT,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+def c_is_staticmethod(cppclass, method_index):
+ return _c_is_staticmethod(cppclass.handle, method_index)
+
+# data member reflection information -----------------------------------------
+_c_num_datamembers = rffi.llexternal(
+ "cppyy_num_datamembers",
+ [C_SCOPE], rffi.INT,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+def c_num_datamembers(cppscope):
+ return _c_num_datamembers(cppscope.handle)
+_c_datamember_name = rffi.llexternal(
+ "cppyy_datamember_name",
+ [C_SCOPE, rffi.INT], rffi.CCHARP,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+def c_datamember_name(cppscope, datamember_index):
+ return charp2str_free(_c_datamember_name(cppscope.handle, datamember_index))
+_c_datamember_type = rffi.llexternal(
+ "cppyy_datamember_type",
+ [C_SCOPE, rffi.INT], rffi.CCHARP,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+def c_datamember_type(cppscope, datamember_index):
+ return charp2str_free(_c_datamember_type(cppscope.handle, datamember_index))
+_c_datamember_offset = rffi.llexternal(
+ "cppyy_datamember_offset",
+ [C_SCOPE, rffi.INT], rffi.SIZE_T,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+def c_datamember_offset(cppscope, datamember_index):
+ return _c_datamember_offset(cppscope.handle, datamember_index)
+
+_c_datamember_index = rffi.llexternal(
+ "cppyy_datamember_index",
+ [C_SCOPE, rffi.CCHARP], rffi.INT,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+def c_datamember_index(cppscope, name):
+ return _c_datamember_index(cppscope.handle, name)
+
+# data member properties -----------------------------------------------------
+_c_is_publicdata = rffi.llexternal(
+ "cppyy_is_publicdata",
+ [C_SCOPE, rffi.INT], rffi.INT,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+def c_is_publicdata(cppscope, datamember_index):
+ return _c_is_publicdata(cppscope.handle, datamember_index)
+_c_is_staticdata = rffi.llexternal(
+ "cppyy_is_staticdata",
+ [C_SCOPE, rffi.INT], rffi.INT,
+ threadsafe=ts_reflect,
+ compilation_info=backend.eci)
+def c_is_staticdata(cppscope, datamember_index):
+ return _c_is_staticdata(cppscope.handle, datamember_index)
+
+# misc helpers ---------------------------------------------------------------
+c_strtoll = rffi.llexternal(
+ "cppyy_strtoll",
+ [rffi.CCHARP], rffi.LONGLONG,
+ threadsafe=ts_helper,
+ compilation_info=backend.eci)
+c_strtoull = rffi.llexternal(
+ "cppyy_strtoull",
+ [rffi.CCHARP], rffi.ULONGLONG,
+ threadsafe=ts_helper,
+ compilation_info=backend.eci)
+c_free = rffi.llexternal(
+ "cppyy_free",
+ [rffi.VOIDP], lltype.Void,
+ threadsafe=ts_memory,
+ compilation_info=backend.eci)
+
+def charp2str_free(charp):
+ string = rffi.charp2str(charp)
+ voidp = rffi.cast(rffi.VOIDP, charp)
+ c_free(voidp)
+ return string
+
+c_charp2stdstring = rffi.llexternal(
+ "cppyy_charp2stdstring",
+ [rffi.CCHARP], C_OBJECT,
+ threadsafe=ts_helper,
+ compilation_info=backend.eci)
+c_stdstring2stdstring = rffi.llexternal(
+ "cppyy_stdstring2stdstring",
+ [C_OBJECT], C_OBJECT,
+ threadsafe=ts_helper,
+ compilation_info=backend.eci)
+c_assign2stdstring = rffi.llexternal(
+ "cppyy_assign2stdstring",
+ [C_OBJECT, rffi.CCHARP], lltype.Void,
+ threadsafe=ts_helper,
+ compilation_info=backend.eci)
+c_free_stdstring = rffi.llexternal(
+ "cppyy_free_stdstring",
+ [C_OBJECT], lltype.Void,
+ threadsafe=ts_helper,
+ compilation_info=backend.eci)
diff --git a/pypy/module/cppyy/capi/cint_capi.py b/pypy/module/cppyy/capi/cint_capi.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/capi/cint_capi.py
@@ -0,0 +1,63 @@
+import py, os
+
+from pypy.translator.tool.cbuild import ExternalCompilationInfo
+from pypy.rpython.lltypesystem import rffi
+from pypy.rlib import libffi, rdynload
+
+__all__ = ['identify', 'eci', 'c_load_dictionary']
+
+pkgpath = py.path.local(__file__).dirpath().join(os.pardir)
+srcpath = pkgpath.join("src")
+incpath = pkgpath.join("include")
+
+if os.environ.get("ROOTSYS"):
+ import commands
+ (stat, incdir) = commands.getstatusoutput("root-config --incdir")
+ if stat != 0: # presumably Reflex-only
+ rootincpath = [os.path.join(os.environ["ROOTSYS"], "include")]
+ rootlibpath = [os.path.join(os.environ["ROOTSYS"], "lib64"), os.path.join(os.environ["ROOTSYS"], "lib")]
+ else:
+ rootincpath = [incdir]
+ rootlibpath = commands.getoutput("root-config --libdir").split()
+else:
+ rootincpath = []
+ rootlibpath = []
+
+def identify():
+ return 'CINT'
+
+ts_reflect = False
+ts_call = False
+ts_memory = 'auto'
+ts_helper = 'auto'
+
+# force loading in global mode of core libraries, rather than linking with
+# them as PyPy uses various version of dlopen in various places; note that
+# this isn't going to fly on Windows (note that locking them in objects and
+# calling dlclose in __del__ seems to come too late, so this'll do for now)
+with rffi.scoped_str2charp('libCint.so') as ll_libname:
+ _cintdll = rdynload.dlopen(ll_libname, rdynload.RTLD_GLOBAL | rdynload.RTLD_NOW)
+with rffi.scoped_str2charp('libCore.so') as ll_libname:
+ _coredll = rdynload.dlopen(ll_libname, rdynload.RTLD_GLOBAL | rdynload.RTLD_NOW)
+
+eci = ExternalCompilationInfo(
+ separate_module_files=[srcpath.join("cintcwrapper.cxx")],
+ include_dirs=[incpath] + rootincpath,
+ includes=["cintcwrapper.h"],
+ library_dirs=rootlibpath,
+ link_extra=["-lCore", "-lCint"],
+ use_cpp_linker=True,
+)
+
+_c_load_dictionary = rffi.llexternal(
+ "cppyy_load_dictionary",
+ [rffi.CCHARP], rdynload.DLLHANDLE,
+ threadsafe=False,
+ compilation_info=eci)
+
+def c_load_dictionary(name):
+ result = _c_load_dictionary(name)
+ if not result:
+ err = rdynload.dlerror()
+ raise rdynload.DLOpenError(err)
+ return libffi.CDLL(name) # should return handle to already open file
diff --git a/pypy/module/cppyy/capi/reflex_capi.py b/pypy/module/cppyy/capi/reflex_capi.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/capi/reflex_capi.py
@@ -0,0 +1,43 @@
+import py, os
+
+from pypy.rlib import libffi
+from pypy.translator.tool.cbuild import ExternalCompilationInfo
+
+__all__ = ['identify', 'eci', 'c_load_dictionary']
+
+pkgpath = py.path.local(__file__).dirpath().join(os.pardir)
+srcpath = pkgpath.join("src")
+incpath = pkgpath.join("include")
+
+if os.environ.get("ROOTSYS"):
+ import commands
+ (stat, incdir) = commands.getstatusoutput("root-config --incdir")
+ if stat != 0: # presumably Reflex-only
+ rootincpath = [os.path.join(os.environ["ROOTSYS"], "include")]
+ rootlibpath = [os.path.join(os.environ["ROOTSYS"], "lib64"), os.path.join(os.environ["ROOTSYS"], "lib")]
+ else:
+ rootincpath = [incdir]
+ rootlibpath = commands.getoutput("root-config --libdir").split()
+else:
+ rootincpath = []
+ rootlibpath = []
+
+def identify():
+ return 'Reflex'
+
+ts_reflect = False
+ts_call = 'auto'
+ts_memory = 'auto'
+ts_helper = 'auto'
+
+eci = ExternalCompilationInfo(
+ separate_module_files=[srcpath.join("reflexcwrapper.cxx")],
+ include_dirs=[incpath] + rootincpath,
+ includes=["reflexcwrapper.h"],
+ library_dirs=rootlibpath,
+ link_extra=["-lReflex"],
+ use_cpp_linker=True,
+)
+
+def c_load_dictionary(name):
+ return libffi.CDLL(name)
diff --git a/pypy/module/cppyy/converter.py b/pypy/module/cppyy/converter.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/converter.py
@@ -0,0 +1,832 @@
+import sys
+
+from pypy.interpreter.error import OperationError
+
+from pypy.rpython.lltypesystem import rffi, lltype
+from pypy.rlib.rarithmetic import r_singlefloat
+from pypy.rlib import jit, libffi, clibffi, rfloat
+
+from pypy.module._rawffi.interp_rawffi import unpack_simple_shape
+from pypy.module._rawffi.array import W_Array
+
+from pypy.module.cppyy import helper, capi
+
+
+def get_rawobject(space, w_obj):
+ from pypy.module.cppyy.interp_cppyy import W_CPPInstance
+ cppinstance = space.interp_w(W_CPPInstance, w_obj, can_be_None=True)
+ if cppinstance:
+ rawobject = cppinstance.get_rawobject()
+ assert lltype.typeOf(rawobject) == capi.C_OBJECT
+ 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)
+ if cppinstance:
+ cppinstance._nullcheck()
+ rawobject = cppinstance.get_rawobject()
+ assert lltype.typeOf(rawobject) == capi.C_OBJECT
+ return rawobject
+ return capi.C_NULL_OBJECT
+
+
+class TypeConverter(object):
+ _immutable_ = True
+ libffitype = lltype.nullptr(clibffi.FFI_TYPE_P.TO)
+ uses_local = False
+
+ name = ""
+
+ def __init__(self, space, extra):
+ pass
+
+ def _get_raw_address(self, space, w_obj, offset):
+ rawobject = get_rawobject_nonnull(space, w_obj)
+ assert lltype.typeOf(rawobject) == capi.C_OBJECT
+ if rawobject:
+ fieldptr = capi.direct_ptradd(rawobject, offset)
+ else:
+ fieldptr = rffi.cast(capi.C_OBJECT, offset)
+ return fieldptr
+
+ def _is_abstract(self, space):
+ raise OperationError(space.w_TypeError, space.wrap("no converter available"))
+
+ def convert_argument(self, space, w_obj, address, call_local):
+ self._is_abstract(space)
+
+ def convert_argument_libffi(self, space, w_obj, argchain, call_local):
+ from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
+ raise FastCallNotPossible
+
+ def default_argument_libffi(self, space, argchain):
+ from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
+ raise FastCallNotPossible
+
+ 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):
+ pass
+
+ def free_argument(self, space, arg, call_local):
+ pass
+
+
+class ArrayCache(object):
+ def __init__(self, space):
+ self.space = space
+ def __getattr__(self, name):
+ if name.startswith('array_'):
+ typecode = name[len('array_'):]
+ arr = self.space.interp_w(W_Array, unpack_simple_shape(self.space, self.space.wrap(typecode)))
+ setattr(self, name, arr)
+ return arr
+ raise AttributeError(name)
+
+ def _freeze_(self):
+ return True
+
+class ArrayTypeConverterMixin(object):
+ _mixin_ = True
+ _immutable_ = True
+
+ def __init__(self, space, array_size):
+ if array_size <= 0:
+ self.size = sys.maxint
+ else:
+ self.size = array_size
+
+ def from_memory(self, space, w_obj, w_pycppclass, offset):
+ if hasattr(space, "fake"):
+ raise NotImplementedError
+ # read access, so no copy needed
+ address_value = self._get_raw_address(space, w_obj, offset)
+ address = rffi.cast(rffi.ULONG, address_value)
+ cache = space.fromcache(ArrayCache)
+ arr = getattr(cache, 'array_' + self.typecode)
+ return arr.fromaddress(space, address, self.size)
+
+ def to_memory(self, space, w_obj, w_value, offset):
+ # copy the full array (uses byte copy for now)
+ address = rffi.cast(rffi.CCHARP, self._get_raw_address(space, w_obj, offset))
+ buf = space.buffer_w(w_value)
+ # TODO: report if too many items given?
+ for i in range(min(self.size*self.typesize, buf.getlength())):
+ address[i] = buf.getitem(i)
+
+
+class PtrTypeConverterMixin(object):
+ _mixin_ = True
+ _immutable_ = True
+
+ def __init__(self, space, array_size):
+ self.size = sys.maxint
+
+ def from_memory(self, space, w_obj, w_pycppclass, offset):
+ # read access, so no copy needed
+ address_value = self._get_raw_address(space, w_obj, offset)
+ address = rffi.cast(rffi.ULONGP, address_value)
+ cache = space.fromcache(ArrayCache)
+ arr = getattr(cache, 'array_' + self.typecode)
+ return arr.fromaddress(space, address[0], self.size)
+
+ def to_memory(self, space, w_obj, w_value, offset):
+ # copy only the pointer value
+ rawobject = get_rawobject_nonnull(space, w_obj)
+ byteptr = rffi.cast(rffi.CCHARPP, capi.direct_ptradd(rawobject, offset))
+ buf = space.buffer_w(w_value)
+ try:
+ byteptr[0] = buf.get_raw_address()
+ except ValueError:
+ raise OperationError(space.w_TypeError,
+ space.wrap("raw buffer interface not supported"))
+
+
+class NumericTypeConverterMixin(object):
+ _mixin_ = True
+ _immutable_ = True
+
+ def convert_argument_libffi(self, space, w_obj, argchain, call_local):
+ argchain.arg(self._unwrap_object(space, w_obj))
+
+ def default_argument_libffi(self, space, argchain):
+ argchain.arg(self.default)
+
+ def from_memory(self, space, w_obj, w_pycppclass, offset):
+ address = self._get_raw_address(space, w_obj, offset)
+ rffiptr = rffi.cast(self.c_ptrtype, address)
+ return space.wrap(rffiptr[0])
+
+ def to_memory(self, space, w_obj, w_value, offset):
+ address = self._get_raw_address(space, w_obj, offset)
+ rffiptr = rffi.cast(self.c_ptrtype, address)
+ rffiptr[0] = self._unwrap_object(space, w_value)
+
+class ConstRefNumericTypeConverterMixin(NumericTypeConverterMixin):
+ _mixin_ = True
+ _immutable_ = True
+ uses_local = True
+
+ def convert_argument_libffi(self, space, w_obj, argchain, call_local):
+ assert rffi.sizeof(self.c_type) <= 2*rffi.sizeof(rffi.VOIDP) # see interp_cppyy.py
+ obj = self._unwrap_object(space, w_obj)
+ typed_buf = rffi.cast(self.c_ptrtype, call_local)
+ typed_buf[0] = obj
+ argchain.arg(call_local)
+
+class IntTypeConverterMixin(NumericTypeConverterMixin):
+ _mixin_ = True
+ _immutable_ = True
+
+ 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)
+
+class FloatTypeConverterMixin(NumericTypeConverterMixin):
+ _mixin_ = True
+ _immutable_ = True
+
+ 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)
+ ba[capi.c_function_arg_typeoffset()] = self.typecode
+
+
+class VoidConverter(TypeConverter):
+ _immutable_ = True
+ libffitype = libffi.types.void
+
+ def __init__(self, space, name):
+ self.name = name
+
+ 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))
+
+
+class BoolConverter(TypeConverter):
+ _immutable_ = True
+ libffitype = libffi.types.schar
+
+ def _unwrap_object(self, space, w_obj):
+ arg = space.c_int_w(w_obj)
+ if arg != False and arg != True:
+ raise OperationError(space.w_ValueError,
+ space.wrap("boolean value should be bool, or integer 1 or 0"))
+ return arg
+
+ def convert_argument(self, space, w_obj, address, call_local):
+ x = rffi.cast(rffi.LONGP, address)
+ x[0] = self._unwrap_object(space, w_obj)
+
+ def convert_argument_libffi(self, space, w_obj, argchain, call_local):
+ argchain.arg(self._unwrap_object(space, w_obj))
+
+ def from_memory(self, space, w_obj, w_pycppclass, offset):
+ address = rffi.cast(rffi.CCHARP, self._get_raw_address(space, w_obj, offset))
+ if address[0] == '\x01':
+ return space.w_True
+ return space.w_False
+
+ def to_memory(self, space, w_obj, w_value, offset):
+ address = rffi.cast(rffi.CCHARP, self._get_raw_address(space, w_obj, offset))
+ arg = self._unwrap_object(space, w_value)
+ if arg:
+ address[0] = '\x01'
+ else:
+ address[0] = '\x00'
+
+class CharConverter(TypeConverter):
+ _immutable_ = True
+ libffitype = libffi.types.schar
+
+ def _unwrap_object(self, space, w_value):
+ # allow int to pass to char and make sure that str is of length 1
+ if space.isinstance_w(w_value, space.w_int):
+ ival = space.c_int_w(w_value)
+ if ival < 0 or 256 <= ival:
+ raise OperationError(space.w_ValueError,
+ space.wrap("char arg not in range(256)"))
+
+ value = rffi.cast(rffi.CHAR, space.c_int_w(w_value))
+ else:
+ value = space.str_w(w_value)
+
+ if len(value) != 1:
+ raise OperationError(space.w_ValueError,
+ 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, call_local):
+ x = rffi.cast(rffi.CCHARP, address)
+ x[0] = self._unwrap_object(space, w_obj)
+
+ def convert_argument_libffi(self, space, w_obj, argchain, call_local):
+ argchain.arg(self._unwrap_object(space, w_obj))
+
+ def from_memory(self, space, w_obj, w_pycppclass, offset):
+ address = rffi.cast(rffi.CCHARP, self._get_raw_address(space, w_obj, offset))
+ return space.wrap(address[0])
+
+ def to_memory(self, space, w_obj, w_value, offset):
+ address = rffi.cast(rffi.CCHARP, self._get_raw_address(space, w_obj, offset))
+ address[0] = self._unwrap_object(space, w_value)
+
+
+class ShortConverter(IntTypeConverterMixin, TypeConverter):
+ _immutable_ = True
+ libffitype = libffi.types.sshort
+ c_type = rffi.SHORT
+ c_ptrtype = rffi.SHORTP
+
+ def __init__(self, space, default):
+ self.default = rffi.cast(rffi.SHORT, capi.c_strtoll(default))
+
+ def _unwrap_object(self, space, w_obj):
+ return rffi.cast(rffi.SHORT, space.int_w(w_obj))
+
+class ConstShortRefConverter(ConstRefNumericTypeConverterMixin, ShortConverter):
+ _immutable_ = True
+ libffitype = libffi.types.pointer
+
+class UnsignedShortConverter(IntTypeConverterMixin, TypeConverter):
+ _immutable_ = True
+ libffitype = libffi.types.sshort
+ c_type = rffi.USHORT
+ c_ptrtype = rffi.USHORTP
+
+ def __init__(self, space, default):
+ self.default = rffi.cast(self.c_type, capi.c_strtoull(default))
+
+ def _unwrap_object(self, space, w_obj):
+ return rffi.cast(self.c_type, space.int_w(w_obj))
+
+class ConstUnsignedShortRefConverter(ConstRefNumericTypeConverterMixin, UnsignedShortConverter):
+ _immutable_ = True
+ libffitype = libffi.types.pointer
+
+class IntConverter(IntTypeConverterMixin, TypeConverter):
+ _immutable_ = True
+ libffitype = libffi.types.sint
+ c_type = rffi.INT
+ c_ptrtype = rffi.INTP
+
+ def __init__(self, space, default):
+ self.default = rffi.cast(self.c_type, capi.c_strtoll(default))
+
+ def _unwrap_object(self, space, w_obj):
+ return rffi.cast(self.c_type, space.c_int_w(w_obj))
+
+class ConstIntRefConverter(ConstRefNumericTypeConverterMixin, IntConverter):
+ _immutable_ = True
+ libffitype = libffi.types.pointer
+
+class UnsignedIntConverter(IntTypeConverterMixin, TypeConverter):
+ _immutable_ = True
+ libffitype = libffi.types.uint
+ c_type = rffi.UINT
+ c_ptrtype = rffi.UINTP
+
+ def __init__(self, space, default):
+ self.default = rffi.cast(self.c_type, capi.c_strtoull(default))
+
+ def _unwrap_object(self, space, w_obj):
+ return rffi.cast(self.c_type, space.uint_w(w_obj))
+
+class ConstUnsignedIntRefConverter(ConstRefNumericTypeConverterMixin, UnsignedIntConverter):
+ _immutable_ = True
+ libffitype = libffi.types.pointer
+
+class LongConverter(IntTypeConverterMixin, TypeConverter):
+ _immutable_ = True
+ libffitype = libffi.types.slong
+ c_type = rffi.LONG
+ c_ptrtype = rffi.LONGP
+
+ def __init__(self, space, default):
+ self.default = rffi.cast(self.c_type, capi.c_strtoll(default))
+
+ def _unwrap_object(self, space, w_obj):
+ return space.int_w(w_obj)
+
+class ConstLongRefConverter(ConstRefNumericTypeConverterMixin, LongConverter):
+ _immutable_ = True
+ libffitype = libffi.types.pointer
+ typecode = 'r'
+
+ 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)
+ ba[capi.c_function_arg_typeoffset()] = self.typecode
+
+class LongLongConverter(IntTypeConverterMixin, TypeConverter):
+ _immutable_ = True
+ libffitype = libffi.types.slong
+ c_type = rffi.LONGLONG
+ c_ptrtype = rffi.LONGLONGP
+
+ def __init__(self, space, default):
+ self.default = rffi.cast(self.c_type, capi.c_strtoll(default))
+
+ def _unwrap_object(self, space, w_obj):
+ return space.r_longlong_w(w_obj)
+
+class ConstLongLongRefConverter(ConstRefNumericTypeConverterMixin, LongLongConverter):
+ _immutable_ = True
+ libffitype = libffi.types.pointer
+ typecode = 'r'
+
+ 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)
+ ba[capi.c_function_arg_typeoffset()] = self.typecode
+
+class UnsignedLongConverter(IntTypeConverterMixin, TypeConverter):
+ _immutable_ = True
+ libffitype = libffi.types.ulong
+ c_type = rffi.ULONG
+ c_ptrtype = rffi.ULONGP
+
+ def __init__(self, space, default):
+ self.default = rffi.cast(self.c_type, capi.c_strtoull(default))
+
+ def _unwrap_object(self, space, w_obj):
+ return space.uint_w(w_obj)
+
+class ConstUnsignedLongRefConverter(ConstRefNumericTypeConverterMixin, UnsignedLongConverter):
+ _immutable_ = True
+ libffitype = libffi.types.pointer
+
+class UnsignedLongLongConverter(IntTypeConverterMixin, TypeConverter):
+ _immutable_ = True
+ libffitype = libffi.types.ulong
+ c_type = rffi.ULONGLONG
+ c_ptrtype = rffi.ULONGLONGP
+
+ def __init__(self, space, default):
+ self.default = rffi.cast(self.c_type, capi.c_strtoull(default))
+
+ def _unwrap_object(self, space, w_obj):
+ return space.r_ulonglong_w(w_obj)
+
+class ConstUnsignedLongLongRefConverter(ConstRefNumericTypeConverterMixin, UnsignedLongLongConverter):
+ _immutable_ = True
+ libffitype = libffi.types.pointer
+
+
+class FloatConverter(FloatTypeConverterMixin, TypeConverter):
+ _immutable_ = True
+ libffitype = libffi.types.float
+ c_type = rffi.FLOAT
+ c_ptrtype = rffi.FLOATP
+ typecode = 'f'
+
+ def __init__(self, space, default):
+ if default:
+ fval = float(rfloat.rstring_to_float(default))
+ else:
+ fval = float(0.)
+ self.default = r_singlefloat(fval)
+
+ def _unwrap_object(self, space, w_obj):
+ return r_singlefloat(space.float_w(w_obj))
+
+ def from_memory(self, space, w_obj, w_pycppclass, offset):
+ address = self._get_raw_address(space, w_obj, offset)
+ rffiptr = rffi.cast(self.c_ptrtype, address)
+ return space.wrap(float(rffiptr[0]))
+
+class ConstFloatRefConverter(FloatConverter):
+ _immutable_ = True
+ libffitype = libffi.types.pointer
+ typecode = 'F'
+
+ def convert_argument_libffi(self, space, w_obj, argchain, call_local):
+ from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
+ raise FastCallNotPossible
+
+class DoubleConverter(FloatTypeConverterMixin, TypeConverter):
+ _immutable_ = True
+ libffitype = libffi.types.double
+ c_type = rffi.DOUBLE
+ c_ptrtype = rffi.DOUBLEP
+ typecode = 'd'
+
+ def __init__(self, space, default):
+ if default:
+ self.default = rffi.cast(self.c_type, rfloat.rstring_to_float(default))
+ else:
+ self.default = rffi.cast(self.c_type, 0.)
+
+ def _unwrap_object(self, space, w_obj):
+ return space.float_w(w_obj)
+
+class ConstDoubleRefConverter(ConstRefNumericTypeConverterMixin, DoubleConverter):
+ _immutable_ = True
+ libffitype = libffi.types.pointer
+ typecode = 'D'
+
+
+class CStringConverter(TypeConverter):
+ _immutable_ = True
+
+ 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))
+ ba = rffi.cast(rffi.CCHARP, address)
+ ba[capi.c_function_arg_typeoffset()] = 'o'
+
+ def from_memory(self, space, w_obj, w_pycppclass, offset):
+ address = self._get_raw_address(space, w_obj, offset)
+ charpptr = rffi.cast(rffi.CCHARPP, address)
+ return space.wrap(rffi.charp2str(charpptr[0]))
+
+ def free_argument(self, space, 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, 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)
+ ba[capi.c_function_arg_typeoffset()] = 'a'
+
+ def convert_argument_libffi(self, space, w_obj, argchain, call_local):
+ argchain.arg(get_rawobject(space, w_obj))
+
+class VoidPtrPtrConverter(TypeConverter):
+ _immutable_ = True
+ uses_local = True
+
+ 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, call_local)
+ address = rffi.cast(capi.C_OBJECT, address)
+ ba = rffi.cast(rffi.CCHARP, address)
+ 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, 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)
+ ba[capi.c_function_arg_typeoffset()] = 'r'
+
+
+class InstancePtrConverter(TypeConverter):
+ _immutable_ = True
+
+ def __init__(self, space, cppclass):
+ from pypy.module.cppyy.interp_cppyy import W_CPPClass
+ assert isinstance(cppclass, W_CPPClass)
+ self.cppclass = cppclass
+
+ def _unwrap_object(self, space, w_obj):
+ from pypy.module.cppyy.interp_cppyy import W_CPPInstance
+ obj = space.interpclass_w(w_obj)
+ if isinstance(obj, W_CPPInstance):
+ if capi.c_is_subtype(obj.cppclass, self.cppclass):
+ rawobject = obj.get_rawobject()
+ offset = capi.c_base_offset(obj.cppclass, self.cppclass, rawobject, 1)
+ obj_address = capi.direct_ptradd(rawobject, offset)
+ return rffi.cast(capi.C_OBJECT, obj_address)
+ raise OperationError(space.w_TypeError,
+ space.wrap("cannot pass %s as %s" %
+ (space.type(w_obj).getname(space, "?"), self.cppclass.name)))
+
+ 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)
+ ba = rffi.cast(rffi.CCHARP, address)
+ ba[capi.c_function_arg_typeoffset()] = 'o'
+
+ def convert_argument_libffi(self, space, w_obj, argchain, call_local):
+ argchain.arg(self._unwrap_object(space, w_obj))
+
+ def from_memory(self, space, w_obj, w_pycppclass, 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.wrap_cppobject_nocast(
+ space, w_pycppclass, self.cppclass, address, isref=True, python_owns=False)
+
+ def to_memory(self, space, w_obj, w_value, offset):
+ address = rffi.cast(rffi.VOIDPP, self._get_raw_address(space, w_obj, offset))
+ address[0] = rffi.cast(rffi.VOIDP, self._unwrap_object(space, w_value))
+
+class InstanceConverter(InstancePtrConverter):
+ _immutable_ = True
+
+ def from_memory(self, space, w_obj, w_pycppclass, 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.wrap_cppobject_nocast(
+ space, w_pycppclass, self.cppclass, address, isref=False, python_owns=False)
+
+ def to_memory(self, space, w_obj, w_value, offset):
+ self._is_abstract(space)
+
+class InstancePtrPtrConverter(InstancePtrConverter):
+ _immutable_ = True
+ uses_local = 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
+
+ def __init__(self, space, extra):
+ from pypy.module.cppyy import interp_cppyy
+ cppclass = interp_cppyy.scope_byname(space, "std::string")
+ InstanceConverter.__init__(self, space, cppclass)
+
+ def _unwrap_object(self, space, w_obj):
+ try:
+ charp = rffi.str2charp(space.str_w(w_obj))
+ arg = capi.c_charp2stdstring(charp)
+ rffi.free_charp(charp)
+ return arg
+ except OperationError:
+ arg = InstanceConverter._unwrap_object(self, space, w_obj)
+ return capi.c_stdstring2stdstring(arg)
+
+ def to_memory(self, space, w_obj, w_value, offset):
+ try:
+ address = rffi.cast(capi.C_OBJECT, self._get_raw_address(space, w_obj, offset))
+ charp = rffi.str2charp(space.str_w(w_value))
+ capi.c_assign2stdstring(address, charp)
+ rffi.free_charp(charp)
+ return
+ except Exception:
+ pass
+ return InstanceConverter.to_memory(self, space, w_obj, w_value, offset)
+
+ 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):
+ _immutable_ = True
+
+ def __init__(self, space, extra):
+ from pypy.module.cppyy import interp_cppyy
+ cppclass = interp_cppyy.scope_byname(space, "std::string")
+ 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):
+ # The matching of the name to a converter should follow:
+ # 1) full, exact match
+ # 1a) const-removed match
+ # 2) match of decorated, unqualified type
+ # 3) accept ref as pointer (for the stubs, const& can be
+ # by value, but that does not work for the ffi path)
+ # 4) generalized cases (covers basically all user classes)
+ # 5) void converter, which fails on use
+
+ name = capi.c_resolve_name(name)
+
+ # 1) full, exact match
+ try:
+ return _converters[name](space, default)
+ except KeyError:
+ pass
+
+ # 1a) const-removed match
+ try:
+ return _converters[helper.remove_const(name)](space, default)
+ except KeyError:
+ pass
+
+ # 2) match of decorated, unqualified type
+ compound = helper.compound(name)
+ clean_name = helper.clean_type(name)
+ try:
+ # array_index may be negative to indicate no size or no size found
+ array_size = helper.array_size(name)
+ return _a_converters[clean_name+compound](space, array_size)
+ except KeyError:
+ pass
+
+ # 3) TODO: accept ref as pointer
+
+ # 4) generalized cases (covers basically all user classes)
+ from pypy.module.cppyy import interp_cppyy
+ cppclass = interp_cppyy.scope_byname(space, clean_name)
+ if cppclass:
+ # type check for the benefit of the annotator
+ from pypy.module.cppyy.interp_cppyy import W_CPPClass
+ 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):
+ return UnsignedIntConverter(space, default)
+
+ # 5) void converter, which fails on use
+ #
+ # return a void converter here, so that the class can be build even
+ # when some types are unknown; this overload will simply fail on use
+ return VoidConverter(space, name)
+
+
+_converters["bool"] = BoolConverter
+_converters["char"] = CharConverter
+_converters["unsigned char"] = CharConverter
+_converters["short int"] = ShortConverter
+_converters["const short int&"] = ConstShortRefConverter
+_converters["short"] = _converters["short int"]
+_converters["const short&"] = _converters["const short int&"]
+_converters["unsigned short int"] = UnsignedShortConverter
+_converters["const unsigned short int&"] = ConstUnsignedShortRefConverter
+_converters["unsigned short"] = _converters["unsigned short int"]
+_converters["const unsigned short&"] = _converters["const unsigned short int&"]
+_converters["int"] = IntConverter
+_converters["const int&"] = ConstIntRefConverter
+_converters["unsigned int"] = UnsignedIntConverter
+_converters["const unsigned int&"] = ConstUnsignedIntRefConverter
+_converters["long int"] = LongConverter
+_converters["const long int&"] = ConstLongRefConverter
+_converters["long"] = _converters["long int"]
+_converters["const long&"] = _converters["const long int&"]
+_converters["unsigned long int"] = UnsignedLongConverter
+_converters["const unsigned long int&"] = ConstUnsignedLongRefConverter
+_converters["unsigned long"] = _converters["unsigned long int"]
+_converters["const unsigned long&"] = _converters["const unsigned long int&"]
+_converters["long long int"] = LongLongConverter
+_converters["const long long int&"] = ConstLongLongRefConverter
+_converters["long long"] = _converters["long long int"]
+_converters["const long long&"] = _converters["const long long int&"]
+_converters["unsigned long long int"] = UnsignedLongLongConverter
+_converters["const unsigned long long int&"] = ConstUnsignedLongLongRefConverter
+_converters["unsigned long long"] = _converters["unsigned long long int"]
+_converters["const unsigned long long&"] = _converters["const unsigned long long int&"]
+_converters["float"] = FloatConverter
+_converters["const float&"] = ConstFloatRefConverter
+_converters["double"] = DoubleConverter
+_converters["const double&"] = ConstDoubleRefConverter
+_converters["const char*"] = CStringConverter
+_converters["char*"] = CStringConverter
+_converters["void*"] = VoidPtrConverter
+_converters["void**"] = VoidPtrPtrConverter
+_converters["void*&"] = VoidPtrRefConverter
+
+# special cases (note: CINT backend requires the simple name 'string')
+_converters["std::basic_string<char>"] = StdStringConverter
+_converters["string"] = _converters["std::basic_string<char>"]
+_converters["const std::basic_string<char>&"] = StdStringConverter # TODO: shouldn't copy
+_converters["const string&"] = _converters["const std::basic_string<char>&"]
+_converters["std::basic_string<char>&"] = StdStringRefConverter
+_converters["string&"] = _converters["std::basic_string<char>&"]
+
+_converters["PyObject*"] = PyObjectConverter
+_converters["_object*"] = _converters["PyObject*"]
+
+def _build_array_converters():
+ "NOT_RPYTHON"
+ array_info = (
+ ('h', rffi.sizeof(rffi.SHORT), ("short int", "short")),
+ ('H', rffi.sizeof(rffi.USHORT), ("unsigned short int", "unsigned short")),
+ ('i', rffi.sizeof(rffi.INT), ("int",)),
+ ('I', rffi.sizeof(rffi.UINT), ("unsigned int", "unsigned")),
+ ('l', rffi.sizeof(rffi.LONG), ("long int", "long")),
+ ('L', rffi.sizeof(rffi.ULONG), ("unsigned long int", "unsigned long")),
+ ('f', rffi.sizeof(rffi.FLOAT), ("float",)),
+ ('d', rffi.sizeof(rffi.DOUBLE), ("double",)),
+ )
+
+ for info in array_info:
+ class ArrayConverter(ArrayTypeConverterMixin, TypeConverter):
+ _immutable_ = True
+ typecode = info[0]
+ typesize = info[1]
+ class PtrConverter(PtrTypeConverterMixin, TypeConverter):
+ _immutable_ = True
+ typecode = info[0]
+ typesize = info[1]
+ for name in info[2]:
+ _a_converters[name+'[]'] = ArrayConverter
+ _a_converters[name+'*'] = PtrConverter
+_build_array_converters()
diff --git a/pypy/module/cppyy/executor.py b/pypy/module/cppyy/executor.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/executor.py
@@ -0,0 +1,466 @@
+import sys
+
+from pypy.interpreter.error import OperationError
+
+from pypy.rpython.lltypesystem import rffi, lltype
+from pypy.rlib import libffi, clibffi
+
+from pypy.module._rawffi.interp_rawffi import unpack_simple_shape
+from pypy.module._rawffi.array import W_Array
+
+from pypy.module.cppyy import helper, capi
+
+
+NULL = lltype.nullptr(clibffi.FFI_TYPE_P.TO)
+
+class FunctionExecutor(object):
+ _immutable_ = True
+ libffitype = NULL
+
+ def __init__(self, space, extra):
+ pass
+
+ def execute(self, space, cppmethod, cppthis, num_args, args):
+ raise OperationError(space.w_TypeError,
+ space.wrap('return type not available or supported'))
+
+ def execute_libffi(self, space, libffifunc, argchain):
+ from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
+ raise FastCallNotPossible
+
+
+class PtrTypeExecutor(FunctionExecutor):
+ _immutable_ = True
+ typecode = 'P'
+
+ 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)
+ address = rffi.cast(rffi.ULONG, lresult)
+ arr = space.interp_w(W_Array, unpack_simple_shape(space, space.wrap(self.typecode)))
+ return arr.fromaddress(space, address, sys.maxint)
+
+
+class VoidExecutor(FunctionExecutor):
+ _immutable_ = True
+ libffitype = libffi.types.void
+
+ def execute(self, space, cppmethod, cppthis, num_args, args):
+ capi.c_call_v(cppmethod, cppthis, num_args, args)
+ return space.w_None
+
+ def execute_libffi(self, space, libffifunc, argchain):
+ libffifunc.call(argchain, lltype.Void)
+ return space.w_None
+
+
+class BoolExecutor(FunctionExecutor):
+ _immutable_ = True
+ libffitype = libffi.types.schar
+
+ def execute(self, space, cppmethod, cppthis, num_args, args):
+ result = capi.c_call_b(cppmethod, cppthis, num_args, args)
+ return space.wrap(result)
+
+ def execute_libffi(self, space, libffifunc, argchain):
+ result = libffifunc.call(argchain, rffi.CHAR)
+ return space.wrap(bool(ord(result)))
+
+class CharExecutor(FunctionExecutor):
+ _immutable_ = True
+ libffitype = libffi.types.schar
+
+ def execute(self, space, cppmethod, cppthis, num_args, args):
+ result = capi.c_call_c(cppmethod, cppthis, num_args, args)
+ return space.wrap(result)
+
+ def execute_libffi(self, space, libffifunc, argchain):
+ result = libffifunc.call(argchain, rffi.CHAR)
+ return space.wrap(result)
+
+class ShortExecutor(FunctionExecutor):
+ _immutable_ = True
+ libffitype = libffi.types.sshort
+
+ def execute(self, space, cppmethod, cppthis, num_args, args):
+ result = capi.c_call_h(cppmethod, cppthis, num_args, args)
+ return space.wrap(result)
+
+ def execute_libffi(self, space, libffifunc, argchain):
+ result = libffifunc.call(argchain, rffi.SHORT)
+ return space.wrap(result)
+
+class IntExecutor(FunctionExecutor):
+ _immutable_ = True
+ libffitype = libffi.types.sint
+
+ def _wrap_result(self, space, result):
+ return space.wrap(result)
+
+ def execute(self, space, cppmethod, cppthis, num_args, args):
+ result = capi.c_call_i(cppmethod, cppthis, num_args, args)
+ return self._wrap_result(space, result)
+
+ def execute_libffi(self, space, libffifunc, argchain):
+ result = libffifunc.call(argchain, rffi.INT)
+ return space.wrap(result)
+
+class UnsignedIntExecutor(FunctionExecutor):
+ _immutable_ = True
+ libffitype = libffi.types.uint
+
+ def _wrap_result(self, space, result):
+ return space.wrap(rffi.cast(rffi.UINT, result))
+
+ def execute(self, space, cppmethod, cppthis, num_args, args):
+ result = capi.c_call_l(cppmethod, cppthis, num_args, args)
+ return self._wrap_result(space, result)
+
+ def execute_libffi(self, space, libffifunc, argchain):
+ result = libffifunc.call(argchain, rffi.UINT)
+ return space.wrap(result)
+
+class LongExecutor(FunctionExecutor):
+ _immutable_ = True
+ libffitype = libffi.types.slong
+
+ def _wrap_result(self, space, result):
+ return space.wrap(result)
+
+ def execute(self, space, cppmethod, cppthis, num_args, args):
+ result = capi.c_call_l(cppmethod, cppthis, num_args, args)
+ return self._wrap_result(space, result)
+
+ def execute_libffi(self, space, libffifunc, argchain):
+ result = libffifunc.call(argchain, rffi.LONG)
+ return space.wrap(result)
+
+class UnsignedLongExecutor(LongExecutor):
+ _immutable_ = True
+ libffitype = libffi.types.ulong
+
+ def _wrap_result(self, space, result):
+ return space.wrap(rffi.cast(rffi.ULONG, result))
+
+ def execute_libffi(self, space, libffifunc, argchain):
+ result = libffifunc.call(argchain, rffi.ULONG)
+ return space.wrap(result)
+
+class LongLongExecutor(FunctionExecutor):
+ _immutable_ = True
+ libffitype = libffi.types.sint64
+
+ def _wrap_result(self, space, result):
+ return space.wrap(result)
+
+ def execute(self, space, cppmethod, cppthis, num_args, args):
+ result = capi.c_call_ll(cppmethod, cppthis, num_args, args)
+ return self._wrap_result(space, result)
+
+ def execute_libffi(self, space, libffifunc, argchain):
+ result = libffifunc.call(argchain, rffi.LONGLONG)
+ return space.wrap(result)
+
+class UnsignedLongLongExecutor(LongLongExecutor):
+ _immutable_ = True
+ libffitype = libffi.types.uint64
+
+ def _wrap_result(self, space, result):
+ return space.wrap(rffi.cast(rffi.ULONGLONG, result))
+
+ def execute_libffi(self, space, libffifunc, argchain):
+ result = libffifunc.call(argchain, rffi.ULONGLONG)
+ return space.wrap(result)
+
+class ConstIntRefExecutor(FunctionExecutor):
+ _immutable_ = True
+ libffitype = libffi.types.pointer
+
+ def _wrap_result(self, space, result):
+ intptr = rffi.cast(rffi.INTP, result)
+ return space.wrap(intptr[0])
+
+ def execute(self, space, cppmethod, cppthis, num_args, args):
+ result = capi.c_call_r(cppmethod, cppthis, num_args, args)
+ return self._wrap_result(space, result)
+
+ def execute_libffi(self, space, libffifunc, argchain):
+ result = libffifunc.call(argchain, rffi.INTP)
+ return space.wrap(result[0])
+
+class ConstLongRefExecutor(ConstIntRefExecutor):
+ _immutable_ = True
+ libffitype = libffi.types.pointer
+
+ def _wrap_result(self, space, result):
+ longptr = rffi.cast(rffi.LONGP, result)
+ return space.wrap(longptr[0])
+
+ def execute_libffi(self, space, libffifunc, argchain):
+ result = libffifunc.call(argchain, rffi.LONGP)
+ return space.wrap(result[0])
+
+class FloatExecutor(FunctionExecutor):
+ _immutable_ = True
+ libffitype = libffi.types.float
+
+ def execute(self, space, cppmethod, cppthis, num_args, args):
+ result = capi.c_call_f(cppmethod, cppthis, num_args, args)
+ return space.wrap(float(result))
+
+ def execute_libffi(self, space, libffifunc, argchain):
+ result = libffifunc.call(argchain, rffi.FLOAT)
+ return space.wrap(float(result))
+
+class DoubleExecutor(FunctionExecutor):
+ _immutable_ = True
+ libffitype = libffi.types.double
+
+ def execute(self, space, cppmethod, cppthis, num_args, args):
+ result = capi.c_call_d(cppmethod, cppthis, num_args, args)
+ return space.wrap(result)
+
+ def execute_libffi(self, space, libffifunc, argchain):
+ result = libffifunc.call(argchain, rffi.DOUBLE)
+ return space.wrap(result)
+
+
+class CStringExecutor(FunctionExecutor):
+ _immutable_ = True
+
+ def execute(self, space, cppmethod, cppthis, num_args, args):
+ lresult = capi.c_call_l(cppmethod, cppthis, num_args, args)
+ ccpresult = rffi.cast(rffi.CCHARP, lresult)
+ result = rffi.charp2str(ccpresult) # TODO: make it a choice to free
+ return space.wrap(result)
+
+
+class ShortPtrExecutor(PtrTypeExecutor):
+ _immutable_ = True
+ typecode = 'h'
+
+class IntPtrExecutor(PtrTypeExecutor):
+ _immutable_ = True
+ typecode = 'i'
+
+class UnsignedIntPtrExecutor(PtrTypeExecutor):
+ _immutable_ = True
+ typecode = 'I'
+
+class LongPtrExecutor(PtrTypeExecutor):
+ _immutable_ = True
+ typecode = 'l'
+
+class UnsignedLongPtrExecutor(PtrTypeExecutor):
+ _immutable_ = True
+ typecode = 'L'
+
+class FloatPtrExecutor(PtrTypeExecutor):
+ _immutable_ = True
+ typecode = 'f'
+
+class DoublePtrExecutor(PtrTypeExecutor):
+ _immutable_ = True
+ typecode = 'd'
+
+
+class ConstructorExecutor(VoidExecutor):
+ _immutable_ = True
+
+ def execute(self, space, cppmethod, cppthis, num_args, args):
+ capi.c_constructor(cppmethod, cppthis, num_args, args)
+ return space.w_None
+
+
+class InstancePtrExecutor(FunctionExecutor):
+ _immutable_ = True
+ libffitype = libffi.types.pointer
+
+ def __init__(self, space, cppclass):
+ FunctionExecutor.__init__(self, space, cppclass)
+ self.cppclass = cppclass
+
+ def execute(self, space, cppmethod, cppthis, num_args, args):
+ 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.wrap_cppobject(
+ space, space.w_None, self.cppclass, ptr_result, isref=False, python_owns=False)
+
+ def execute_libffi(self, space, libffifunc, argchain):
+ from pypy.module.cppyy import interp_cppyy
+ ptr_result = rffi.cast(capi.C_OBJECT, libffifunc.call(argchain, rffi.VOIDP))
+ return interp_cppyy.wrap_cppobject(
+ space, space.w_None, self.cppclass, ptr_result, isref=False, python_owns=False)
+
+class InstancePtrPtrExecutor(InstancePtrExecutor):
+ _immutable_ = True
+
+ def execute(self, space, cppmethod, cppthis, num_args, args):
+ from pypy.module.cppyy import interp_cppyy
+ 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.wrap_cppobject(
+ space, space.w_None, self.cppclass, ptr_result, isref=False, python_owns=False)
+
+ def execute_libffi(self, space, libffifunc, argchain):
+ from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
+ raise FastCallNotPossible
+
+class InstanceExecutor(InstancePtrExecutor):
+ _immutable_ = True
+
+ def execute(self, space, cppmethod, cppthis, num_args, args):
+ from pypy.module.cppyy import interp_cppyy
+ long_result = capi.c_call_o(cppmethod, cppthis, num_args, args, self.cppclass)
+ ptr_result = rffi.cast(capi.C_OBJECT, long_result)
+ return interp_cppyy.wrap_cppobject(
+ space, space.w_None, self.cppclass, ptr_result, isref=False, python_owns=True)
+
+ def execute_libffi(self, space, libffifunc, argchain):
+ from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
+ raise FastCallNotPossible
+
+
+class StdStringExecutor(InstancePtrExecutor):
+ _immutable_ = True
+
+ def execute(self, space, cppmethod, cppthis, num_args, args):
+ charp_result = capi.c_call_s(cppmethod, cppthis, num_args, args)
+ return space.wrap(capi.charp2str_free(charp_result))
+
+ def execute_libffi(self, space, libffifunc, argchain):
+ from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
+ 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:
+ # 1) full, qualified match
+ # 2) drop '&': by-ref is pretty much the same as by-value, python-wise
+ # 3) types/classes, either by ref/ptr or by value
+ # 4) additional special cases
+ #
+ # If all fails, a default is used, which can be ignored at least until use.
+
+ name = capi.c_resolve_name(name)
+
+ # 1) full, qualified match
+ try:
+ return _executors[name](space, None)
+ except KeyError:
+ pass
+
+ compound = helper.compound(name)
+ clean_name = helper.clean_type(name)
+
+ # 1a) clean lookup
+ try:
+ return _executors[clean_name+compound](space, None)
+ except KeyError:
+ pass
+
+ # 2) drop '&': by-ref is pretty much the same as by-value, python-wise
+ if compound and compound[len(compound)-1] == "&":
+ # TODO: this does not actually work with Reflex (?)
+ try:
+ return _executors[clean_name](space, None)
+ except KeyError:
+ pass
+
+ # 3) types/classes, either by ref/ptr or by value
+ from pypy.module.cppyy import interp_cppyy
+ cppclass = interp_cppyy.scope_byname(space, clean_name)
+ if cppclass:
+ # type check for the benefit of the annotator
+ from pypy.module.cppyy.interp_cppyy import W_CPPClass
+ cppclass = space.interp_w(W_CPPClass, cppclass, can_be_None=False)
+ if compound == "":
+ return InstanceExecutor(space, cppclass)
+ elif compound == "*" or compound == "&":
+ return InstancePtrExecutor(space, cppclass)
+ elif compound == "**" or compound == "*&":
+ return InstancePtrPtrExecutor(space, cppclass)
+ elif capi.c_is_enum(clean_name):
+ return UnsignedIntExecutor(space, None)
+
+ # 4) additional special cases
+ # ... none for now
+
+ # currently used until proper lazy instantiation available in interp_cppyy
+ return FunctionExecutor(space, None)
+
+
+_executors["void"] = VoidExecutor
+_executors["void*"] = PtrTypeExecutor
+_executors["bool"] = BoolExecutor
+_executors["char"] = CharExecutor
+_executors["char*"] = CStringExecutor
+_executors["unsigned char"] = CharExecutor
+_executors["short int"] = ShortExecutor
+_executors["short"] = _executors["short int"]
+_executors["short int*"] = ShortPtrExecutor
+_executors["short*"] = _executors["short int*"]
+_executors["unsigned short int"] = ShortExecutor
+_executors["unsigned short"] = _executors["unsigned short int"]
+_executors["unsigned short int*"] = ShortPtrExecutor
+_executors["unsigned short*"] = _executors["unsigned short int*"]
+_executors["int"] = IntExecutor
+_executors["int*"] = IntPtrExecutor
+_executors["const int&"] = ConstIntRefExecutor
+_executors["int&"] = ConstIntRefExecutor
+_executors["unsigned int"] = UnsignedIntExecutor
+_executors["unsigned int*"] = UnsignedIntPtrExecutor
+_executors["long int"] = LongExecutor
+_executors["long"] = _executors["long int"]
+_executors["long int*"] = LongPtrExecutor
+_executors["long*"] = _executors["long int*"]
+_executors["unsigned long int"] = UnsignedLongExecutor
+_executors["unsigned long"] = _executors["unsigned long int"]
+_executors["unsigned long int*"] = UnsignedLongPtrExecutor
+_executors["unsigned long*"] = _executors["unsigned long int*"]
+_executors["long long int"] = LongLongExecutor
+_executors["long long"] = _executors["long long int"]
+_executors["unsigned long long int"] = UnsignedLongLongExecutor
+_executors["unsigned long long"] = _executors["unsigned long long int"]
+_executors["float"] = FloatExecutor
+_executors["float*"] = FloatPtrExecutor
+_executors["double"] = DoubleExecutor
+_executors["double*"] = DoublePtrExecutor
+
+_executors["constructor"] = ConstructorExecutor
+
+# 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/genreflex-methptrgetter.patch b/pypy/module/cppyy/genreflex-methptrgetter.patch
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/genreflex-methptrgetter.patch
@@ -0,0 +1,126 @@
+Index: cint/reflex/python/genreflex/gendict.py
+===================================================================
+--- cint/reflex/python/genreflex/gendict.py (revision 43705)
++++ cint/reflex/python/genreflex/gendict.py (working copy)
+@@ -52,6 +52,7 @@
+ self.typedefs_for_usr = []
+ self.gccxmlvers = gccxmlvers
+ self.split = opts.get('split', '')
++ self.with_methptrgetter = opts.get('with_methptrgetter', False)
+ # The next is to avoid a known problem with gccxml that it generates a
+ # references to id equal '_0' which is not defined anywhere
+ self.xref['_0'] = {'elem':'Unknown', 'attrs':{'id':'_0','name':''}, 'subelems':[]}
+@@ -1306,6 +1307,8 @@
+ bases = self.getBases( attrs['id'] )
+ if inner and attrs.has_key('demangled') and self.isUnnamedType(attrs['demangled']) :
+ cls = attrs['demangled']
++ if self.xref[attrs['id']]['elem'] == 'Union':
++ return 80*' '
+ clt = ''
+ else:
+ cls = self.genTypeName(attrs['id'],const=True,colon=True)
+@@ -1343,7 +1346,7 @@
+ # Inner class/struct/union/enum.
+ for m in memList :
+ member = self.xref[m]
+- if member['elem'] in ('Class','Struct','Union','Enumeration') \
++ if member['elem'] in ('Class','Struct','Enumeration') \
+ and member['attrs'].get('access') in ('private','protected') \
+ and not self.isUnnamedType(member['attrs'].get('demangled')):
+ cmem = self.genTypeName(member['attrs']['id'],const=True,colon=True)
+@@ -1981,8 +1984,15 @@
+ else : params = '0'
+ s = ' .AddFunctionMember(%s, Reflex::Literal("%s"), %s%s, 0, %s, %s)' % (self.genTypeID(id), name, type, id, params, mod)
+ s += self.genCommentProperty(attrs)
++ s += self.genMethPtrGetterProperty(type, attrs)
+ return s
+ #----------------------------------------------------------------------------------
++ def genMethPtrGetterProperty(self, type, attrs):
++ funcname = self.nameOfMethPtrGetter(type, attrs)
++ if funcname is None:
++ return ''
++ return '\n .AddProperty("MethPtrGetter", (void*)%s)' % funcname
++#----------------------------------------------------------------------------------
+ def genMCODef(self, type, name, attrs, args):
+ id = attrs['id']
+ cl = self.genTypeName(attrs['context'],colon=True)
+@@ -2049,8 +2059,44 @@
+ if returns == 'void' : body += ' }\n'
+ else : body += ' }\n'
+ body += '}\n'
+- return head + body;
++ methptrgetter = self.genMethPtrGetter(type, name, attrs, args)
++ return head + body + methptrgetter
+ #----------------------------------------------------------------------------------
++ def nameOfMethPtrGetter(self, type, attrs):
++ id = attrs['id']
++ if self.with_methptrgetter and 'static' not in attrs and type in ('operator', 'method'):
++ return '%s%s_methptrgetter' % (type, id)
++ return None
++#----------------------------------------------------------------------------------
++ def genMethPtrGetter(self, type, name, attrs, args):
++ funcname = self.nameOfMethPtrGetter(type, attrs)
++ if funcname is None:
++ return ''
++ id = attrs['id']
++ cl = self.genTypeName(attrs['context'],colon=True)
++ rettype = self.genTypeName(attrs['returns'],enum=True, const=True, colon=True)
++ arg_type_list = [self.genTypeName(arg['type'], colon=True) for arg in args]
++ constness = attrs.get('const', 0) and 'const' or ''
++ lines = []
++ a = lines.append
++ a('static void* %s(void* o)' % (funcname,))
++ a('{')
++ if name == 'EmitVA':
++ # TODO: this is for ROOT TQObject, the problem being that ellipses is not
++ # exposed in the arguments and that makes the generated code fail if the named
++ # method is overloaded as is with TQObject::EmitVA
++ a(' return (void*)0;')
++ else:
++ # declare a variable "meth" which is a member pointer
++ a(' %s (%s::*meth)(%s)%s;' % (rettype, cl, ', '.join(arg_type_list), constness))
++ a(' meth = (%s (%s::*)(%s)%s)&%s::%s;' % \
++ (rettype, cl, ', '.join(arg_type_list), constness, cl, name))
++ a(' %s* obj = (%s*)o;' % (cl, cl))
++ a(' return (void*)(obj->*meth);')
++ a('}')
++ return '\n'.join(lines)
++
++#----------------------------------------------------------------------------------
+ def getDefaultArgs(self, args):
+ n = 0
+ for a in args :
+Index: cint/reflex/python/genreflex/genreflex.py
+===================================================================
+--- cint/reflex/python/genreflex/genreflex.py (revision 43705)
++++ cint/reflex/python/genreflex/genreflex.py (working copy)
+@@ -108,6 +108,10 @@
+ Print extra debug information while processing. Keep intermediate files\n
+ --quiet
+ Do not print informational messages\n
++ --with-methptrgetter
++ Add the property MethPtrGetter to every FunctionMember. It contains a pointer to a
++ function which you can call to get the actual function pointer of the method that it's
++ stored in the vtable. It works only with gcc.
+ -h, --help
+ Print this help\n
+ """
+@@ -127,7 +131,8 @@
+ opts, args = getopt.getopt(options, 'ho:s:c:I:U:D:PC', \
+ ['help','debug=', 'output=','selection_file=','pool','dataonly','interpreteronly','deep','gccxmlpath=',
+ 'capabilities=','rootmap=','rootmap-lib=','comments','iocomments','no_membertypedefs',
+- 'fail_on_warnings', 'quiet', 'gccxmlopt=', 'reflex', 'split=','no_templatetypedefs','gccxmlpost='])
++ 'fail_on_warnings', 'quiet', 'gccxmlopt=', 'reflex', 'split=','no_templatetypedefs','gccxmlpost=',
++ 'with-methptrgetter'])
+ except getopt.GetoptError, e:
+ print "--->> genreflex: ERROR:",e
+ self.usage(2)
+@@ -186,6 +191,8 @@
+ self.rootmap = a
+ if o in ('--rootmap-lib',):
+ self.rootmaplib = a
++ if o in ('--with-methptrgetter',):
++ self.opts['with_methptrgetter'] = True
+ if o in ('-I', '-U', '-D', '-P', '-C') :
+ # escape quotes; we need to use " because of windows cmd
+ poseq = a.find('=')
diff --git a/pypy/module/cppyy/helper.py b/pypy/module/cppyy/helper.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/helper.py
@@ -0,0 +1,179 @@
+from pypy.rlib import rstring
+
+
+#- type name manipulations --------------------------------------------------
+def _remove_const(name):
+ return "".join(rstring.split(name, "const")) # poor man's replace
+
+def remove_const(name):
+ return _remove_const(name).strip(' ')
+
+def compound(name):
+ name = _remove_const(name)
+ if name.endswith("]"): # array type?
+ return "[]"
+ i = _find_qualifier_index(name)
+ return "".join(name[i:].split(" "))
+
+def array_size(name):
+ name = _remove_const(name)
+ if name.endswith("]"): # array type?
+ idx = name.rfind("[")
+ if 0 < idx:
+ end = len(name)-1 # len rather than -1 for rpython
+ if 0 < end and (idx+1) < end: # guarantee non-neg for rpython
+ return int(name[idx+1:end])
+ return -1
+
+def _find_qualifier_index(name):
+ i = len(name)
+ # search from the back; note len(name) > 0 (so rtyper can use uint)
+ for i in range(len(name) - 1, 0, -1):
+ c = name[i]
+ if c.isalnum() or c == ">" or c == "]":
+ break
+ return i + 1
+
+def clean_type(name):
+ # can't strip const early b/c name could be a template ...
+ i = _find_qualifier_index(name)
+ name = name[:i].strip(' ')
+
+ idx = -1
+ if name.endswith("]"): # array type?
+ idx = name.rfind("[")
+ if 0 < idx:
+ name = name[:idx]
+ elif name.endswith(">"): # template type?
+ idx = name.find("<")
+ if 0 < idx: # always true, but just so that the translater knows
+ n1 = _remove_const(name[:idx])
+ name = "".join([n1, name[idx:]])
+ else:
+ name = _remove_const(name)
+ name = name[:_find_qualifier_index(name)]
+ return name.strip(' ')
+
+
+#- operator mappings --------------------------------------------------------
+_operator_mappings = {}
+
+def map_operator_name(cppname, nargs, result_type):
+ from pypy.module.cppyy import capi
+
+ if cppname[0:8] == "operator":
+ op = cppname[8:].strip(' ')
+
+ # look for known mapping
+ try:
+ return _operator_mappings[op]
+ except KeyError:
+ pass
+
+ # return-type dependent mapping
+ if op == "[]":
+ if result_type.find("const") != 0:
+ cpd = compound(result_type)
+ if cpd and cpd[len(cpd)-1] == "&":
+ return "__setitem__"
+ return "__getitem__"
+
+ # a couple more cases that depend on whether args were given
+
+ if op == "*": # dereference (not python) vs. multiplication
+ return nargs and "__mul__" or "__deref__"
+
+ if op == "+": # unary positive vs. binary addition
+ return nargs and "__add__" or "__pos__"
+
+ if op == "-": # unary negative vs. binary subtraction
+ return nargs and "__sub__" or "__neg__"
+
+ if op == "++": # prefix v.s. postfix increment (not python)
+ return nargs and "__postinc__" or "__preinc__";
+
+ if op == "--": # prefix v.s. postfix decrement (not python)
+ return nargs and "__postdec__" or "__predec__";
+
+ # operator could have been a conversion using a typedef (this lookup
+ # is put at the end only as it is unlikely and may trigger unwanted
+ # errors in class loaders in the backend, because a typical operator
+ # name is illegal as a class name)
+ true_op = capi.c_resolve_name(op)
+
+ try:
+ return _operator_mappings[true_op]
+ except KeyError:
+ pass
+
+ # might get here, as not all operator methods handled (although some with
+ # no python equivalent, such as new, delete, etc., are simply retained)
+ # TODO: perhaps absorb or "pythonify" these operators?
+ return cppname
+
+# _operator_mappings["[]"] = "__setitem__" # depends on return type
+# _operator_mappings["+"] = "__add__" # depends on # of args (see __pos__)
+# _operator_mappings["-"] = "__sub__" # id. (eq. __neg__)
+# _operator_mappings["*"] = "__mul__" # double meaning in C++
+
+# _operator_mappings["[]"] = "__getitem__" # depends on return type
+_operator_mappings["()"] = "__call__"
+_operator_mappings["/"] = "__div__" # __truediv__ in p3
+_operator_mappings["%"] = "__mod__"
+_operator_mappings["**"] = "__pow__" # not C++
+_operator_mappings["<<"] = "__lshift__"
+_operator_mappings[">>"] = "__rshift__"
+_operator_mappings["&"] = "__and__"
+_operator_mappings["|"] = "__or__"
+_operator_mappings["^"] = "__xor__"
+_operator_mappings["~"] = "__inv__"
+_operator_mappings["!"] = "__nonzero__"
+_operator_mappings["+="] = "__iadd__"
+_operator_mappings["-="] = "__isub__"
+_operator_mappings["*="] = "__imul__"
+_operator_mappings["/="] = "__idiv__" # __itruediv__ in p3
+_operator_mappings["%="] = "__imod__"
+_operator_mappings["**="] = "__ipow__"
+_operator_mappings["<<="] = "__ilshift__"
+_operator_mappings[">>="] = "__irshift__"
+_operator_mappings["&="] = "__iand__"
+_operator_mappings["|="] = "__ior__"
+_operator_mappings["^="] = "__ixor__"
+_operator_mappings["=="] = "__eq__"
+_operator_mappings["!="] = "__ne__"
+_operator_mappings[">"] = "__gt__"
+_operator_mappings["<"] = "__lt__"
+_operator_mappings[">="] = "__ge__"
+_operator_mappings["<="] = "__le__"
+
+# the following type mappings are "exact"
+_operator_mappings["const char*"] = "__str__"
+_operator_mappings["int"] = "__int__"
+_operator_mappings["long"] = "__long__" # __int__ in p3
+_operator_mappings["double"] = "__float__"
+
+# the following type mappings are "okay"; the assumption is that they
+# are not mixed up with the ones above or between themselves (and if
+# they are, that it is done consistently)
+_operator_mappings["char*"] = "__str__"
+_operator_mappings["short"] = "__int__"
+_operator_mappings["unsigned short"] = "__int__"
+_operator_mappings["unsigned int"] = "__long__" # __int__ in p3
+_operator_mappings["unsigned long"] = "__long__" # id.
+_operator_mappings["long long"] = "__long__" # id.
+_operator_mappings["unsigned long long"] = "__long__" # id.
+_operator_mappings["float"] = "__float__"
+
+_operator_mappings["bool"] = "__nonzero__" # __bool__ in p3
+
+# the following are not python, but useful to expose
+_operator_mappings["->"] = "__follow__"
+_operator_mappings["="] = "__assign__"
+
+# a bundle of operators that have no equivalent and are left "as-is" for now:
+_operator_mappings["&&"] = "&&"
+_operator_mappings["||"] = "||"
+_operator_mappings["new"] = "new"
+_operator_mappings["delete"] = "delete"
+_operator_mappings["new[]"] = "new[]"
+_operator_mappings["delete[]"] = "delete[]"
diff --git a/pypy/module/cppyy/include/capi.h b/pypy/module/cppyy/include/capi.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/include/capi.h
@@ -0,0 +1,111 @@
+#ifndef CPPYY_CAPI
+#define CPPYY_CAPI
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif // ifdef __cplusplus
+
+ typedef long cppyy_scope_t;
+ typedef cppyy_scope_t cppyy_type_t;
+ typedef long cppyy_object_t;
+ typedef long cppyy_method_t;
+ typedef void* (*cppyy_methptrgetter_t)(cppyy_object_t);
+
+ /* name to opaque C++ scope representation -------------------------------- */
+ char* cppyy_resolve_name(const char* cppitem_name);
+ cppyy_scope_t cppyy_get_scope(const char* scope_name);
+ cppyy_type_t cppyy_get_template(const char* template_name);
+ cppyy_type_t cppyy_actual_class(cppyy_type_t klass, cppyy_object_t obj);
+
+ /* memory management ------------------------------------------------------ */
+ cppyy_object_t cppyy_allocate(cppyy_type_t type);
+ void cppyy_deallocate(cppyy_type_t type, cppyy_object_t self);
+ void cppyy_destruct(cppyy_type_t type, cppyy_object_t self);
+
+ /* method/function dispatching -------------------------------------------- */
+ void cppyy_call_v(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+ int cppyy_call_b(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+ char cppyy_call_c(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+ short cppyy_call_h(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+ int cppyy_call_i(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+ long cppyy_call_l(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+ long long cppyy_call_ll(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+ double cppyy_call_f(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+ double cppyy_call_d(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+
+ void* cppyy_call_r(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+ char* cppyy_call_s(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+
+ void cppyy_constructor(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+ cppyy_object_t cppyy_call_o(cppyy_method_t method, cppyy_object_t self, int nargs, void* args, cppyy_type_t result_type);
+
+ cppyy_methptrgetter_t cppyy_get_methptr_getter(cppyy_scope_t scope, int method_index);
+
+ /* handling of function argument buffer ----------------------------------- */
+ void* cppyy_allocate_function_args(size_t nargs);
+ void cppyy_deallocate_function_args(void* args);
+ size_t cppyy_function_arg_sizeof();
+ size_t cppyy_function_arg_typeoffset();
+
+ /* scope reflection information ------------------------------------------- */
+ int cppyy_is_namespace(cppyy_scope_t scope);
+ int cppyy_is_enum(const char* type_name);
+
+ /* class reflection information ------------------------------------------- */
+ char* cppyy_final_name(cppyy_type_t type);
+ char* cppyy_scoped_final_name(cppyy_type_t type);
+ int cppyy_has_complex_hierarchy(cppyy_type_t type);
+ int cppyy_num_bases(cppyy_type_t type);
+ char* cppyy_base_name(cppyy_type_t type, int base_index);
+ int cppyy_is_subtype(cppyy_type_t derived, cppyy_type_t base);
+
+ /* calculate offsets between declared and actual type, up-cast: direction > 0; down-cast: direction < 0 */
+ size_t cppyy_base_offset(cppyy_type_t derived, cppyy_type_t base, cppyy_object_t address, int direction);
+
+ /* method/function reflection information --------------------------------- */
+ int cppyy_num_methods(cppyy_scope_t scope);
+ char* cppyy_method_name(cppyy_scope_t scope, int method_index);
+ char* cppyy_method_result_type(cppyy_scope_t scope, int method_index);
+ int cppyy_method_num_args(cppyy_scope_t scope, int method_index);
+ int cppyy_method_req_args(cppyy_scope_t scope, int method_index);
+ char* cppyy_method_arg_type(cppyy_scope_t scope, int method_index, int arg_index);
+ char* cppyy_method_arg_default(cppyy_scope_t scope, int method_index, int arg_index);
+ char* cppyy_method_signature(cppyy_scope_t scope, int method_index);
+
+ int cppyy_method_index(cppyy_scope_t scope, const char* name);
+
+ cppyy_method_t cppyy_get_method(cppyy_scope_t scope, int method_index);
+
+ /* method properties ----------------------------------------------------- */
+ int cppyy_is_constructor(cppyy_type_t type, int method_index);
+ int cppyy_is_staticmethod(cppyy_type_t type, int method_index);
+
+ /* data member reflection information ------------------------------------ */
+ int cppyy_num_datamembers(cppyy_scope_t scope);
+ char* cppyy_datamember_name(cppyy_scope_t scope, int datamember_index);
+ char* cppyy_datamember_type(cppyy_scope_t scope, int datamember_index);
+ size_t cppyy_datamember_offset(cppyy_scope_t scope, int datamember_index);
+
+ int cppyy_datamember_index(cppyy_scope_t scope, const char* name);
+
+ /* data member properties ------------------------------------------------ */
+ int cppyy_is_publicdata(cppyy_type_t type, int datamember_index);
+ int cppyy_is_staticdata(cppyy_type_t type, int datamember_index);
+
+ /* misc helpers ----------------------------------------------------------- */
+ void cppyy_free(void* ptr);
+ long long cppyy_strtoll(const char* str);
+ unsigned long long cppyy_strtuoll(const char* str);
+
+ cppyy_object_t cppyy_charp2stdstring(const char* str);
+ cppyy_object_t cppyy_stdstring2stdstring(cppyy_object_t ptr);
+ void cppyy_assign2stdstring(cppyy_object_t ptr, const char* str);
+ void cppyy_free_stdstring(cppyy_object_t ptr);
+
+#ifdef __cplusplus
+}
+#endif // ifdef __cplusplus
+
+#endif // ifndef CPPYY_CAPI
diff --git a/pypy/module/cppyy/include/cintcwrapper.h b/pypy/module/cppyy/include/cintcwrapper.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/include/cintcwrapper.h
@@ -0,0 +1,16 @@
+#ifndef CPPYY_CINTCWRAPPER
+#define CPPYY_CINTCWRAPPER
+
+#include "capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif // ifdef __cplusplus
+
+ void* cppyy_load_dictionary(const char* lib_name);
+
+#ifdef __cplusplus
+}
+#endif // ifdef __cplusplus
+
+#endif // ifndef CPPYY_CINTCWRAPPER
diff --git a/pypy/module/cppyy/include/cppyy.h b/pypy/module/cppyy/include/cppyy.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/include/cppyy.h
@@ -0,0 +1,64 @@
+#ifndef CPPYY_CPPYY
+#define CPPYY_CPPYY
+
+#ifdef __cplusplus
+struct CPPYY_G__DUMMY_FOR_CINT7 {
+#else
+typedef struct
+#endif
+ void* fTypeName;
+ unsigned int fModifiers;
+#ifdef __cplusplus
+};
+#else
+} CPPYY_G__DUMMY_FOR_CINT7;
+#endif
+
+#ifdef __cplusplus
+struct CPPYY_G__p2p {
+#else
+#typedef struct
+#endif
+ long i;
+ int reftype;
+#ifdef __cplusplus
+};
+#else
+} CPPYY_G__p2p;
+#endif
+
+
+#ifdef __cplusplus
+struct CPPYY_G__value {
+#else
+typedef struct {
+#endif
+ union {
+ double d;
+ long i; /* used to be int */
+ struct CPPYY_G__p2p reftype;
+ char ch;
+ short sh;
+ int in;
+ float fl;
+ unsigned char uch;
+ unsigned short ush;
+ unsigned int uin;
+ unsigned long ulo;
+ long long ll;
+ unsigned long long ull;
+ long double ld;
+ } obj;
+ long ref;
+ int type;
+ int tagnum;
+ int typenum;
+ char isconst;
+ struct CPPYY_G__DUMMY_FOR_CINT7 dummyForCint7;
+#ifdef __cplusplus
+};
+#else
+} CPPYY_G__value;
+#endif
+
+#endif // CPPYY_CPPYY
diff --git a/pypy/module/cppyy/include/reflexcwrapper.h b/pypy/module/cppyy/include/reflexcwrapper.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/include/reflexcwrapper.h
@@ -0,0 +1,6 @@
+#ifndef CPPYY_REFLEXCWRAPPER
+#define CPPYY_REFLEXCWRAPPER
+
+#include "capi.h"
+
+#endif // ifndef CPPYY_REFLEXCWRAPPER
diff --git a/pypy/module/cppyy/interp_cppyy.py b/pypy/module/cppyy/interp_cppyy.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/interp_cppyy.py
@@ -0,0 +1,807 @@
+import pypy.module.cppyy.capi as capi
+
+from pypy.interpreter.error import OperationError
+from pypy.interpreter.gateway import interp2app, unwrap_spec
+from pypy.interpreter.typedef import TypeDef, GetSetProperty, interp_attrproperty
+from pypy.interpreter.baseobjspace import Wrappable, W_Root
+
+from pypy.rpython.lltypesystem import rffi, lltype
+
+from pypy.rlib import libffi, rdynload, rweakref
+from pypy.rlib import jit, debug, objectmodel
+
+from pypy.module.cppyy import converter, executor, helper
+
+
+class FastCallNotPossible(Exception):
+ pass
+
+
+ at unwrap_spec(name=str)
+def load_dictionary(space, name):
+ try:
+ cdll = capi.c_load_dictionary(name)
+ except rdynload.DLOpenError, e:
+ raise OperationError(space.w_RuntimeError, space.wrap(str(e)))
+ return W_CPPLibrary(space, cdll)
+
+class State(object):
+ def __init__(self, space):
+ self.cppscope_cache = {
+ "void" : W_CPPClass(space, "void", capi.C_NULL_TYPE) }
+ self.cpptemplate_cache = {}
+ self.cppclass_registry = {}
+ self.w_clgen_callback = None
+
+ at unwrap_spec(name=str)
+def resolve_name(space, name):
+ return space.wrap(capi.c_resolve_name(name))
+
+ at unwrap_spec(name=str)
+def scope_byname(space, name):
+ true_name = capi.c_resolve_name(name)
+
+ state = space.fromcache(State)
+ try:
+ return state.cppscope_cache[true_name]
+ except KeyError:
+ pass
+
+ opaque_handle = capi.c_get_scope_opaque(true_name)
+ assert lltype.typeOf(opaque_handle) == capi.C_SCOPE
+ if opaque_handle:
+ final_name = capi.c_final_name(opaque_handle)
+ if capi.c_is_namespace(opaque_handle):
+ cppscope = W_CPPNamespace(space, final_name, opaque_handle)
+ elif capi.c_has_complex_hierarchy(opaque_handle):
+ cppscope = W_ComplexCPPClass(space, final_name, opaque_handle)
+ else:
+ cppscope = W_CPPClass(space, final_name, opaque_handle)
+ state.cppscope_cache[name] = cppscope
+
+ cppscope._find_methods()
+ cppscope._find_datamembers()
+ return cppscope
+
+ return None
+
+ at unwrap_spec(name=str)
+def template_byname(space, name):
+ state = space.fromcache(State)
+ try:
+ return state.cpptemplate_cache[name]
+ except KeyError:
+ pass
+
+ opaque_handle = capi.c_get_template(name)
+ assert lltype.typeOf(opaque_handle) == capi.C_TYPE
+ if opaque_handle:
+ cpptemplate = W_CPPTemplateType(space, name, opaque_handle)
+ state.cpptemplate_cache[name] = cpptemplate
+ return cpptemplate
+
+ 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_pycppclass=W_Root)
+def register_class(space, w_pycppclass):
+ w_cppclass = space.findattr(w_pycppclass, space.wrap("_cpp_proxy"))
+ cppclass = space.interp_w(W_CPPClass, w_cppclass, can_be_None=False)
+ state = space.fromcache(State)
+ state.cppclass_registry[cppclass.handle] = w_pycppclass
+
+
+class W_CPPLibrary(Wrappable):
+ _immutable_ = True
+
+ def __init__(self, space, cdll):
+ self.cdll = cdll
+ self.space = space
+
+W_CPPLibrary.typedef = TypeDef(
+ 'CPPLibrary',
+)
+W_CPPLibrary.typedef.acceptable_as_base_class = True
+
+
+class CPPMethod(object):
+ """ A concrete function after overloading has been resolved """
+ _immutable_ = True
+
+ def __init__(self, space, containing_scope, method_index, arg_defs, args_required):
+ self.space = space
+ self.scope = containing_scope
+ self.index = method_index
+ self.cppmethod = capi.c_get_method(self.scope, method_index)
+ self.arg_defs = arg_defs
+ self.args_required = args_required
+ self.args_expected = len(arg_defs)
+
+ # Setup of the method dispatch's innards is done lazily, i.e. only when
+ # the method is actually used.
+ self.converters = None
+ self.executor = None
+ self._libffifunc = None
+
+ def _address_from_local_buffer(self, call_local, idx):
+ if not call_local:
+ return call_local
+ stride = 2*rffi.sizeof(rffi.VOIDP)
+ loc_idx = lltype.direct_ptradd(rffi.cast(rffi.CCHARP, call_local), idx*stride)
+ return rffi.cast(rffi.VOIDP, loc_idx)
+
+ @jit.unroll_safe
+ def call(self, cppthis, args_w):
+ jit.promote(self)
+ assert lltype.typeOf(cppthis) == capi.C_OBJECT
+
+ # check number of given arguments against required (== total - defaults)
+ args_expected = len(self.arg_defs)
+ args_given = len(args_w)
+ if args_expected < args_given or args_given < self.args_required:
+ raise OperationError(self.space.w_TypeError,
+ self.space.wrap("wrong number of arguments"))
+
+ # initial setup of converters, executors, and libffi (if available)
+ if self.converters is None:
+ self._setup(cppthis)
+
+ # some calls, e.g. for ptr-ptr or reference need a local array to store data for
+ # the duration of the call
+ if [conv for conv in self.converters if conv.uses_local]:
+ call_local = lltype.malloc(rffi.VOIDP.TO, 2*len(args_w), flavor='raw')
+ else:
+ call_local = lltype.nullptr(rffi.VOIDP.TO)
+
+ try:
+ # attempt to call directly through ffi chain
+ if self._libffifunc:
+ try:
+ return self.do_fast_call(cppthis, args_w, call_local)
+ except FastCallNotPossible:
+ pass # can happen if converters or executor does not implement ffi
+
+ # ffi chain must have failed; using stub functions instead
+ args = self.prepare_arguments(args_w, call_local)
+ try:
+ return self.executor.execute(self.space, self.cppmethod, cppthis, len(args_w), args)
+ finally:
+ self.finalize_call(args, args_w, call_local)
+ finally:
+ if call_local:
+ lltype.free(call_local, flavor='raw')
+
+ @jit.unroll_safe
+ def do_fast_call(self, cppthis, args_w, call_local):
+ jit.promote(self)
+ argchain = libffi.ArgChain()
+ argchain.arg(cppthis)
+ i = len(self.arg_defs)
+ for i in range(len(args_w)):
+ conv = self.converters[i]
+ w_arg = args_w[i]
+ conv.convert_argument_libffi(self.space, w_arg, argchain, call_local)
+ for j in range(i+1, len(self.arg_defs)):
+ conv = self.converters[j]
+ conv.default_argument_libffi(self.space, argchain)
+ return self.executor.execute_libffi(self.space, self._libffifunc, argchain)
+
+ def _setup(self, cppthis):
+ self.converters = [converter.get_converter(self.space, arg_type, arg_dflt)
+ for arg_type, arg_dflt in self.arg_defs]
+ self.executor = executor.get_executor(self.space, capi.c_method_result_type(self.scope, self.index))
+
+ # Each CPPMethod corresponds one-to-one to a C++ equivalent and cppthis
+ # has been offset to the matching class. Hence, the libffi pointer is
+ # uniquely defined and needs to be setup only once.
+ methgetter = capi.c_get_methptr_getter(self.scope, self.index)
+ if methgetter and cppthis: # methods only for now
+ funcptr = methgetter(rffi.cast(capi.C_OBJECT, cppthis))
+ argtypes_libffi = [conv.libffitype for conv in self.converters if conv.libffitype]
+ if (len(argtypes_libffi) == len(self.converters) and
+ self.executor.libffitype):
+ # add c++ this to the arguments
+ libffifunc = libffi.Func("XXX",
+ [libffi.types.pointer] + argtypes_libffi,
+ self.executor.libffitype, funcptr)
+ self._libffifunc = libffifunc
+
+ @jit.unroll_safe
+ 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()
+ for i in range(len(args_w)):
+ conv = self.converters[i]
+ w_arg = args_w[i]
+ try:
+ arg_i = lltype.direct_ptradd(rffi.cast(rffi.CCHARP, args), i*stride)
+ 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.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(self.space, rffi.cast(capi.C_OBJECT, arg_j), loc_j)
+ capi.c_deallocate_function_args(args)
+ raise
+ return args
+
+ @jit.unroll_safe
+ def finalize_call(self, args, args_w, call_local):
+ stride = capi.c_function_arg_sizeof()
+ for i in range(len(args_w)):
+ conv = self.converters[i]
+ 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(self.space, rffi.cast(capi.C_OBJECT, arg_i), loc_i)
+ capi.c_deallocate_function_args(args)
+
+ def signature(self):
+ return capi.c_method_signature(self.scope, self.index)
+
+ def __repr__(self):
+ return "CPPMethod: %s" % self.signature()
+
+ def _freeze_(self):
+ assert 0, "you should never have a pre-built instance of this!"
+
+
+class CPPFunction(CPPMethod):
+ _immutable_ = True
+
+ def __repr__(self):
+ return "CPPFunction: %s" % self.signature()
+
+
+class CPPConstructor(CPPMethod):
+ _immutable_ = True
+
+ def call(self, cppthis, args_w):
+ newthis = capi.c_allocate(self.scope)
+ assert lltype.typeOf(newthis) == capi.C_OBJECT
+ try:
+ CPPMethod.call(self, newthis, args_w)
+ except:
+ capi.c_deallocate(self.scope, newthis)
+ raise
+ return wrap_new_cppobject_nocast(
+ self.space, self.space.w_None, self.scope, newthis, isref=False, python_owns=True)
+
+ def __repr__(self):
+ return "CPPConstructor: %s" % self.signature()
+
+
+class W_CPPOverload(Wrappable):
+ _immutable_ = True
+
+ def __init__(self, space, containing_scope, functions):
+ self.space = space
+ self.scope = containing_scope
+ self.functions = debug.make_sure_not_resized(functions)
+
+ def is_static(self):
+ return self.space.wrap(isinstance(self.functions[0], CPPFunction))
+
+ @jit.unroll_safe
+ @unwrap_spec(args_w='args_w')
+ def call(self, w_cppinstance, args_w):
+ cppinstance = self.space.interp_w(W_CPPInstance, w_cppinstance, can_be_None=True)
+ if cppinstance is not None:
+ cppinstance._nullcheck()
+ cppthis = cppinstance.get_cppthis(self.scope)
+ else:
+ cppthis = capi.C_NULL_OBJECT
+ assert lltype.typeOf(cppthis) == capi.C_OBJECT
+
+ # The following code tries out each of the functions in order. If
+ # argument conversion fails (or simply if the number of arguments do
+ # not match, that will lead to an exception, The JIT will snip out
+ # those (always) failing paths, but only if they have no side-effects.
+ # A second loop gathers all exceptions in the case all methods fail
+ # (the exception gathering would otherwise be a side-effect as far as
+ # the JIT is concerned).
+ #
+ # TODO: figure out what happens if a callback into from the C++ call
+ # raises a Python exception.
+ jit.promote(self)
+ for i in range(len(self.functions)):
+ cppyyfunc = self.functions[i]
+ try:
+ return cppyyfunc.call(cppthis, args_w)
+ except Exception:
+ pass
+
+ # only get here if all overloads failed ...
+ errmsg = 'none of the %d overloaded methods succeeded. Full details:' % len(self.functions)
+ if hasattr(self.space, "fake"): # FakeSpace fails errorstr (see below)
+ raise OperationError(self.space.w_TypeError, self.space.wrap(errmsg))
+ for i in range(len(self.functions)):
+ cppyyfunc = self.functions[i]
+ try:
+ return cppyyfunc.call(cppthis, args_w)
+ except OperationError, e:
+ errmsg += '\n '+cppyyfunc.signature()+' =>\n'
+ errmsg += ' '+e.errorstr(self.space)
+ except Exception, e:
+ errmsg += '\n '+cppyyfunc.signature()+' =>\n'
+ errmsg += ' Exception: '+str(e)
+
+ raise OperationError(self.space.w_TypeError, self.space.wrap(errmsg))
+
+ def signature(self):
+ sig = self.functions[0].signature()
+ for i in range(1, len(self.functions)):
+ sig += '\n'+self.functions[i].signature()
+ return self.space.wrap(sig)
+
+ def __repr__(self):
+ return "W_CPPOverload(%s)" % [f.signature() for f in self.functions]
+
+W_CPPOverload.typedef = TypeDef(
+ 'CPPOverload',
+ is_static = interp2app(W_CPPOverload.is_static),
+ call = interp2app(W_CPPOverload.call),
+ signature = interp2app(W_CPPOverload.signature),
+)
+
+
+class W_CPPDataMember(Wrappable):
+ _immutable_ = True
+
+ def __init__(self, space, containing_scope, type_name, offset, is_static):
+ self.space = space
+ self.scope = containing_scope
+ self.converter = converter.get_converter(self.space, type_name, '')
+ self.offset = offset
+ self._is_static = is_static
+
+ def get_returntype(self):
+ return self.space.wrap(self.converter.name)
+
+ def is_static(self):
+ return self.space.newbool(self._is_static)
+
+ @jit.elidable_promote()
+ def _get_offset(self, cppinstance):
+ if cppinstance:
+ assert lltype.typeOf(cppinstance.cppclass.handle) == lltype.typeOf(self.scope.handle)
+ offset = self.offset + capi.c_base_offset(
+ cppinstance.cppclass, self.scope, cppinstance.get_rawobject(), 1)
+ else:
+ offset = self.offset
+ return offset
+
+ def get(self, w_cppinstance, w_pycppclass):
+ cppinstance = self.space.interp_w(W_CPPInstance, w_cppinstance, can_be_None=True)
+ offset = self._get_offset(cppinstance)
+ return self.converter.from_memory(self.space, w_cppinstance, w_pycppclass, offset)
+
+ def set(self, w_cppinstance, w_value):
+ cppinstance = self.space.interp_w(W_CPPInstance, w_cppinstance, can_be_None=True)
+ offset = self._get_offset(cppinstance)
+ self.converter.to_memory(self.space, w_cppinstance, w_value, offset)
+ return self.space.w_None
+
+W_CPPDataMember.typedef = TypeDef(
+ 'CPPDataMember',
+ is_static = interp2app(W_CPPDataMember.is_static),
+ get_returntype = interp2app(W_CPPDataMember.get_returntype),
+ get = interp2app(W_CPPDataMember.get),
+ set = interp2app(W_CPPDataMember.set),
+)
+W_CPPDataMember.typedef.acceptable_as_base_class = False
+
+
+class W_CPPScope(Wrappable):
+ _immutable_ = True
+ _immutable_fields_ = ["methods[*]", "datamembers[*]"]
+
+ kind = "scope"
+
+ def __init__(self, space, name, opaque_handle):
+ self.space = space
+ self.name = name
+ assert lltype.typeOf(opaque_handle) == capi.C_SCOPE
+ self.handle = opaque_handle
+ self.methods = {}
+ # Do not call "self._find_methods()" here, so that a distinction can
+ # be made between testing for existence (i.e. existence in the cache
+ # of classes) and actual use. Point being that a class can use itself,
+ # e.g. as a return type or an argument to one of its methods.
+
+ self.datamembers = {}
+ # Idem self.methods: a type could hold itself by pointer.
+
+ def _find_methods(self):
+ num_methods = capi.c_num_methods(self)
+ args_temp = {}
+ for i in range(num_methods):
+ method_name = capi.c_method_name(self, i)
+ pymethod_name = helper.map_operator_name(
+ method_name, capi.c_method_num_args(self, i),
+ capi.c_method_result_type(self, i))
+ if not pymethod_name in self.methods:
+ cppfunction = self._make_cppfunction(i)
+ overload = args_temp.setdefault(pymethod_name, [])
+ overload.append(cppfunction)
+ for name, functions in args_temp.iteritems():
+ overload = W_CPPOverload(self.space, self, functions[:])
+ self.methods[name] = overload
+
+ def get_method_names(self):
+ return self.space.newlist([self.space.wrap(name) for name in self.methods])
+
+ @jit.elidable_promote('0')
+ def get_overload(self, name):
+ try:
+ return self.methods[name]
+ except KeyError:
+ pass
+ new_method = self.find_overload(name)
+ self.methods[name] = new_method
+ return new_method
+
+ def get_datamember_names(self):
+ return self.space.newlist([self.space.wrap(name) for name in self.datamembers])
+
+ @jit.elidable_promote('0')
+ def get_datamember(self, name):
+ try:
+ return self.datamembers[name]
+ except KeyError:
+ pass
+ new_dm = self.find_datamember(name)
+ self.datamembers[name] = new_dm
+ return new_dm
+
+ @jit.elidable_promote('0')
+ def dispatch(self, name, signature):
+ overload = self.get_overload(name)
+ sig = '(%s)' % signature
+ for f in overload.functions:
+ if 0 < f.signature().find(sig):
+ return W_CPPOverload(self.space, self, [f])
+ raise OperationError(self.space.w_TypeError, self.space.wrap("no overload matches signature"))
+
+ def missing_attribute_error(self, name):
+ return OperationError(
+ self.space.w_AttributeError,
+ self.space.wrap("%s '%s' has no attribute %s" % (self.kind, self.name, name)))
+
+ def __eq__(self, other):
+ return self.handle == other.handle
+
+
+# For now, keep namespaces and classes separate as namespaces are extensible
+# with info from multiple dictionaries and do not need to bother with meta
+# classes for inheritance. Both are python classes, though, and refactoring
+# may be in order at some point.
+class W_CPPNamespace(W_CPPScope):
+ _immutable_ = True
+ kind = "namespace"
+
+ def _make_cppfunction(self, method_index):
+ num_args = capi.c_method_num_args(self, method_index)
+ args_required = capi.c_method_req_args(self, method_index)
+ arg_defs = []
+ for i in range(num_args):
+ arg_type = capi.c_method_arg_type(self, method_index, i)
+ arg_dflt = capi.c_method_arg_default(self, method_index, i)
+ arg_defs.append((arg_type, arg_dflt))
+ return CPPFunction(self.space, self, method_index, arg_defs, args_required)
+
+ def _make_datamember(self, dm_name, dm_idx):
+ type_name = capi.c_datamember_type(self, dm_idx)
+ offset = capi.c_datamember_offset(self, dm_idx)
+ datamember = W_CPPDataMember(self.space, self, type_name, offset, True)
+ self.datamembers[dm_name] = datamember
+ return datamember
+
+ def _find_datamembers(self):
+ num_datamembers = capi.c_num_datamembers(self)
+ for i in range(num_datamembers):
+ if not capi.c_is_publicdata(self, i):
+ continue
+ datamember_name = capi.c_datamember_name(self, i)
+ if not datamember_name in self.datamembers:
+ self._make_datamember(datamember_name, i)
+
+ def find_overload(self, meth_name):
+ # TODO: collect all overloads, not just the non-overloaded version
+ meth_idx = capi.c_method_index(self, meth_name)
+ if meth_idx < 0:
+ raise self.missing_attribute_error(meth_name)
+ cppfunction = self._make_cppfunction(meth_idx)
+ overload = W_CPPOverload(self.space, self, [cppfunction])
+ return overload
+
+ def find_datamember(self, dm_name):
+ dm_idx = capi.c_datamember_index(self, dm_name)
+ if dm_idx < 0:
+ raise self.missing_attribute_error(dm_name)
+ datamember = self._make_datamember(dm_name, dm_idx)
+ return datamember
+
+ def update(self):
+ self._find_methods()
+ self._find_datamembers()
+
+ def is_namespace(self):
+ return self.space.w_True
+
+W_CPPNamespace.typedef = TypeDef(
+ 'CPPNamespace',
+ update = interp2app(W_CPPNamespace.update),
+ get_method_names = interp2app(W_CPPNamespace.get_method_names),
+ get_overload = interp2app(W_CPPNamespace.get_overload, unwrap_spec=['self', str]),
+ get_datamember_names = interp2app(W_CPPNamespace.get_datamember_names),
+ get_datamember = interp2app(W_CPPNamespace.get_datamember, unwrap_spec=['self', str]),
+ is_namespace = interp2app(W_CPPNamespace.is_namespace),
+)
+W_CPPNamespace.typedef.acceptable_as_base_class = False
+
+
+class W_CPPClass(W_CPPScope):
+ _immutable_ = True
+ kind = "class"
+
+ def _make_cppfunction(self, method_index):
+ num_args = capi.c_method_num_args(self, method_index)
+ args_required = capi.c_method_req_args(self, method_index)
+ arg_defs = []
+ for i in range(num_args):
+ arg_type = capi.c_method_arg_type(self, method_index, i)
+ arg_dflt = capi.c_method_arg_default(self, method_index, i)
+ arg_defs.append((arg_type, arg_dflt))
+ if capi.c_is_constructor(self, method_index):
+ cls = CPPConstructor
+ elif capi.c_is_staticmethod(self, method_index):
+ cls = CPPFunction
+ else:
+ cls = CPPMethod
+ return cls(self.space, self, method_index, arg_defs, args_required)
+
+ def _find_datamembers(self):
+ num_datamembers = capi.c_num_datamembers(self)
+ for i in range(num_datamembers):
+ if not capi.c_is_publicdata(self, i):
+ continue
+ datamember_name = capi.c_datamember_name(self, i)
+ type_name = capi.c_datamember_type(self, i)
+ offset = capi.c_datamember_offset(self, i)
+ is_static = bool(capi.c_is_staticdata(self, i))
+ datamember = W_CPPDataMember(self.space, self, type_name, offset, is_static)
+ self.datamembers[datamember_name] = datamember
+
+ def find_overload(self, name):
+ raise self.missing_attribute_error(name)
+
+ def find_datamember(self, name):
+ raise self.missing_attribute_error(name)
+
+ def get_cppthis(self, cppinstance, calling_scope):
+ assert self == cppinstance.cppclass
+ return cppinstance.get_rawobject()
+
+ def is_namespace(self):
+ return self.space.w_False
+
+ def get_base_names(self):
+ bases = []
+ num_bases = capi.c_num_bases(self)
+ for i in range(num_bases):
+ base_name = capi.c_base_name(self, i)
+ bases.append(self.space.wrap(base_name))
+ return self.space.newlist(bases)
+
+W_CPPClass.typedef = TypeDef(
+ 'CPPClass',
+ type_name = interp_attrproperty('name', W_CPPClass),
+ get_base_names = interp2app(W_CPPClass.get_base_names),
+ get_method_names = interp2app(W_CPPClass.get_method_names),
+ get_overload = interp2app(W_CPPClass.get_overload, unwrap_spec=['self', str]),
+ get_datamember_names = interp2app(W_CPPClass.get_datamember_names),
+ get_datamember = interp2app(W_CPPClass.get_datamember, unwrap_spec=['self', str]),
+ is_namespace = interp2app(W_CPPClass.is_namespace),
+ dispatch = interp2app(W_CPPClass.dispatch, unwrap_spec=['self', str, str])
+)
+W_CPPClass.typedef.acceptable_as_base_class = False
+
+
+class W_ComplexCPPClass(W_CPPClass):
+ _immutable_ = True
+
+ def get_cppthis(self, cppinstance, calling_scope):
+ assert self == cppinstance.cppclass
+ offset = capi.c_base_offset(self, calling_scope, cppinstance.get_rawobject(), 1)
+ return capi.direct_ptradd(cppinstance.get_rawobject(), offset)
+
+W_ComplexCPPClass.typedef = TypeDef(
+ 'ComplexCPPClass',
+ type_name = interp_attrproperty('name', W_CPPClass),
+ get_base_names = interp2app(W_ComplexCPPClass.get_base_names),
+ get_method_names = interp2app(W_ComplexCPPClass.get_method_names),
+ get_overload = interp2app(W_ComplexCPPClass.get_overload, unwrap_spec=['self', str]),
+ get_datamember_names = interp2app(W_ComplexCPPClass.get_datamember_names),
+ get_datamember = interp2app(W_ComplexCPPClass.get_datamember, unwrap_spec=['self', str]),
+ is_namespace = interp2app(W_ComplexCPPClass.is_namespace),
+ dispatch = interp2app(W_CPPClass.dispatch, unwrap_spec=['self', str, str])
+)
+W_ComplexCPPClass.typedef.acceptable_as_base_class = False
+
+
+class W_CPPTemplateType(Wrappable):
+ _immutable_ = True
+
+ def __init__(self, space, name, opaque_handle):
+ self.space = space
+ self.name = name
+ assert lltype.typeOf(opaque_handle) == capi.C_TYPE
+ self.handle = opaque_handle
+
+ @unwrap_spec(args_w='args_w')
+ def __call__(self, args_w):
+ # TODO: this is broken but unused (see pythonify.py)
+ fullname = "".join([self.name, '<', self.space.str_w(args_w[0]), '>'])
+ return scope_byname(self.space, fullname)
+
+W_CPPTemplateType.typedef = TypeDef(
+ 'CPPTemplateType',
+ __call__ = interp2app(W_CPPTemplateType.__call__),
+)
+W_CPPTemplateType.typedef.acceptable_as_base_class = False
+
+
+class W_CPPInstance(Wrappable):
+ _immutable_fields_ = ["cppclass", "isref"]
+
+ def __init__(self, space, cppclass, rawobject, isref, python_owns):
+ self.space = space
+ self.cppclass = cppclass
+ assert lltype.typeOf(rawobject) == capi.C_OBJECT
+ assert not isref or rawobject
+ self._rawobject = rawobject
+ assert not isref or not python_owns
+ self.isref = isref
+ self.python_owns = python_owns
+
+ def _nullcheck(self):
+ if not self._rawobject or (self.isref and not self.get_rawobject()):
+ raise OperationError(self.space.w_ReferenceError,
+ self.space.wrap("trying to access a NULL pointer"))
+
+ # allow user to determine ownership rules on a per object level
+ def fget_python_owns(self, space):
+ return space.wrap(self.python_owns)
+
+ @unwrap_spec(value=bool)
+ def fset_python_owns(self, space, value):
+ self.python_owns = space.is_true(value)
+
+ def get_cppthis(self, calling_scope):
+ return self.cppclass.get_cppthis(self, calling_scope)
+
+ def get_rawobject(self):
+ if not self.isref:
+ return self._rawobject
+ else:
+ ptrptr = rffi.cast(rffi.VOIDPP, self._rawobject)
+ return rffi.cast(capi.C_OBJECT, ptrptr[0])
+
+ def instance__eq__(self, w_other):
+ other = self.space.interp_w(W_CPPInstance, w_other, can_be_None=False)
+ iseq = self._rawobject == other._rawobject
+ return self.space.wrap(iseq)
+
+ def instance__ne__(self, w_other):
+ return self.space.not_(self.instance__eq__(w_other))
+
+ def instance__nonzero__(self):
+ if not self._rawobject or (self.isref and not self.get_rawobject()):
+ return self.space.w_False
+ return self.space.w_True
+
+ def destruct(self):
+ assert isinstance(self, W_CPPInstance)
+ if self._rawobject and not self.isref:
+ memory_regulator.unregister(self)
+ capi.c_destruct(self.cppclass, self._rawobject)
+ self._rawobject = capi.C_NULL_OBJECT
+
+ def __del__(self):
+ if self.python_owns:
+ self.enqueue_for_destruction(self.space, W_CPPInstance.destruct,
+ '__del__() method of ')
+
+W_CPPInstance.typedef = TypeDef(
+ 'CPPInstance',
+ cppclass = interp_attrproperty('cppclass', cls=W_CPPInstance),
+ _python_owns = GetSetProperty(W_CPPInstance.fget_python_owns, W_CPPInstance.fset_python_owns),
+ __eq__ = interp2app(W_CPPInstance.instance__eq__),
+ __ne__ = interp2app(W_CPPInstance.instance__ne__),
+ __nonzero__ = interp2app(W_CPPInstance.instance__nonzero__),
+ destruct = interp2app(W_CPPInstance.destruct),
+)
+W_CPPInstance.typedef.acceptable_as_base_class = True
+
+
+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 get_pythonized_cppclass(space, handle):
+ state = space.fromcache(State)
+ try:
+ w_pycppclass = state.cppclass_registry[handle]
+ except KeyError:
+ final_name = capi.c_scoped_final_name(handle)
+ w_pycppclass = space.call_function(state.w_clgen_callback, space.wrap(final_name))
+ return w_pycppclass
+
+def wrap_new_cppobject_nocast(space, w_pycppclass, cppclass, rawobject, isref, python_owns):
+ if space.is_w(w_pycppclass, space.w_None):
+ w_pycppclass = get_pythonized_cppclass(space, cppclass.handle)
+ w_cppinstance = space.allocate_instance(W_CPPInstance, w_pycppclass)
+ cppinstance = space.interp_w(W_CPPInstance, w_cppinstance, can_be_None=False)
+ W_CPPInstance.__init__(cppinstance, space, cppclass, rawobject, isref, python_owns)
+ memory_regulator.register(cppinstance)
+ return w_cppinstance
+
+def wrap_cppobject_nocast(space, w_pycppclass, cppclass, rawobject, isref, python_owns):
+ obj = memory_regulator.retrieve(rawobject)
+ if obj and obj.cppclass == cppclass:
+ return obj
+ return wrap_new_cppobject_nocast(space, w_pycppclass, cppclass, rawobject, isref, python_owns)
+
+def wrap_cppobject(space, w_pycppclass, cppclass, rawobject, isref, python_owns):
+ if rawobject:
+ actual = capi.c_actual_class(cppclass, rawobject)
+ if actual != cppclass.handle:
+ offset = capi._c_base_offset(actual, cppclass.handle, rawobject, -1)
+ rawobject = capi.direct_ptradd(rawobject, offset)
+ w_pycppclass = get_pythonized_cppclass(space, actual)
+ w_cppclass = space.findattr(w_pycppclass, space.wrap("_cpp_proxy"))
+ cppclass = space.interp_w(W_CPPClass, w_cppclass, can_be_None=False)
+ return wrap_cppobject_nocast(space, w_pycppclass, cppclass, rawobject, isref, python_owns)
+
+ at unwrap_spec(cppinstance=W_CPPInstance)
+def addressof(space, cppinstance):
+ address = rffi.cast(rffi.LONG, cppinstance.get_rawobject())
+ return space.wrap(address)
+
+ at unwrap_spec(address=int, owns=bool)
+def bind_object(space, address, w_pycppclass, owns=False):
+ rawobject = rffi.cast(capi.C_OBJECT, address)
+ w_cppclass = space.findattr(w_pycppclass, space.wrap("_cpp_proxy"))
+ cppclass = space.interp_w(W_CPPClass, w_cppclass, can_be_None=False)
+ return wrap_cppobject_nocast(space, w_pycppclass, cppclass, rawobject, False, owns)
diff --git a/pypy/module/cppyy/pythonify.py b/pypy/module/cppyy/pythonify.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/pythonify.py
@@ -0,0 +1,388 @@
+# NOT_RPYTHON
+import cppyy
+import types
+
+
+# For now, keep namespaces and classes separate as namespaces are extensible
+# with info from multiple dictionaries and do not need to bother with meta
+# classes for inheritance. Both are python classes, though, and refactoring
+# may be in order at some point.
+class CppyyScopeMeta(type):
+ def __getattr__(self, name):
+ try:
+ return get_pycppitem(self, name) # will cache on self
+ except TypeError, t:
+ raise AttributeError("%s object has no attribute '%s'" % (self, name))
+
+class CppyyNamespaceMeta(CppyyScopeMeta):
+ pass
+
+class CppyyClass(CppyyScopeMeta):
+ pass
+
+class CPPObject(cppyy.CPPInstance):
+ __metaclass__ = CppyyClass
+
+
+class CppyyTemplateType(object):
+ def __init__(self, scope, name):
+ self._scope = scope
+ self._name = name
+
+ def _arg_to_str(self, arg):
+ if type(arg) != str:
+ arg = arg.__name__
+ return arg
+
+ def __call__(self, *args):
+ fullname = ''.join(
+ [self._name, '<', ','.join(map(self._arg_to_str, args))])
+ if fullname[-1] == '>':
+ fullname += ' >'
+ else:
+ fullname += '>'
+ return getattr(self._scope, fullname)
+
+
+def clgen_callback(name):
+ return get_pycppclass(name)
+cppyy._set_class_generator(clgen_callback)
+
+def make_static_function(func_name, cppol):
+ def function(*args):
+ return cppol.call(None, *args)
+ function.__name__ = func_name
+ function.__doc__ = cppol.signature()
+ return staticmethod(function)
+
+def make_method(meth_name, cppol):
+ def method(self, *args):
+ return cppol.call(self, *args)
+ method.__name__ = meth_name
+ method.__doc__ = cppol.signature()
+ return method
+
+
+def make_datamember(cppdm):
+ rettype = cppdm.get_returntype()
+ if not rettype: # return builtin type
+ cppclass = None
+ else: # return instance
+ try:
+ cppclass = get_pycppclass(rettype)
+ except AttributeError:
+ import warnings
+ warnings.warn("class %s unknown: no data member access" % rettype,
+ RuntimeWarning)
+ cppclass = None
+ if cppdm.is_static():
+ def binder(obj):
+ return cppdm.get(None, cppclass)
+ def setter(obj, value):
+ return cppdm.set(None, value)
+ else:
+ def binder(obj):
+ return cppdm.get(obj, cppclass)
+ setter = cppdm.set
+ return property(binder, setter)
+
+
+def make_cppnamespace(scope, namespace_name, cppns, build_in_full=True):
+ # build up a representation of a C++ namespace (namespaces are classes)
+
+ # create a meta class to allow properties (for static data write access)
+ metans = type(CppyyNamespaceMeta)(namespace_name+'_meta', (CppyyNamespaceMeta,), {})
+
+ if cppns:
+ d = {"_cpp_proxy" : cppns}
+ else:
+ d = dict()
+ def cpp_proxy_loader(cls):
+ cpp_proxy = cppyy._scope_byname(cls.__name__ != '::' and cls.__name__ or '')
+ del cls.__class__._cpp_proxy
+ cls._cpp_proxy = cpp_proxy
+ return cpp_proxy
+ metans._cpp_proxy = property(cpp_proxy_loader)
+
+ # create the python-side C++ namespace representation, cache in scope if given
+ pycppns = metans(namespace_name, (object,), d)
+ if scope:
+ setattr(scope, namespace_name, pycppns)
+
+ if build_in_full: # if False, rely on lazy build-up
+ # insert static methods into the "namespace" dictionary
+ for func_name in cppns.get_method_names():
+ cppol = cppns.get_overload(func_name)
+ pyfunc = make_static_function(func_name, cppol)
+ setattr(pycppns, func_name, pyfunc)
+
+ # add all data members to the dictionary of the class to be created, and
+ # static ones also to the meta class (needed for property setters)
+ for dm in cppns.get_datamember_names():
+ cppdm = cppns.get_datamember(dm)
+ pydm = make_datamember(cppdm)
+ setattr(pycppns, dm, pydm)
+ setattr(metans, dm, pydm)
+
+ return pycppns
+
+def _drop_cycles(bases):
+ # TODO: figure this out, as it seems to be a PyPy bug?!
+ for b1 in bases:
+ for b2 in bases:
+ if not (b1 is b2) and issubclass(b2, b1):
+ bases.remove(b1) # removes lateral class
+ break
+ return tuple(bases)
+
+def make_new(class_name, cppclass):
+ try:
+ constructor_overload = cppclass.get_overload(cppclass.type_name)
+ except AttributeError:
+ msg = "cannot instantiate abstract class '%s'" % class_name
+ def __new__(cls, *args):
+ raise TypeError(msg)
+ else:
+ def __new__(cls, *args):
+ return constructor_overload.call(None, *args)
+ return __new__
+
+def make_pycppclass(scope, class_name, final_class_name, cppclass):
+
+ # get a list of base classes for class creation
+ bases = [get_pycppclass(base) for base in cppclass.get_base_names()]
+ if not bases:
+ bases = [CPPObject,]
+ else:
+ # it's technically possible that the required class now has been built
+ # if one of the base classes uses it in e.g. a function interface
+ try:
+ return scope.__dict__[final_class_name]
+ except KeyError:
+ pass
+
+ # create a meta class to allow properties (for static data write access)
+ metabases = [type(base) for base in bases]
+ metacpp = type(CppyyClass)(class_name+'_meta', _drop_cycles(metabases), {})
+
+ # create the python-side C++ class representation
+ def dispatch(self, name, signature):
+ cppol = cppclass.dispatch(name, signature)
+ return types.MethodType(make_method(name, cppol), self, type(self))
+ d = {"_cpp_proxy" : cppclass,
+ "__dispatch__" : dispatch,
+ "__new__" : make_new(class_name, cppclass),
+ }
+ pycppclass = metacpp(class_name, _drop_cycles(bases), d)
+
+ # cache result early so that the class methods can find the class itself
+ setattr(scope, final_class_name, pycppclass)
+
+ # insert (static) methods into the class dictionary
+ for meth_name in cppclass.get_method_names():
+ cppol = cppclass.get_overload(meth_name)
+ if cppol.is_static():
+ setattr(pycppclass, meth_name, make_static_function(meth_name, cppol))
+ else:
+ setattr(pycppclass, meth_name, make_method(meth_name, cppol))
+
+ # add all data members to the dictionary of the class to be created, and
+ # static ones also to the meta class (needed for property setters)
+ for dm_name in cppclass.get_datamember_names():
+ cppdm = cppclass.get_datamember(dm_name)
+ pydm = make_datamember(cppdm)
+
+ setattr(pycppclass, dm_name, pydm)
+ if cppdm.is_static():
+ setattr(metacpp, dm_name, pydm)
+
+ _pythonize(pycppclass)
+ cppyy._register_class(pycppclass)
+ return pycppclass
+
+def make_cpptemplatetype(scope, template_name):
+ return CppyyTemplateType(scope, template_name)
+
+
+def get_pycppitem(scope, name):
+ # resolve typedefs/aliases
+ full_name = (scope == gbl) and name or (scope.__name__+'::'+name)
+ true_name = cppyy._resolve_name(full_name)
+ if true_name != full_name:
+ return get_pycppclass(true_name)
+
+ pycppitem = None
+
+ # classes
+ cppitem = cppyy._scope_byname(true_name)
+ if cppitem:
+ if cppitem.is_namespace():
+ pycppitem = make_cppnamespace(scope, true_name, cppitem)
+ setattr(scope, name, pycppitem)
+ else:
+ pycppitem = make_pycppclass(scope, true_name, name, cppitem)
+
+ # templates
+ if not cppitem:
+ cppitem = cppyy._template_byname(true_name)
+ if cppitem:
+ pycppitem = make_cpptemplatetype(scope, name)
+ setattr(scope, name, pycppitem)
+
+ # functions
+ if not cppitem:
+ try:
+ cppitem = scope._cpp_proxy.get_overload(name)
+ pycppitem = make_static_function(name, cppitem)
+ setattr(scope.__class__, name, pycppitem)
+ pycppitem = getattr(scope, name) # binds function as needed
+ except AttributeError:
+ pass
+
+ # data
+ if not cppitem:
+ try:
+ cppitem = scope._cpp_proxy.get_datamember(name)
+ pycppitem = make_datamember(cppitem)
+ setattr(scope, name, pycppitem)
+ if cppitem.is_static():
+ setattr(scope.__class__, name, pycppitem)
+ pycppitem = getattr(scope, name) # gets actual property value
+ except AttributeError:
+ pass
+
+ if not (pycppitem is None): # pycppitem could be a bound C++ NULL, so check explicitly for Py_None
+ return pycppitem
+
+ raise AttributeError("'%s' has no attribute '%s'" % (str(scope), name))
+
+
+def scope_splitter(name):
+ is_open_template, scope = 0, ""
+ for c in name:
+ if c == ':' and not is_open_template:
+ if scope:
+ yield scope
+ scope = ""
+ continue
+ elif c == '<':
+ is_open_template += 1
+ elif c == '>':
+ is_open_template -= 1
+ scope += c
+ yield scope
+
+def get_pycppclass(name):
+ # break up the name, to walk the scopes and get the class recursively
+ scope = gbl
+ for part in scope_splitter(name):
+ scope = getattr(scope, part)
+ return scope
+
+
+# pythonization by decoration (move to their own file?)
+def python_style_getitem(self, idx):
+ # python-style indexing: check for size and allow indexing from the back
+ sz = len(self)
+ if idx < 0: idx = sz + idx
+ if idx < sz:
+ return self._getitem__unchecked(idx)
+ raise IndexError('index out of range: %d requested for %s of size %d' % (idx, str(self), sz))
+
+def python_style_sliceable_getitem(self, slice_or_idx):
+ if type(slice_or_idx) == types.SliceType:
+ nseq = self.__class__()
+ nseq += [python_style_getitem(self, i) \
+ for i in range(*slice_or_idx.indices(len(self)))]
+ return nseq
+ else:
+ return python_style_getitem(self, slice_or_idx)
+
+_pythonizations = {}
+def _pythonize(pyclass):
+
+ try:
+ _pythonizations[pyclass.__name__](pyclass)
+ except KeyError:
+ pass
+
+ # map size -> __len__ (generally true for STL)
+ if hasattr(pyclass, 'size') and \
+ not hasattr(pyclass, '__len__') and callable(pyclass.size):
+ pyclass.__len__ = pyclass.size
+
+ # map push_back -> __iadd__ (generally true for STL)
+ if hasattr(pyclass, 'push_back') and not hasattr(pyclass, '__iadd__'):
+ def __iadd__(self, ll):
+ [self.push_back(x) for x in ll]
+ return self
+ pyclass.__iadd__ = __iadd__
+
+ # for STL iterators, whose comparison functions live globally for gcc
+ # TODO: this needs to be solved fundamentally for all classes
+ if 'iterator' in pyclass.__name__:
+ if hasattr(gbl, '__gnu_cxx'):
+ if hasattr(gbl.__gnu_cxx, '__eq__'):
+ setattr(pyclass, '__eq__', gbl.__gnu_cxx.__eq__)
+ if hasattr(gbl.__gnu_cxx, '__ne__'):
+ setattr(pyclass, '__ne__', gbl.__gnu_cxx.__ne__)
+
+ # map begin()/end() protocol to iter protocol
+ if hasattr(pyclass, 'begin') and hasattr(pyclass, 'end'):
+ # TODO: make gnu-independent
+ def __iter__(self):
+ iter = self.begin()
+ while gbl.__gnu_cxx.__ne__(iter, self.end()):
+ yield iter.__deref__()
+ iter.__preinc__()
+ iter.destruct()
+ raise StopIteration
+ pyclass.__iter__ = __iter__
+
+ # combine __getitem__ and __len__ to make a pythonized __getitem__
+ if hasattr(pyclass, '__getitem__') and hasattr(pyclass, '__len__'):
+ pyclass._getitem__unchecked = pyclass.__getitem__
+ if hasattr(pyclass, '__setitem__') and hasattr(pyclass, '__iadd__'):
+ pyclass.__getitem__ = python_style_sliceable_getitem
+ else:
+ pyclass.__getitem__ = python_style_getitem
+
+ # string comparisons (note: CINT backend requires the simple name 'string')
+ if pyclass.__name__ == 'std::basic_string<char>' or pyclass.__name__ == 'string':
+ def eq(self, other):
+ if type(other) == pyclass:
+ return self.c_str() == other.c_str()
+ else:
+ return self.c_str() == other
+ pyclass.__eq__ = eq
+ pyclass.__str__ = pyclass.c_str
+
+ # TODO: clean this up
+ # fixup lack of __getitem__ if no const return
+ if hasattr(pyclass, '__setitem__') and not hasattr(pyclass, '__getitem__'):
+ pyclass.__getitem__ = pyclass.__setitem__
+
+_loaded_dictionaries = {}
+def load_reflection_info(name):
+ try:
+ return _loaded_dictionaries[name]
+ except KeyError:
+ dct = cppyy._load_dictionary(name)
+ _loaded_dictionaries[name] = dct
+ return dct
+
+
+# user interface objects (note the two-step of not calling scope_byname here:
+# creation of global functions may cause the creation of classes in the global
+# namespace, so gbl must exist at that point to cache them)
+gbl = make_cppnamespace(None, "::", None, False) # global C++ namespace
+
+# mostly for the benefit of the CINT backend, which treats std as special
+gbl.std = make_cppnamespace(None, "std", None, False)
+
+# user-defined pythonizations interface
+_pythonizations = {}
+def add_pythonization(class_name, callback):
+ if not callable(callback):
+ raise TypeError("given '%s' object is not callable" % str(callback))
+ _pythonizations[class_name] = callback
diff --git a/pypy/module/cppyy/src/cintcwrapper.cxx b/pypy/module/cppyy/src/cintcwrapper.cxx
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/src/cintcwrapper.cxx
@@ -0,0 +1,791 @@
+#include "cppyy.h"
+#include "cintcwrapper.h"
+
+#include "Api.h"
+
+#include "TROOT.h"
+#include "TError.h"
+#include "TList.h"
+#include "TSystem.h"
+
+#include "TApplication.h"
+#include "TInterpreter.h"
+#include "Getline.h"
+
+#include "TBaseClass.h"
+#include "TClass.h"
+#include "TClassEdit.h"
+#include "TClassRef.h"
+#include "TDataMember.h"
+#include "TFunction.h"
+#include "TGlobal.h"
+#include "TMethod.h"
+#include "TMethodArg.h"
+
+#include <assert.h>
+#include <string.h>
+#include <map>
+#include <sstream>
+#include <string>
+#include <utility>
+
+
+/* CINT internals (some won't work on Windows) -------------------------- */
+extern long G__store_struct_offset;
+extern "C" void* G__SetShlHandle(char*);
+extern "C" void G__LockCriticalSection();
+extern "C" void G__UnlockCriticalSection();
+
+#define G__SETMEMFUNCENV (long)0x7fff0035
+#define G__NOP (long)0x7fff00ff
+
+namespace {
+
+class Cppyy_OpenedTClass : public TDictionary {
+public:
+ mutable TObjArray* fStreamerInfo; //Array of TVirtualStreamerInfo
+ mutable std::map<std::string, TObjArray*>* fConversionStreamerInfo; //Array of the streamer infos derived from another class.
+ TList* fRealData; //linked list for persistent members including base classes
+ TList* fBase; //linked list for base classes
+ TList* fData; //linked list for data members
+ TList* fMethod; //linked list for methods
+ TList* fAllPubData; //all public data members (including from base classes)
+ TList* fAllPubMethod; //all public methods (including from base classes)
+};
+
+} // unnamed namespace
+
+
+/* data for life time management ------------------------------------------ */
+#define GLOBAL_HANDLE 1l
+
+typedef std::vector<TClassRef> ClassRefs_t;
+static ClassRefs_t g_classrefs(1);
+
+typedef std::map<std::string, ClassRefs_t::size_type> ClassRefIndices_t;
+static ClassRefIndices_t g_classref_indices;
+
+class ClassRefsInit {
+public:
+ ClassRefsInit() { // setup dummy holders for global and std namespaces
+ assert(g_classrefs.size() == (ClassRefs_t::size_type)GLOBAL_HANDLE);
+ g_classref_indices[""] = (ClassRefs_t::size_type)GLOBAL_HANDLE;
+ g_classrefs.push_back(TClassRef(""));
+ g_classref_indices["std"] = g_classrefs.size();
+ g_classrefs.push_back(TClassRef("")); // CINT ignores std
+ g_classref_indices["::std"] = g_classrefs.size();
+ g_classrefs.push_back(TClassRef("")); // id.
+ }
+};
+static ClassRefsInit _classrefs_init;
+
+typedef std::vector<TFunction> GlobalFuncs_t;
+static GlobalFuncs_t g_globalfuncs;
+
+typedef std::vector<TGlobal> GlobalVars_t;
+static GlobalVars_t g_globalvars;
+
+
+/* initialization of the ROOT system (debatable ... ) --------------------- */
+namespace {
+
+class TCppyyApplication : public TApplication {
+public:
+ TCppyyApplication(const char* acn, Int_t* argc, char** argv, Bool_t do_load = kTRUE)
+ : TApplication(acn, argc, argv) {
+
+ // Explicitly load libMathCore as CINT will not auto load it when using one
+ // of its globals. Once moved to Cling, which should work correctly, we
+ // can remove this statement.
+ gSystem->Load("libMathCore");
+
+ if (do_load) {
+ // follow TRint to minimize differences with CINT
+ ProcessLine("#include <iostream>", kTRUE);
+ ProcessLine("#include <_string>", kTRUE); // for std::string iostream.
+ ProcessLine("#include <DllImport.h>", kTRUE);// Defined R__EXTERN
+ ProcessLine("#include <vector>", kTRUE); // needed because they're used within the
+ ProcessLine("#include <pair>", kTRUE); // core ROOT dicts and CINT won't be able
+ // to properly unload these files
+ }
+
+ // save current interpreter context
+ gInterpreter->SaveContext();
+ gInterpreter->SaveGlobalsContext();
+
+ // prevent crashes on accessing history
+ Gl_histinit((char*)"-");
+
+ // prevent ROOT from exiting python
+ SetReturnFromRun(kTRUE);
+
+ // enable auto-loader
+ gInterpreter->EnableAutoLoading();
+ }
+};
+
+static const char* appname = "pypy-cppyy";
+
+class ApplicationStarter {
+public:
+ ApplicationStarter() {
+ if (!gApplication) {
+ int argc = 1;
+ char* argv[1]; argv[0] = (char*)appname;
+ gApplication = new TCppyyApplication(appname, &argc, argv, kTRUE);
+ }
+ }
+} _applicationStarter;
+
+} // unnamed namespace
+
+
+/* local helpers ---------------------------------------------------------- */
+static inline char* cppstring_to_cstring(const std::string& name) {
+ char* name_char = (char*)malloc(name.size() + 1);
+ strcpy(name_char, name.c_str());
+ return name_char;
+}
+
+static inline char* type_cppstring_to_cstring(const std::string& tname) {
+ G__TypeInfo ti(tname.c_str());
+ std::string true_name = ti.IsValid() ? ti.TrueName() : tname;
+ return cppstring_to_cstring(true_name);
+}
+
+static inline TClassRef type_from_handle(cppyy_type_t handle) {
+ return g_classrefs[(ClassRefs_t::size_type)handle];
+}
+
+static inline TFunction* type_get_method(cppyy_type_t handle, int method_index) {
+ TClassRef cr = type_from_handle(handle);
+ if (cr.GetClass())
+ return (TFunction*)cr->GetListOfMethods()->At(method_index);
+ return &g_globalfuncs[method_index];
+}
+
+
+static inline void fixup_args(G__param* libp) {
+ for (int i = 0; i < libp->paran; ++i) {
+ libp->para[i].ref = libp->para[i].obj.i;
+ const char partype = libp->para[i].type;
+ switch (partype) {
+ case 'p': {
+ libp->para[i].obj.i = (long)&libp->para[i].ref;
+ break;
+ }
+ case 'r': {
+ libp->para[i].ref = (long)&libp->para[i].obj.i;
+ break;
+ }
+ case 'f': {
+ assert(sizeof(float) <= sizeof(long));
+ long val = libp->para[i].obj.i;
+ void* pval = (void*)&val;
+ libp->para[i].obj.d = *(float*)pval;
+ break;
+ }
+ case 'F': {
+ libp->para[i].ref = (long)&libp->para[i].obj.i;
+ libp->para[i].type = 'f';
+ break;
+ }
+ case 'D': {
+ libp->para[i].ref = (long)&libp->para[i].obj.i;
+ libp->para[i].type = 'd';
+ break;
+
+ }
+ }
+ }
+}
+
+
+/* name to opaque C++ scope representation -------------------------------- */
+char* cppyy_resolve_name(const char* cppitem_name) {
+ if (strcmp(cppitem_name, "") == 0)
+ return cppstring_to_cstring(cppitem_name);
+ G__TypeInfo ti(cppitem_name);
+ if (ti.IsValid()) {
+ if (ti.Property() & G__BIT_ISENUM)
+ return cppstring_to_cstring("unsigned int");
+ return cppstring_to_cstring(ti.TrueName());
+ }
+ return cppstring_to_cstring(cppitem_name);
+}
+
+cppyy_scope_t cppyy_get_scope(const char* scope_name) {
+ ClassRefIndices_t::iterator icr = g_classref_indices.find(scope_name);
+ if (icr != g_classref_indices.end())
+ return (cppyy_type_t)icr->second;
+
+ // use TClass directly, to enable auto-loading
+ TClassRef cr(TClass::GetClass(scope_name, kTRUE, kTRUE));
+ if (!cr.GetClass())
+ return (cppyy_type_t)NULL;
+
+ if (!cr->GetClassInfo())
+ return (cppyy_type_t)NULL;
+
+ if (!G__TypeInfo(scope_name).IsValid())
+ return (cppyy_type_t)NULL;
+
+ ClassRefs_t::size_type sz = g_classrefs.size();
+ g_classref_indices[scope_name] = sz;
+ g_classrefs.push_back(TClassRef(scope_name));
+ return (cppyy_scope_t)sz;
+}
+
+cppyy_type_t cppyy_get_template(const char* template_name) {
+ ClassRefIndices_t::iterator icr = g_classref_indices.find(template_name);
+ if (icr != g_classref_indices.end())
+ return (cppyy_type_t)icr->second;
+
+ if (!G__defined_templateclass((char*)template_name))
+ return (cppyy_type_t)NULL;
+
+ // the following yields a dummy TClassRef, but its name can be queried
+ ClassRefs_t::size_type sz = g_classrefs.size();
+ g_classref_indices[template_name] = sz;
+ g_classrefs.push_back(TClassRef(template_name));
+ return (cppyy_type_t)sz;
+}
+
+cppyy_type_t cppyy_actual_class(cppyy_type_t klass, cppyy_object_t obj) {
+ TClassRef cr = type_from_handle(klass);
+ TClass* clActual = cr->GetActualClass( (void*)obj );
+ if (clActual && clActual != cr.GetClass()) {
+ // TODO: lookup through name should not be needed
+ return (cppyy_type_t)cppyy_get_scope(clActual->GetName());
+ }
+ return klass;
+}
+
+/* memory management ------------------------------------------------------ */
+cppyy_object_t cppyy_allocate(cppyy_type_t handle) {
+ TClassRef cr = type_from_handle(handle);
+ return (cppyy_object_t)malloc(cr->Size());
+}
+
+void cppyy_deallocate(cppyy_type_t /*handle*/, cppyy_object_t instance) {
+ free((void*)instance);
+}
+
+void cppyy_destruct(cppyy_type_t handle, cppyy_object_t self) {
+ TClassRef cr = type_from_handle(handle);
+ cr->Destructor((void*)self, true);
+}
+
+
+/* method/function dispatching -------------------------------------------- */
+static inline G__value cppyy_call_T(cppyy_method_t method,
+ cppyy_object_t self, int nargs, void* args) {
+
+ G__InterfaceMethod meth = (G__InterfaceMethod)method;
+ G__param* libp = (G__param*)((char*)args - offsetof(G__param, para));
+ assert(libp->paran == nargs);
+ fixup_args(libp);
+
+ G__value result;
+ G__setnull(&result);
+
+ G__LockCriticalSection(); // CINT-level lock, is recursive
+ G__settemplevel(1);
+
+ long index = (long)&method;
+ G__CurrentCall(G__SETMEMFUNCENV, 0, &index);
+
+ // TODO: access to store_struct_offset won't work on Windows
+ long store_struct_offset = G__store_struct_offset;
+ if (self)
+ G__store_struct_offset = (long)self;
+
+ meth(&result, 0, libp, 0);
+ if (self)
+ G__store_struct_offset = store_struct_offset;
+
+ if (G__get_return(0) > G__RETURN_NORMAL)
+ G__security_recover(0); // 0 ensures silence
+
+ G__CurrentCall(G__NOP, 0, 0);
+ G__settemplevel(-1);
+ G__UnlockCriticalSection();
+
+ return result;
+}
+
+void cppyy_call_v(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ cppyy_call_T(method, self, nargs, args);
+}
+
+int cppyy_call_b(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ G__value result = cppyy_call_T(method, self, nargs, args);
+ return (bool)G__int(result);
+}
+
+char cppyy_call_c(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ G__value result = cppyy_call_T(method, self, nargs, args);
+ return (char)G__int(result);
+}
+
+short cppyy_call_h(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ G__value result = cppyy_call_T(method, self, nargs, args);
+ return (short)G__int(result);
+}
+
+int cppyy_call_i(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ G__value result = cppyy_call_T(method, self, nargs, args);
+ return (int)G__int(result);
+}
+
+long cppyy_call_l(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ G__value result = cppyy_call_T(method, self, nargs, args);
+ return G__int(result);
+}
+
+long long cppyy_call_ll(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ G__value result = cppyy_call_T(method, self, nargs, args);
+ return G__Longlong(result);
+}
+
+double cppyy_call_f(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ G__value result = cppyy_call_T(method, self, nargs, args);
+ return G__double(result);
+}
+
+double cppyy_call_d(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ G__value result = cppyy_call_T(method, self, nargs, args);
+ return G__double(result);
+}
+
+void* cppyy_call_r(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ G__value result = cppyy_call_T(method, self, nargs, args);
+ return (void*)result.ref;
+}
+
+char* cppyy_call_s(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ G__value result = cppyy_call_T(method, self, nargs, args);
+ G__pop_tempobject_nodel();
+ if (result.ref && *(long*)result.ref) {
+ char* charp = cppstring_to_cstring(*(std::string*)result.ref);
+ delete (std::string*)result.ref;
+ return charp;
+ }
+ return cppstring_to_cstring("");
+}
+
+void cppyy_constructor(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ G__setgvp((long)self);
+ cppyy_call_T(method, self, nargs, args);
+ G__setgvp((long)G__PVOID);
+}
+
+cppyy_object_t cppyy_call_o(cppyy_type_t method, cppyy_object_t self, int nargs, void* args,
+ cppyy_type_t /*result_type*/ ) {
+ G__value result = cppyy_call_T(method, self, nargs, args);
+ G__pop_tempobject_nodel();
+ return G__int(result);
+}
+
+cppyy_methptrgetter_t cppyy_get_methptr_getter(cppyy_type_t /*handle*/, int /*method_index*/) {
+ return (cppyy_methptrgetter_t)NULL;
+}
+
+
+/* handling of function argument buffer ----------------------------------- */
+void* cppyy_allocate_function_args(size_t nargs) {
+ assert(sizeof(CPPYY_G__value) == sizeof(G__value));
+ G__param* libp = (G__param*)malloc(
+ offsetof(G__param, para) + nargs*sizeof(CPPYY_G__value));
+ libp->paran = (int)nargs;
+ for (size_t i = 0; i < nargs; ++i)
+ libp->para[i].type = 'l';
+ return (void*)libp->para;
+}
+
+void cppyy_deallocate_function_args(void* args) {
+ free((char*)args - offsetof(G__param, para));
+}
+
+size_t cppyy_function_arg_sizeof() {
+ return sizeof(CPPYY_G__value);
+}
+
+size_t cppyy_function_arg_typeoffset() {
+ return offsetof(CPPYY_G__value, type);
+}
+
+
+/* scope reflection information ------------------------------------------- */
+int cppyy_is_namespace(cppyy_scope_t handle) {
+ TClassRef cr = type_from_handle(handle);
+ if (cr.GetClass() && cr->GetClassInfo())
+ return cr->Property() & G__BIT_ISNAMESPACE;
+ if (strcmp(cr.GetClassName(), "") == 0)
+ return true;
+ return false;
+}
+
+int cppyy_is_enum(const char* type_name) {
+ G__TypeInfo ti(type_name);
+ return (ti.Property() & G__BIT_ISENUM);
+}
+
+
+/* type/class reflection information -------------------------------------- */
+char* cppyy_final_name(cppyy_type_t handle) {
+ TClassRef cr = type_from_handle(handle);
+ if (cr.GetClass() && cr->GetClassInfo()) {
+ std::string true_name = G__TypeInfo(cr->GetName()).TrueName();
+ std::string::size_type pos = true_name.rfind("::");
+ if (pos != std::string::npos)
+ return cppstring_to_cstring(true_name.substr(pos+2, std::string::npos));
+ return cppstring_to_cstring(true_name);
+ }
+ return cppstring_to_cstring(cr.GetClassName());
+}
+
+char* cppyy_scoped_final_name(cppyy_type_t handle) {
+ TClassRef cr = type_from_handle(handle);
+ if (cr.GetClass() && cr->GetClassInfo()) {
+ std::string true_name = G__TypeInfo(cr->GetName()).TrueName();
+ return cppstring_to_cstring(true_name);
+ }
+ return cppstring_to_cstring(cr.GetClassName());
+}
+
+int cppyy_has_complex_hierarchy(cppyy_type_t handle) {
+// as long as no fast path is supported for CINT, calculating offsets (which
+// are cached by the JIT) is not going to hurt
+ return 1;
+}
+
+int cppyy_num_bases(cppyy_type_t handle) {
+ TClassRef cr = type_from_handle(handle);
+ if (cr.GetClass() && cr->GetListOfBases() != 0)
+ return cr->GetListOfBases()->GetSize();
+ return 0;
+}
+
+char* cppyy_base_name(cppyy_type_t handle, int base_index) {
+ TClassRef cr = type_from_handle(handle);
+ TBaseClass* b = (TBaseClass*)cr->GetListOfBases()->At(base_index);
+ return type_cppstring_to_cstring(b->GetName());
+}
+
+int cppyy_is_subtype(cppyy_type_t derived_handle, cppyy_type_t base_handle) {
+ TClassRef derived_type = type_from_handle(derived_handle);
+ TClassRef base_type = type_from_handle(base_handle);
+ return derived_type->GetBaseClass(base_type) != 0;
+}
+
+size_t cppyy_base_offset(cppyy_type_t derived_handle, cppyy_type_t base_handle,
+ cppyy_object_t address, int /* direction */) {
+ // WARNING: CINT can not handle actual dynamic casts!
+ TClassRef derived_type = type_from_handle(derived_handle);
+ TClassRef base_type = type_from_handle(base_handle);
+
+ long offset = 0;
+
+ if (derived_type && base_type) {
+ G__ClassInfo* base_ci = (G__ClassInfo*)base_type->GetClassInfo();
+ G__ClassInfo* derived_ci = (G__ClassInfo*)derived_type->GetClassInfo();
+
+ if (base_ci && derived_ci) {
+#ifdef WIN32
+ // Windows cannot cast-to-derived for virtual inheritance
+ // with CINT's (or Reflex's) interfaces.
+ long baseprop = derived_ci->IsBase(*base_ci);
+ if (!baseprop || (baseprop & G__BIT_ISVIRTUALBASE))
+ offset = derived_type->GetBaseClassOffset(base_type);
+ else
+#endif
+ offset = G__isanybase(base_ci->Tagnum(), derived_ci->Tagnum(), (long)address);
+ } else {
+ offset = derived_type->GetBaseClassOffset(base_type);
+ }
+ }
+
+ return (size_t) offset; // may be negative (will roll over)
+}
+
+
+/* method/function reflection information --------------------------------- */
+int cppyy_num_methods(cppyy_scope_t handle) {
+ TClassRef cr = type_from_handle(handle);
+ if (cr.GetClass() && cr->GetListOfMethods())
+ return cr->GetListOfMethods()->GetSize();
+ else if (strcmp(cr.GetClassName(), "") == 0) {
+ // NOTE: the updated list of global funcs grows with 5 "G__ateval"'s just
+ // because it is being updated => infinite loop! Apply offset to correct ...
+ static int ateval_offset = 0;
+ TCollection* funcs = gROOT->GetListOfGlobalFunctions(kTRUE);
+ ateval_offset += 5;
+ if (g_globalfuncs.size() <= (GlobalFuncs_t::size_type)funcs->GetSize() - ateval_offset) {
+ g_globalfuncs.clear();
+ g_globalfuncs.reserve(funcs->GetSize());
+
+ TIter ifunc(funcs);
+
+ TFunction* func = 0;
+ while ((func = (TFunction*)ifunc.Next())) {
+ if (strcmp(func->GetName(), "G__ateval") == 0)
+ ateval_offset += 1;
+ else
+ g_globalfuncs.push_back(*func);
+ }
+ }
+ return (int)g_globalfuncs.size();
+ }
+ return 0;
+}
+
+char* cppyy_method_name(cppyy_scope_t handle, int method_index) {
+ TFunction* f = type_get_method(handle, method_index);
+ return cppstring_to_cstring(f->GetName());
+}
+
+char* cppyy_method_result_type(cppyy_scope_t handle, int method_index) {
+ TFunction* f = 0;
+ TClassRef cr = type_from_handle(handle);
+ if (cr.GetClass()) {
+ if (cppyy_is_constructor(handle, method_index))
+ return cppstring_to_cstring("constructor");
+ f = (TFunction*)cr->GetListOfMethods()->At(method_index);
+ } else
+ f = &g_globalfuncs[method_index];
+ return type_cppstring_to_cstring(f->GetReturnTypeName());
+}
+
+int cppyy_method_num_args(cppyy_scope_t handle, int method_index) {
+ TFunction* f = type_get_method(handle, method_index);
+ return f->GetNargs();
+}
+
+int cppyy_method_req_args(cppyy_scope_t handle, int method_index) {
+ TFunction* f = type_get_method(handle, method_index);
+ return f->GetNargs() - f->GetNargsOpt();
+}
+
+char* cppyy_method_arg_type(cppyy_scope_t handle, int method_index, int arg_index) {
+ TFunction* f = type_get_method(handle, method_index);
+ TMethodArg* arg = (TMethodArg*)f->GetListOfMethodArgs()->At(arg_index);
+ return type_cppstring_to_cstring(arg->GetFullTypeName());
+}
+
+char* cppyy_method_arg_default(cppyy_scope_t, int, int) {
+ /* unused: libffi does not work with CINT back-end */
+ return cppstring_to_cstring("");
+}
+
+char* cppyy_method_signature(cppyy_scope_t handle, int method_index) {
+ TFunction* f = type_get_method(handle, method_index);
+ TClassRef cr = type_from_handle(handle);
+ std::ostringstream sig;
+ if (cr.GetClass() && cr->GetClassInfo()
+ && strcmp(f->GetName(), ((G__ClassInfo*)cr->GetClassInfo())->Name()) != 0)
+ sig << f->GetReturnTypeName() << " ";
+ sig << cr.GetClassName() << "::" << f->GetName() << "(";
+ int nArgs = f->GetNargs();
+ for (int iarg = 0; iarg < nArgs; ++iarg) {
+ sig << ((TMethodArg*)f->GetListOfMethodArgs()->At(iarg))->GetFullTypeName();
+ if (iarg != nArgs-1)
+ sig << ", ";
+ }
+ sig << ")" << std::ends;
+ return cppstring_to_cstring(sig.str());
+}
+
+int cppyy_method_index(cppyy_scope_t handle, const char* name) {
+ TClassRef cr = type_from_handle(handle);
+ if (cr.GetClass()) {
+ gInterpreter->UpdateListOfMethods(cr.GetClass());
+ int imeth = 0;
+ TFunction* func;
+ TIter next(cr->GetListOfMethods());
+ while ((func = (TFunction*)next())) {
+ if (strcmp(name, func->GetName()) == 0) {
+ if (func->Property() & G__BIT_ISPUBLIC)
+ return imeth;
+ return -1;
+ }
+ ++imeth;
+ }
+ }
+ TFunction* func = gROOT->GetGlobalFunction(name, NULL, kTRUE);
+ if (!func)
+ return -1;
+ int idx = g_globalfuncs.size();
+ g_globalfuncs.push_back(*func);
+ return idx;
+}
+
+cppyy_method_t cppyy_get_method(cppyy_scope_t handle, int method_index) {
+ TFunction* f = type_get_method(handle, method_index);
+ return (cppyy_method_t)f->InterfaceMethod();
+}
+
+
+/* method properties ----------------------------------------------------- */
+int cppyy_is_constructor(cppyy_type_t handle, int method_index) {
+ TClassRef cr = type_from_handle(handle);
+ TMethod* m = (TMethod*)cr->GetListOfMethods()->At(method_index);
+ return strcmp(m->GetName(), ((G__ClassInfo*)cr->GetClassInfo())->Name()) == 0;
+}
+
+int cppyy_is_staticmethod(cppyy_type_t handle, int method_index) {
+ TClassRef cr = type_from_handle(handle);
+ TMethod* m = (TMethod*)cr->GetListOfMethods()->At(method_index);
+ return m->Property() & G__BIT_ISSTATIC;
+}
+
+
+/* data member reflection information ------------------------------------- */
+int cppyy_num_datamembers(cppyy_scope_t handle) {
+ TClassRef cr = type_from_handle(handle);
+ if (cr.GetClass() && cr->GetListOfDataMembers())
+ return cr->GetListOfDataMembers()->GetSize();
+ else if (strcmp(cr.GetClassName(), "") == 0) {
+ TCollection* vars = gROOT->GetListOfGlobals(kTRUE);
+ if (g_globalvars.size() != (GlobalVars_t::size_type)vars->GetSize()) {
+ g_globalvars.clear();
+ g_globalvars.reserve(vars->GetSize());
+
+ TIter ivar(vars);
+
+ TGlobal* var = 0;
+ while ((var = (TGlobal*)ivar.Next()))
+ g_globalvars.push_back(*var);
+
+ }
+ return (int)g_globalvars.size();
+ }
+ return 0;
+}
+
+char* cppyy_datamember_name(cppyy_scope_t handle, int datamember_index) {
+ TClassRef cr = type_from_handle(handle);
+ if (cr.GetClass()) {
+ TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At(datamember_index);
+ return cppstring_to_cstring(m->GetName());
+ }
+ TGlobal& gbl = g_globalvars[datamember_index];
+ return cppstring_to_cstring(gbl.GetName());
+}
+
+char* cppyy_datamember_type(cppyy_scope_t handle, int datamember_index) {
+ TClassRef cr = type_from_handle(handle);
+ if (cr.GetClass()) {
+ TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At(datamember_index);
+ std::string fullType = m->GetFullTypeName();
+ if ((int)m->GetArrayDim() > 1 || (!m->IsBasic() && m->IsaPointer()))
+ fullType.append("*");
+ else if ((int)m->GetArrayDim() == 1) {
+ std::ostringstream s;
+ s << '[' << m->GetMaxIndex(0) << ']' << std::ends;
+ fullType.append(s.str());
+ }
+ return cppstring_to_cstring(fullType);
+ }
+ TGlobal& gbl = g_globalvars[datamember_index];
+ return cppstring_to_cstring(gbl.GetFullTypeName());
+}
+
+size_t cppyy_datamember_offset(cppyy_scope_t handle, int datamember_index) {
+ TClassRef cr = type_from_handle(handle);
+ if (cr.GetClass()) {
+ TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At(datamember_index);
+ return (size_t)m->GetOffsetCint();
+ }
+ TGlobal& gbl = g_globalvars[datamember_index];
+ return (size_t)gbl.GetAddress();
+}
+
+int cppyy_datamember_index(cppyy_scope_t handle, const char* name) {
+ TClassRef cr = type_from_handle(handle);
+ if (cr.GetClass()) {
+ // called from updates; add a hard reset as the code itself caches in
+ // Class (TODO: by-pass ROOT/meta)
+ Cppyy_OpenedTClass* c = (Cppyy_OpenedTClass*)cr.GetClass();
+ if (c->fData) {
+ c->fData->Delete();
+ delete c->fData; c->fData = 0;
+ delete c->fAllPubData; c->fAllPubData = 0;
+ }
+ // the following appears dumb, but TClass::GetDataMember() does a linear
+ // search itself, so there is no gain
+ int idm = 0;
+ TDataMember* dm;
+ TIter next(cr->GetListOfDataMembers());
+ while ((dm = (TDataMember*)next())) {
+ if (strcmp(name, dm->GetName()) == 0) {
+ if (dm->Property() & G__BIT_ISPUBLIC)
+ return idm;
+ return -1;
+ }
+ ++idm;
+ }
+ }
+ TGlobal* gbl = (TGlobal*)gROOT->GetListOfGlobals(kTRUE)->FindObject(name);
+ if (!gbl)
+ return -1;
+ int idx = g_globalvars.size();
+ g_globalvars.push_back(*gbl);
+ return idx;
+}
+
+
+/* data member properties ------------------------------------------------ */
+int cppyy_is_publicdata(cppyy_scope_t handle, int datamember_index) {
+ TClassRef cr = type_from_handle(handle);
+ if (cr.GetClass()) {
+ TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At(datamember_index);
+ return m->Property() & G__BIT_ISPUBLIC;
+ }
+ return 1; // global data is always public
+}
+
+int cppyy_is_staticdata(cppyy_scope_t handle, int datamember_index) {
+ TClassRef cr = type_from_handle(handle);
+ if (cr.GetClass()) {
+ TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At(datamember_index);
+ return m->Property() & G__BIT_ISSTATIC;
+ }
+ return 1; // global data is always static
+}
+
+
+/* misc helpers ----------------------------------------------------------- */
+long long cppyy_strtoll(const char* str) {
+ return strtoll(str, NULL, 0);
+}
+
+extern "C" unsigned long long cppyy_strtoull(const char* str) {
+ return strtoull(str, NULL, 0);
+}
+
+void cppyy_free(void* ptr) {
+ free(ptr);
+}
+
+cppyy_object_t cppyy_charp2stdstring(const char* str) {
+ return (cppyy_object_t)new std::string(str);
+}
+
+cppyy_object_t cppyy_stdstring2stdstring(cppyy_object_t ptr) {
+ return (cppyy_object_t)new std::string(*(std::string*)ptr);
+}
+
+void cppyy_free_stdstring(cppyy_object_t ptr) {
+ delete (std::string*)ptr;
+}
+
+void cppyy_assign2stdstring(cppyy_object_t ptr, const char* str) {
+ *((std::string*)ptr) = str;
+}
+
+void* cppyy_load_dictionary(const char* lib_name) {
+ if (0 <= gSystem->Load(lib_name))
+ return (void*)1;
+ return (void*)0;
+}
diff --git a/pypy/module/cppyy/src/reflexcwrapper.cxx b/pypy/module/cppyy/src/reflexcwrapper.cxx
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/src/reflexcwrapper.cxx
@@ -0,0 +1,541 @@
+#include "cppyy.h"
+#include "reflexcwrapper.h"
+
+#include "Reflex/Kernel.h"
+#include "Reflex/Type.h"
+#include "Reflex/Base.h"
+#include "Reflex/Member.h"
+#include "Reflex/Object.h"
+#include "Reflex/Builder/TypeBuilder.h"
+#include "Reflex/PropertyList.h"
+#include "Reflex/TypeTemplate.h"
+
+#define private public
+#include "Reflex/PluginService.h"
+#undef private
+
+#include <string>
+#include <sstream>
+#include <utility>
+#include <vector>
+
+#include <assert.h>
+#include <stdlib.h>
+
+
+/* local helpers ---------------------------------------------------------- */
+static inline char* cppstring_to_cstring(const std::string& name) {
+ char* name_char = (char*)malloc(name.size() + 1);
+ strcpy(name_char, name.c_str());
+ return name_char;
+}
+
+static inline Reflex::Scope scope_from_handle(cppyy_type_t handle) {
+ return Reflex::Scope((Reflex::ScopeName*)handle);
+}
+
+static inline Reflex::Type type_from_handle(cppyy_type_t handle) {
+ return Reflex::Scope((Reflex::ScopeName*)handle);
+}
+
+static inline std::vector<void*> build_args(int nargs, void* args) {
+ std::vector<void*> arguments;
+ arguments.reserve(nargs);
+ for (int i = 0; i < nargs; ++i) {
+ char tc = ((CPPYY_G__value*)args)[i].type;
+ if (tc != 'a' && tc != 'o')
+ arguments.push_back(&((CPPYY_G__value*)args)[i]);
+ else
+ arguments.push_back((void*)(*(long*)&((CPPYY_G__value*)args)[i]));
+ }
+ return arguments;
+}
+
+
+/* name to opaque C++ scope representation -------------------------------- */
+char* cppyy_resolve_name(const char* cppitem_name) {
+ Reflex::Scope s = Reflex::Scope::ByName(cppitem_name);
+ if (s.IsEnum())
+ return cppstring_to_cstring("unsigned int");
+ const std::string& name = s.Name(Reflex::SCOPED|Reflex::QUALIFIED|Reflex::FINAL);
+ if (name.empty())
+ return cppstring_to_cstring(cppitem_name);
+ return cppstring_to_cstring(name);
+}
+
+cppyy_scope_t cppyy_get_scope(const char* scope_name) {
+ Reflex::Scope s = Reflex::Scope::ByName(scope_name);
+ if (!s) Reflex::PluginService::Instance().LoadFactoryLib(scope_name);
+ s = Reflex::Scope::ByName(scope_name);
+ if (s.IsEnum()) // pretend to be builtin by returning 0
+ return (cppyy_type_t)0;
+ return (cppyy_type_t)s.Id();
+}
+
+cppyy_type_t cppyy_get_template(const char* template_name) {
+ Reflex::TypeTemplate tt = Reflex::TypeTemplate::ByName(template_name);
+ return (cppyy_type_t)tt.Id();
+}
+
+cppyy_type_t cppyy_actual_class(cppyy_type_t klass, cppyy_object_t obj) {
+ Reflex::Type t = type_from_handle(klass);
+ Reflex::Type tActual = t.DynamicType(Reflex::Object(t, (void*)obj));
+ if (tActual && tActual != t) {
+ // TODO: lookup through name should not be needed (but tActual.Id()
+ // does not return a singular Id for the system :( )
+ return (cppyy_type_t)cppyy_get_scope(tActual.Name().c_str());
+ }
+ return klass;
+}
+
+
+/* memory management ------------------------------------------------------ */
+cppyy_object_t cppyy_allocate(cppyy_type_t handle) {
+ Reflex::Type t = type_from_handle(handle);
+ return (cppyy_object_t)t.Allocate();
+}
+
+void cppyy_deallocate(cppyy_type_t handle, cppyy_object_t instance) {
+ Reflex::Type t = type_from_handle(handle);
+ t.Deallocate((void*)instance);
+}
+
+void cppyy_destruct(cppyy_type_t handle, cppyy_object_t self) {
+ Reflex::Type t = type_from_handle(handle);
+ t.Destruct((void*)self, true);
+}
+
+
+/* method/function dispatching -------------------------------------------- */
+void cppyy_call_v(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ std::vector<void*> arguments = build_args(nargs, args);
+ Reflex::StubFunction stub = (Reflex::StubFunction)method;
+ stub(NULL /* return address */, (void*)self, arguments, NULL /* stub context */);
+}
+
+template<typename T>
+static inline T cppyy_call_T(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ T result;
+ std::vector<void*> arguments = build_args(nargs, args);
+ Reflex::StubFunction stub = (Reflex::StubFunction)method;
+ stub(&result, (void*)self, arguments, NULL /* stub context */);
+ return result;
+}
+
+int cppyy_call_b(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ return (int)cppyy_call_T<bool>(method, self, nargs, args);
+}
+
+char cppyy_call_c(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ return cppyy_call_T<char>(method, self, nargs, args);
+}
+
+short cppyy_call_h(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ return cppyy_call_T<short>(method, self, nargs, args);
+}
+
+int cppyy_call_i(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ return cppyy_call_T<int>(method, self, nargs, args);
+}
+
+long cppyy_call_l(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ return cppyy_call_T<long>(method, self, nargs, args);
+}
+
+long long cppyy_call_ll(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ return cppyy_call_T<long long>(method, self, nargs, args);
+}
+
+double cppyy_call_f(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ return cppyy_call_T<float>(method, self, nargs, args);
+}
+
+double cppyy_call_d(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ return cppyy_call_T<double>(method, self, nargs, args);
+}
+
+void* cppyy_call_r(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ return (void*)cppyy_call_T<long>(method, self, nargs, args);
+}
+
+char* cppyy_call_s(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ std::string result("");
+ std::vector<void*> arguments = build_args(nargs, args);
+ Reflex::StubFunction stub = (Reflex::StubFunction)method;
+ stub(&result, (void*)self, arguments, NULL /* stub context */);
+ return cppstring_to_cstring(result);
+}
+
+void cppyy_constructor(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ cppyy_call_v(method, self, nargs, args);
+}
+
+cppyy_object_t cppyy_call_o(cppyy_method_t method, cppyy_object_t self, int nargs, void* args,
+ cppyy_type_t result_type) {
+ void* result = (void*)cppyy_allocate(result_type);
+ std::vector<void*> arguments = build_args(nargs, args);
+ Reflex::StubFunction stub = (Reflex::StubFunction)method;
+ stub(result, (void*)self, arguments, NULL /* stub context */);
+ return (cppyy_object_t)result;
+}
+
+static cppyy_methptrgetter_t get_methptr_getter(Reflex::Member m) {
+ Reflex::PropertyList plist = m.Properties();
+ if (plist.HasProperty("MethPtrGetter")) {
+ Reflex::Any& value = plist.PropertyValue("MethPtrGetter");
+ return (cppyy_methptrgetter_t)Reflex::any_cast<void*>(value);
+ }
+ return 0;
+}
+
+cppyy_methptrgetter_t cppyy_get_methptr_getter(cppyy_type_t handle, int method_index) {
+ Reflex::Scope s = scope_from_handle(handle);
+ Reflex::Member m = s.FunctionMemberAt(method_index);
+ return get_methptr_getter(m);
+}
+
+
+/* handling of function argument buffer ----------------------------------- */
+void* cppyy_allocate_function_args(size_t nargs) {
+ CPPYY_G__value* args = (CPPYY_G__value*)malloc(nargs*sizeof(CPPYY_G__value));
+ for (size_t i = 0; i < nargs; ++i)
+ args[i].type = 'l';
+ return (void*)args;
+}
+
+void cppyy_deallocate_function_args(void* args) {
+ free(args);
+}
+
+size_t cppyy_function_arg_sizeof() {
+ return sizeof(CPPYY_G__value);
+}
+
+size_t cppyy_function_arg_typeoffset() {
+ return offsetof(CPPYY_G__value, type);
+}
+
+
+/* scope reflection information ------------------------------------------- */
+int cppyy_is_namespace(cppyy_scope_t handle) {
+ Reflex::Scope s = scope_from_handle(handle);
+ return s.IsNamespace();
+}
+
+int cppyy_is_enum(const char* type_name) {
+ Reflex::Type t = Reflex::Type::ByName(type_name);
+ return t.IsEnum();
+}
+
+
+/* class reflection information ------------------------------------------- */
+char* cppyy_final_name(cppyy_type_t handle) {
+ Reflex::Scope s = scope_from_handle(handle);
+ if (s.IsEnum())
+ return cppstring_to_cstring("unsigned int");
+ std::string name = s.Name(Reflex::FINAL);
+ return cppstring_to_cstring(name);
+}
+
+char* cppyy_scoped_final_name(cppyy_type_t handle) {
+ Reflex::Scope s = scope_from_handle(handle);
+ if (s.IsEnum())
+ return cppstring_to_cstring("unsigned int");
+ std::string name = s.Name(Reflex::SCOPED | Reflex::FINAL);
+ return cppstring_to_cstring(name);
+}
+
+static int cppyy_has_complex_hierarchy(const Reflex::Type& t) {
+ int is_complex = 1;
+
+ size_t nbases = t.BaseSize();
+ if (1 < nbases)
+ is_complex = 1;
+ else if (nbases == 0)
+ is_complex = 0;
+ else { // one base class only
+ Reflex::Base b = t.BaseAt(0);
+ if (b.IsVirtual())
+ is_complex = 1; // TODO: verify; can be complex, need not be.
+ else
+ is_complex = cppyy_has_complex_hierarchy(t.BaseAt(0).ToType());
+ }
+
+ return is_complex;
+}
+
+int cppyy_has_complex_hierarchy(cppyy_type_t handle) {
+ Reflex::Type t = type_from_handle(handle);
+ return cppyy_has_complex_hierarchy(t);
+}
+
+int cppyy_num_bases(cppyy_type_t handle) {
+ Reflex::Type t = type_from_handle(handle);
+ return t.BaseSize();
+}
+
+char* cppyy_base_name(cppyy_type_t handle, int base_index) {
+ Reflex::Type t = type_from_handle(handle);
+ Reflex::Base b = t.BaseAt(base_index);
+ std::string name = b.Name(Reflex::FINAL|Reflex::SCOPED);
+ return cppstring_to_cstring(name);
+}
+
+int cppyy_is_subtype(cppyy_type_t derived_handle, cppyy_type_t base_handle) {
+ Reflex::Type derived_type = type_from_handle(derived_handle);
+ Reflex::Type base_type = type_from_handle(base_handle);
+ return (int)derived_type.HasBase(base_type);
+}
+
+size_t cppyy_base_offset(cppyy_type_t derived_handle, cppyy_type_t base_handle,
+ cppyy_object_t address, int direction) {
+ Reflex::Type derived_type = type_from_handle(derived_handle);
+ Reflex::Type base_type = type_from_handle(base_handle);
+
+ // when dealing with virtual inheritance the only (reasonably) well-defined info is
+ // in a Reflex internal base table, that contains all offsets within the hierarchy
+ Reflex::Member getbases = derived_type.FunctionMemberByName(
+ "__getBasesTable", Reflex::Type(), 0, Reflex::INHERITEDMEMBERS_NO, Reflex::DELAYEDLOAD_OFF);
+ if (getbases) {
+ typedef std::vector<std::pair<Reflex::Base, int> > Bases_t;
+ Bases_t* bases;
+ Reflex::Object bases_holder(Reflex::Type::ByTypeInfo(typeid(Bases_t)), &bases);
+ getbases.Invoke(&bases_holder);
+
+ // if direction is down-cast, perform the cast in C++ first in order to ensure
+ // we have a derived object for accessing internal offset pointers
+ if (direction < 0) {
+ Reflex::Object o(base_type, (void*)address);
+ address = (cppyy_object_t)o.CastObject(derived_type).Address();
+ }
+
+ for (Bases_t::iterator ibase = bases->begin(); ibase != bases->end(); ++ibase) {
+ if (ibase->first.ToType() == base_type) {
+ long offset = (long)ibase->first.Offset((void*)address);
+ if (direction < 0)
+ return (size_t) -offset; // note negative; rolls over
+ return (size_t)offset;
+ }
+ }
+
+ // contrary to typical invoke()s, the result of the internal getbases function
+ // is a pointer to a function static, so no delete
+ }
+
+ return 0;
+}
+
+
+/* method/function reflection information --------------------------------- */
+int cppyy_num_methods(cppyy_scope_t handle) {
+ Reflex::Scope s = scope_from_handle(handle);
+ return s.FunctionMemberSize();
+}
+
+char* cppyy_method_name(cppyy_scope_t handle, int method_index) {
+ Reflex::Scope s = scope_from_handle(handle);
+ Reflex::Member m = s.FunctionMemberAt(method_index);
+ std::string name;
+ if (m.IsConstructor())
+ name = s.Name(Reflex::FINAL); // to get proper name for templates
+ else
+ name = m.Name();
+ return cppstring_to_cstring(name);
+}
+
+char* cppyy_method_result_type(cppyy_scope_t handle, int method_index) {
+ Reflex::Scope s = scope_from_handle(handle);
+ Reflex::Member m = s.FunctionMemberAt(method_index);
+ if (m.IsConstructor())
+ return cppstring_to_cstring("constructor");
+ Reflex::Type rt = m.TypeOf().ReturnType();
+ std::string name = rt.Name(Reflex::FINAL|Reflex::SCOPED|Reflex::QUALIFIED);
+ return cppstring_to_cstring(name);
+}
+
+int cppyy_method_num_args(cppyy_scope_t handle, int method_index) {
+ Reflex::Scope s = scope_from_handle(handle);
+ Reflex::Member m = s.FunctionMemberAt(method_index);
+ return m.FunctionParameterSize();
+}
+
+int cppyy_method_req_args(cppyy_scope_t handle, int method_index) {
+ Reflex::Scope s = scope_from_handle(handle);
+ Reflex::Member m = s.FunctionMemberAt(method_index);
+ return m.FunctionParameterSize(true);
+}
+
+char* cppyy_method_arg_type(cppyy_scope_t handle, int method_index, int arg_index) {
+ Reflex::Scope s = scope_from_handle(handle);
+ Reflex::Member m = s.FunctionMemberAt(method_index);
+ Reflex::Type at = m.TypeOf().FunctionParameterAt(arg_index);
+ std::string name = at.Name(Reflex::FINAL|Reflex::SCOPED|Reflex::QUALIFIED);
+ return cppstring_to_cstring(name);
+}
+
+char* cppyy_method_arg_default(cppyy_scope_t handle, int method_index, int arg_index) {
+ Reflex::Scope s = scope_from_handle(handle);
+ Reflex::Member m = s.FunctionMemberAt(method_index);
+ std::string dflt = m.FunctionParameterDefaultAt(arg_index);
+ return cppstring_to_cstring(dflt);
+}
+
+char* cppyy_method_signature(cppyy_scope_t handle, int method_index) {
+ Reflex::Scope s = scope_from_handle(handle);
+ Reflex::Member m = s.FunctionMemberAt(method_index);
+ Reflex::Type mt = m.TypeOf();
+ std::ostringstream sig;
+ if (!m.IsConstructor())
+ sig << mt.ReturnType().Name() << " ";
+ sig << s.Name(Reflex::SCOPED) << "::" << m.Name() << "(";
+ int nArgs = m.FunctionParameterSize();
+ for (int iarg = 0; iarg < nArgs; ++iarg) {
+ sig << mt.FunctionParameterAt(iarg).Name(Reflex::SCOPED|Reflex::QUALIFIED);
+ if (iarg != nArgs-1)
+ sig << ", ";
+ }
+ sig << ")" << std::ends;
+ return cppstring_to_cstring(sig.str());
+}
+
+int cppyy_method_index(cppyy_scope_t handle, const char* name) {
+ Reflex::Scope s = scope_from_handle(handle);
+ // the following appears dumb, but the internal storage for Reflex is an
+ // unsorted std::vector anyway, so there's no gain to be had in using the
+ // Scope::FunctionMemberByName() function
+ int num_meth = s.FunctionMemberSize();
+ for (int imeth = 0; imeth < num_meth; ++imeth) {
+ Reflex::Member m = s.FunctionMemberAt(imeth);
+ if (m.Name() == name) {
+ if (m.IsPublic())
+ return imeth;
+ return -1;
+ }
+ }
+ return -1;
+}
+
+cppyy_method_t cppyy_get_method(cppyy_scope_t handle, int method_index) {
+ Reflex::Scope s = scope_from_handle(handle);
+ Reflex::Member m = s.FunctionMemberAt(method_index);
+ assert(m.IsFunctionMember());
+ return (cppyy_method_t)m.Stubfunction();
+}
+
+
+/* method properties ----------------------------------------------------- */
+int cppyy_is_constructor(cppyy_type_t handle, int method_index) {
+ Reflex::Scope s = scope_from_handle(handle);
+ Reflex::Member m = s.FunctionMemberAt(method_index);
+ return m.IsConstructor();
+}
+
+int cppyy_is_staticmethod(cppyy_type_t handle, int method_index) {
+ Reflex::Scope s = scope_from_handle(handle);
+ Reflex::Member m = s.FunctionMemberAt(method_index);
+ return m.IsStatic();
+}
+
+
+/* data member reflection information ------------------------------------- */
+int cppyy_num_datamembers(cppyy_scope_t handle) {
+ Reflex::Scope s = scope_from_handle(handle);
+ // fix enum representation by adding them to the containing scope as per C++
+ // TODO: this (relatively harmlessly) dupes data members when updating in the
+ // case s is a namespace
+ for (int isub = 0; isub < (int)s.ScopeSize(); ++isub) {
+ Reflex::Scope sub = s.SubScopeAt(isub);
+ if (sub.IsEnum()) {
+ for (int idata = 0; idata < (int)sub.DataMemberSize(); ++idata) {
+ Reflex::Member m = sub.DataMemberAt(idata);
+ s.AddDataMember(m.Name().c_str(), sub, 0,
+ Reflex::PUBLIC|Reflex::STATIC|Reflex::ARTIFICIAL,
+ (char*)m.Offset());
+ }
+ }
+ }
+ return s.DataMemberSize();
+}
+
+char* cppyy_datamember_name(cppyy_scope_t handle, int datamember_index) {
+ Reflex::Scope s = scope_from_handle(handle);
+ Reflex::Member m = s.DataMemberAt(datamember_index);
+ std::string name = m.Name();
+ return cppstring_to_cstring(name);
+}
+
+char* cppyy_datamember_type(cppyy_scope_t handle, int datamember_index) {
+ Reflex::Scope s = scope_from_handle(handle);
+ Reflex::Member m = s.DataMemberAt(datamember_index);
+ std::string name = m.TypeOf().Name(Reflex::FINAL|Reflex::SCOPED|Reflex::QUALIFIED);
+ return cppstring_to_cstring(name);
+}
+
+size_t cppyy_datamember_offset(cppyy_scope_t handle, int datamember_index) {
+ Reflex::Scope s = scope_from_handle(handle);
+ Reflex::Member m = s.DataMemberAt(datamember_index);
+ if (m.IsArtificial() && m.TypeOf().IsEnum())
+ return (size_t)&m.InterpreterOffset();
+ return m.Offset();
+}
+
+int cppyy_datamember_index(cppyy_scope_t handle, const char* name) {
+ Reflex::Scope s = scope_from_handle(handle);
+ // the following appears dumb, but the internal storage for Reflex is an
+ // unsorted std::vector anyway, so there's no gain to be had in using the
+ // Scope::DataMemberByName() function (which returns Member, not an index)
+ int num_dm = cppyy_num_datamembers(handle);
+ for (int idm = 0; idm < num_dm; ++idm) {
+ Reflex::Member m = s.DataMemberAt(idm);
+ if (m.Name() == name || m.Name(Reflex::FINAL) == name) {
+ if (m.IsPublic())
+ return idm;
+ return -1;
+ }
+ }
+ return -1;
+}
+
+
+/* data member properties ------------------------------------------------ */
+int cppyy_is_publicdata(cppyy_scope_t handle, int datamember_index) {
+ Reflex::Scope s = scope_from_handle(handle);
+ Reflex::Member m = s.DataMemberAt(datamember_index);
+ return m.IsPublic();
+}
+
+int cppyy_is_staticdata(cppyy_scope_t handle, int datamember_index) {
+ Reflex::Scope s = scope_from_handle(handle);
+ Reflex::Member m = s.DataMemberAt(datamember_index);
+ return m.IsStatic();
+}
+
+
+/* misc helpers ----------------------------------------------------------- */
+long long cppyy_strtoll(const char* str) {
+ return strtoll(str, NULL, 0);
+}
+
+extern "C" unsigned long long cppyy_strtoull(const char* str) {
+ return strtoull(str, NULL, 0);
+}
+
+void cppyy_free(void* ptr) {
+ free(ptr);
+}
+
+cppyy_object_t cppyy_charp2stdstring(const char* str) {
+ return (cppyy_object_t)new std::string(str);
+}
+
+cppyy_object_t cppyy_stdstring2stdstring(cppyy_object_t ptr) {
+ return (cppyy_object_t)new std::string(*(std::string*)ptr);
+}
+
+void cppyy_assign2stdstring(cppyy_object_t ptr, const char* str) {
+ *((std::string*)ptr) = str;
+}
+
+void cppyy_free_stdstring(cppyy_object_t ptr) {
+ delete (std::string*)ptr;
+}
diff --git a/pypy/module/cppyy/test/Makefile b/pypy/module/cppyy/test/Makefile
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/Makefile
@@ -0,0 +1,62 @@
+dicts = example01Dict.so datatypesDict.so advancedcppDict.so advancedcpp2Dict.so \
+overloadsDict.so stltypesDict.so operatorsDict.so fragileDict.so crossingDict.so \
+std_streamsDict.so
+all : $(dicts)
+
+ROOTSYS := ${ROOTSYS}
+
+ifeq ($(ROOTSYS),)
+ genreflex=genreflex
+ cppflags=
+else
+ genreflex=$(ROOTSYS)/bin/genreflex
+ ifeq ($(wildcard $(ROOTSYS)/include),) # standard locations used?
+ cppflags=-I$(shell root-config --incdir) -L$(shell root-config --libdir)
+ else
+ cppflags=-I$(ROOTSYS)/include -L$(ROOTSYS)/lib64 -L$(ROOTSYS)/lib
+ endif
+endif
+
+PLATFORM := $(shell uname -s)
+ifeq ($(PLATFORM),Darwin)
+ cppflags+=-dynamiclib -single_module -arch x86_64
+endif
+
+ifeq ($(CINT),)
+ ifeq ($(shell $(genreflex) --help | grep -- --with-methptrgetter),)
+ genreflexflags=
+ cppflags2=-O3 -fPIC
+ else
+ genreflexflags=--with-methptrgetter
+ cppflags2=-Wno-pmf-conversions -O3 -fPIC
+ endif
+else
+ cppflags2=-O3 -fPIC -rdynamic
+endif
+
+ifeq ($(CINT),)
+%Dict.so: %_rflx.cpp %.cxx
+ echo $(cppflags)
+ g++ -o $@ $^ -shared -lReflex $(cppflags) $(cppflags2)
+
+%_rflx.cpp: %.h %.xml
+ $(genreflex) $< $(genreflexflags) --selection=$*.xml --rootmap=$*Dict.rootmap --rootmap-lib=$*Dict.so
+else
+%Dict.so: %_cint.cxx %.cxx
+ g++ -o $@ $^ -shared $(cppflags) $(cppflags2)
+ rlibmap -f -o $*Dict.rootmap -l $@ -c $*_LinkDef.h
+
+%_cint.cxx: %.h %_LinkDef.h
+ rootcint -f $@ -c $*.h $*_LinkDef.h
+endif
+
+ifeq ($(CINT),)
+# TODO: methptrgetter causes these tests to crash, so don't use it for now
+std_streamsDict.so: std_streams.cxx std_streams.h std_streams.xml
+ $(genreflex) std_streams.h --selection=std_streams.xml
+ g++ -o $@ std_streams_rflx.cpp std_streams.cxx -shared -lReflex $(cppflags) $(cppflags2)
+endif
+
+.PHONY: clean
+clean:
+ -rm -f $(dicts) $(subst .so,.rootmap,$(dicts)) $(wildcard *_cint.h)
diff --git a/pypy/module/cppyy/test/__init__.py b/pypy/module/cppyy/test/__init__.py
new file mode 100644
diff --git a/pypy/module/cppyy/test/advancedcpp.cxx b/pypy/module/cppyy/test/advancedcpp.cxx
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/advancedcpp.cxx
@@ -0,0 +1,76 @@
+#include "advancedcpp.h"
+
+
+// for testing of default arguments
+defaulter::defaulter(int a, int b, int c ) {
+ m_a = a;
+ m_b = b;
+ m_c = c;
+}
+
+
+// for esoteric inheritance testing
+a_class* create_c1() { return new c_class_1; }
+a_class* create_c2() { return new c_class_2; }
+
+int get_a( a_class& a ) { return a.m_a; }
+int get_b( b_class& b ) { return b.m_b; }
+int get_c( c_class& c ) { return c.m_c; }
+int get_d( d_class& d ) { return d.m_d; }
+
+
+// for namespace testing
+int a_ns::g_a = 11;
+int a_ns::b_class::s_b = 22;
+int a_ns::b_class::c_class::s_c = 33;
+int a_ns::d_ns::g_d = 44;
+int a_ns::d_ns::e_class::s_e = 55;
+int a_ns::d_ns::e_class::f_class::s_f = 66;
+
+int a_ns::get_g_a() { return g_a; }
+int a_ns::d_ns::get_g_d() { return g_d; }
+
+
+// for template testing
+template class T1<int>;
+template class T2<T1<int> >;
+template class T3<int, double>;
+template class T3<T1<int>, T2<T1<int> > >;
+template class a_ns::T4<int>;
+template class a_ns::T4<a_ns::T4<T3<int, double> > >;
+
+
+// helpers for checking pass-by-ref
+void set_int_through_ref(int& i, int val) { i = val; }
+int pass_int_through_const_ref(const int& i) { return i; }
+void set_long_through_ref(long& l, long val) { l = val; }
+long pass_long_through_const_ref(const long& l) { return l; }
+void set_double_through_ref(double& d, double val) { d = val; }
+double pass_double_through_const_ref(const double& d) { return d; }
+
+
+// for math conversions testing
+bool operator==(const some_comparable& c1, const some_comparable& c2 )
+{
+ return &c1 != &c2; // the opposite of a pointer comparison
+}
+
+bool operator!=( const some_comparable& c1, const some_comparable& c2 )
+{
+ return &c1 == &c2; // the opposite of a pointer comparison
+}
+
+
+// a couple of globals for access testing
+double my_global_double = 12.;
+double my_global_array[500];
+
+
+// for life-line and identity testing
+int some_class_with_data::some_data::s_num_data = 0;
+
+
+// for testing multiple inheritance
+multi1::~multi1() {}
+multi2::~multi2() {}
+multi::~multi() {}
diff --git a/pypy/module/cppyy/test/advancedcpp.h b/pypy/module/cppyy/test/advancedcpp.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/advancedcpp.h
@@ -0,0 +1,339 @@
+#include <vector>
+
+
+//===========================================================================
+class defaulter { // for testing of default arguments
+public:
+ defaulter(int a = 11, int b = 22, int c = 33 );
+
+public:
+ int m_a, m_b, m_c;
+};
+
+
+//===========================================================================
+class base_class { // for simple inheritance testing
+public:
+ base_class() { m_b = 1; m_db = 1.1; }
+ virtual ~base_class() {}
+ virtual int get_value() { return m_b; }
+ 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;
+ double m_db;
+};
+
+class derived_class : public base_class {
+public:
+ 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;
+ double m_dd;
+};
+
+
+//===========================================================================
+class a_class { // for esoteric inheritance testing
+public:
+ a_class() { m_a = 1; m_da = 1.1; }
+ ~a_class() {}
+ virtual int get_value() = 0;
+
+public:
+ int m_a;
+ double m_da;
+};
+
+class b_class : public virtual a_class {
+public:
+ b_class() { m_b = 2; m_db = 2.2;}
+ virtual int get_value() { return m_b; }
+
+public:
+ int m_b;
+ double m_db;
+};
+
+class c_class_1 : public virtual a_class, public virtual b_class {
+public:
+ c_class_1() { m_c = 3; }
+ virtual int get_value() { return m_c; }
+
+public:
+ int m_c;
+};
+
+class c_class_2 : public virtual b_class, public virtual a_class {
+public:
+ c_class_2() { m_c = 3; }
+ virtual int get_value() { return m_c; }
+
+public:
+ int m_c;
+};
+
+typedef c_class_2 c_class;
+
+class d_class : public virtual c_class, public virtual a_class {
+public:
+ d_class() { m_d = 4; }
+ virtual int get_value() { return m_d; }
+
+public:
+ int m_d;
+};
+
+a_class* create_c1();
+a_class* create_c2();
+
+int get_a(a_class& a);
+int get_b(b_class& b);
+int get_c(c_class& c);
+int get_d(d_class& d);
+
+
+//===========================================================================
+namespace a_ns { // for namespace testing
+ extern int g_a;
+ int get_g_a();
+
+ struct b_class {
+ b_class() { m_b = -2; }
+ int m_b;
+ static int s_b;
+
+ struct c_class {
+ c_class() { m_c = -3; }
+ int m_c;
+ static int s_c;
+ };
+ };
+
+ namespace d_ns {
+ extern int g_d;
+ int get_g_d();
+
+ struct e_class {
+ e_class() { m_e = -5; }
+ int m_e;
+ static int s_e;
+
+ struct f_class {
+ f_class() { m_f = -6; }
+ int m_f;
+ static int s_f;
+ };
+ };
+
+ } // namespace d_ns
+
+} // namespace a_ns
+
+
+//===========================================================================
+template<typename T> // for template testing
+class T1 {
+public:
+ T1(T t = T(1)) : m_t1(t) {}
+ T value() { return m_t1; }
+
+public:
+ T m_t1;
+};
+
+template<typename T>
+class T2 {
+public:
+ T2(T t = T(2)) : m_t2(t) {}
+ T value() { return m_t2; }
+
+public:
+ T m_t2;
+};
+
+template<typename T, typename U>
+class T3 {
+public:
+ T3(T t = T(3), U u = U(33)) : m_t3(t), m_u3(u) {}
+ T value_t() { return m_t3; }
+ U value_u() { return m_u3; }
+
+public:
+ T m_t3;
+ U m_u3;
+};
+
+namespace a_ns {
+
+ template<typename T>
+ class T4 {
+ public:
+ T4(T t = T(4)) : m_t4(t) {}
+ T value() { return m_t4; }
+
+ public:
+ T m_t4;
+ };
+
+} // namespace a_ns
+
+extern template class T1<int>;
+extern template class T2<T1<int> >;
+extern template class T3<int, double>;
+extern template class T3<T1<int>, T2<T1<int> > >;
+extern template class a_ns::T4<int>;
+extern template class a_ns::T4<a_ns::T4<T3<int, double> > >;
+
+
+//===========================================================================
+// for checking pass-by-reference of builtin types
+void set_int_through_ref(int& i, int val);
+int pass_int_through_const_ref(const int& i);
+void set_long_through_ref(long& l, long val);
+long pass_long_through_const_ref(const long& l);
+void set_double_through_ref(double& d, double val);
+double pass_double_through_const_ref(const double& d);
+
+
+//===========================================================================
+class some_abstract_class { // to test abstract class handling
+public:
+ virtual void a_virtual_method() = 0;
+};
+
+class some_concrete_class : public some_abstract_class {
+public:
+ virtual void a_virtual_method() {}
+};
+
+
+//===========================================================================
+/*
+TODO: methptrgetter support for std::vector<>
+class ref_tester { // for assignment by-ref testing
+public:
+ ref_tester() : m_i(-99) {}
+ ref_tester(int i) : m_i(i) {}
+ ref_tester(const ref_tester& s) : m_i(s.m_i) {}
+ ref_tester& operator=(const ref_tester& s) {
+ if (&s != this) m_i = s.m_i;
+ return *this;
+ }
+ ~ref_tester() {}
+
+public:
+ int m_i;
+};
+
+template class std::vector< ref_tester >;
+*/
+
+
+//===========================================================================
+class some_convertible { // for math conversions testing
+public:
+ some_convertible() : m_i(-99), m_d(-99.) {}
+
+ operator int() { return m_i; }
+ operator long() { return m_i; }
+ operator double() { return m_d; }
+
+public:
+ int m_i;
+ double m_d;
+};
+
+
+class some_comparable {
+};
+
+bool operator==(const some_comparable& c1, const some_comparable& c2 );
+bool operator!=( const some_comparable& c1, const some_comparable& c2 );
+
+
+//===========================================================================
+extern double my_global_double; // a couple of globals for access testing
+extern double my_global_array[500];
+
+
+//===========================================================================
+class some_class_with_data { // for life-line and identity testing
+public:
+ class some_data {
+ public:
+ some_data() { ++s_num_data; }
+ some_data(const some_data&) { ++s_num_data; }
+ ~some_data() { --s_num_data; }
+
+ static int s_num_data;
+ };
+
+ some_class_with_data gime_copy() {
+ return *this;
+ }
+
+ const some_data& gime_data() { /* TODO: methptrgetter const support */
+ return m_data;
+ }
+
+ int m_padding;
+ some_data m_data;
+};
+
+
+//===========================================================================
+class pointer_pass { // for testing passing of void*'s
+public:
+ long gime_address_ptr(void* obj) {
+ return (long)obj;
+ }
+
+ long gime_address_ptr_ptr(void** obj) {
+ return (long)*((long**)obj);
+ }
+
+ long gime_address_ptr_ref(void*& obj) {
+ return (long)obj;
+ }
+};
+
+
+//===========================================================================
+class multi1 { // for testing multiple inheritance
+public:
+ multi1(int val) : m_int(val) {}
+ virtual ~multi1();
+ int get_multi1_int() { return m_int; }
+
+private:
+ int m_int;
+};
+
+class multi2 {
+public:
+ multi2(int val) : m_int(val) {}
+ virtual ~multi2();
+ int get_multi2_int() { return m_int; }
+
+private:
+ int m_int;
+};
+
+class multi : public multi1, public multi2 {
+public:
+ multi(int val1, int val2, int val3) :
+ multi1(val1), multi2(val2), m_int(val3) {}
+ virtual ~multi();
+ int get_my_own_int() { return m_int; }
+
+private:
+ int m_int;
+};
diff --git a/pypy/module/cppyy/test/advancedcpp.xml b/pypy/module/cppyy/test/advancedcpp.xml
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/advancedcpp.xml
@@ -0,0 +1,40 @@
+<lcgdict>
+
+ <class name="defaulter" />
+
+ <class name="base_class" />
+ <class name="derived_class" />
+
+ <class name="a_class" />
+ <class name="b_class" />
+ <class name="c_class" />
+ <class name="c_class_1" />
+ <class name="c_class_2" />
+ <class name="d_class" />
+
+ <function pattern="create_*" />
+ <function pattern="get_*" />
+
+ <class pattern="T1<*>" />
+ <class pattern="T2<*>" />
+ <class pattern="T3<*>" />
+
+ <namespace name="a_ns" />
+ <namespace pattern="a_ns::*" />
+ <class pattern="a_ns::*" />
+ <variable name="a_ns::g_a" />
+ <function name="a_ns::get_g_a" />
+ <variable name="a_ns::d_ns::g_d" />
+ <function name="a_ns::d_ns::get_g_d" />
+
+ <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" />
+
+ <class pattern="multi*" />
+
+</lcgdict>
diff --git a/pypy/module/cppyy/test/advancedcpp2.cxx b/pypy/module/cppyy/test/advancedcpp2.cxx
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/advancedcpp2.cxx
@@ -0,0 +1,13 @@
+#include "advancedcpp2.h"
+
+
+// for namespace testing
+int a_ns::g_g = 77;
+int a_ns::g_class::s_g = 88;
+int a_ns::g_class::h_class::s_h = 99;
+int a_ns::d_ns::g_i = 111;
+int a_ns::d_ns::i_class::s_i = 222;
+int a_ns::d_ns::i_class::j_class::s_j = 333;
+
+int a_ns::get_g_g() { return g_g; }
+int a_ns::d_ns::get_g_i() { return g_i; }
diff --git a/pypy/module/cppyy/test/advancedcpp2.h b/pypy/module/cppyy/test/advancedcpp2.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/advancedcpp2.h
@@ -0,0 +1,36 @@
+//===========================================================================
+namespace a_ns { // for namespace testing
+ extern int g_g;
+ int get_g_g();
+
+ struct g_class {
+ g_class() { m_g = -7; }
+ int m_g;
+ static int s_g;
+
+ struct h_class {
+ h_class() { m_h = -8; }
+ int m_h;
+ static int s_h;
+ };
+ };
+
+ namespace d_ns {
+ extern int g_i;
+ int get_g_i();
+
+ struct i_class {
+ i_class() { m_i = -9; }
+ int m_i;
+ static int s_i;
+
+ struct j_class {
+ j_class() { m_j = -10; }
+ int m_j;
+ static int s_j;
+ };
+ };
+
+ } // namespace d_ns
+
+} // namespace a_ns
diff --git a/pypy/module/cppyy/test/advancedcpp2.xml b/pypy/module/cppyy/test/advancedcpp2.xml
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/advancedcpp2.xml
@@ -0,0 +1,11 @@
+<lcgdict>
+
+ <namespace name="a_ns" />
+ <namespace pattern="a_ns::*" />
+ <class pattern="a_ns::*" />
+ <variable name="a_ns::g_g" />
+ <function name="a_ns::get_g_g" />
+ <variable name="a_ns::d_ns::g_i" />
+ <function name="a_ns::d_ns::get_g_i" />
+
+</lcgdict>
diff --git a/pypy/module/cppyy/test/advancedcpp2_LinkDef.h b/pypy/module/cppyy/test/advancedcpp2_LinkDef.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/advancedcpp2_LinkDef.h
@@ -0,0 +1,18 @@
+#ifdef __CINT__
+
+#pragma link off all globals;
+#pragma link off all classes;
+#pragma link off all functions;
+
+#pragma link C++ namespace a_ns;
+#pragma link C++ namespace a_ns::d_ns;
+#pragma link C++ struct a_ns::g_class;
+#pragma link C++ struct a_ns::g_class::h_class;
+#pragma link C++ struct a_ns::d_ns::i_class;
+#pragma link C++ struct a_ns::d_ns::i_class::j_class;
+#pragma link C++ variable a_ns::g_g;
+#pragma link C++ function a_ns::get_g_g;
+#pragma link C++ variable a_ns::d_ns::g_i;
+#pragma link C++ function a_ns::d_ns::get_g_i;
+
+#endif
diff --git a/pypy/module/cppyy/test/advancedcpp_LinkDef.h b/pypy/module/cppyy/test/advancedcpp_LinkDef.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/advancedcpp_LinkDef.h
@@ -0,0 +1,58 @@
+#ifdef __CINT__
+
+#pragma link off all globals;
+#pragma link off all classes;
+#pragma link off all functions;
+
+#pragma link C++ class defaulter;
+
+#pragma link C++ class base_class;
+#pragma link C++ class derived_class;
+
+#pragma link C++ class a_class;
+#pragma link C++ class b_class;
+#pragma link C++ class c_class;
+#pragma link C++ class c_class_1;
+#pragma link C++ class c_class_2;
+#pragma link C++ class d_class;
+
+#pragma link C++ function create_c1();
+#pragma link C++ function create_c2();
+
+#pragma link C++ function get_a(a_class&);
+#pragma link C++ function get_b(b_class&);
+#pragma link C++ function get_c(c_class&);
+#pragma link C++ function get_d(d_class&);
+
+#pragma link C++ class T1<int>;
+#pragma link C++ class T2<T1<int> >;
+#pragma link C++ class T3<int, double>;
+#pragma link C++ class T3<T1<int>, T2<T1<int> > >;
+#pragma link C++ class a_ns::T4<int>;
+#pragma link C++ class a_ns::T4<T3<int,double> >;
+#pragma link C++ class a_ns::T4<a_ns::T4<T3<int, double> > >;
+
+#pragma link C++ namespace a_ns;
+#pragma link C++ namespace a_ns::d_ns;
+#pragma link C++ struct a_ns::b_class;
+#pragma link C++ struct a_ns::b_class::c_class;
+#pragma link C++ struct a_ns::d_ns::e_class;
+#pragma link C++ struct a_ns::d_ns::e_class::f_class;
+#pragma link C++ variable a_ns::g_a;
+#pragma link C++ function a_ns::get_g_a;
+#pragma link C++ variable a_ns::d_ns::g_d;
+#pragma link C++ function a_ns::d_ns::get_g_d;
+
+#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;
+
+#pragma link C++ class multi1;
+#pragma link C++ class multi2;
+#pragma link C++ class multi;
+
+#endif
diff --git a/pypy/module/cppyy/test/bench1.cxx b/pypy/module/cppyy/test/bench1.cxx
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/bench1.cxx
@@ -0,0 +1,39 @@
+#include <iostream>
+#include <iomanip>
+#include <time.h>
+#include <unistd.h>
+
+#include "example01.h"
+
+static const int NNN = 10000000;
+
+
+int cpp_loop_offset() {
+ int i = 0;
+ for ( ; i < NNN*10; ++i)
+ ;
+ return i;
+}
+
+int cpp_bench1() {
+ int i = 0;
+ example01 e;
+ for ( ; i < NNN*10; ++i)
+ e.addDataToInt(i);
+ return i;
+}
+
+
+int main() {
+
+ clock_t t1 = clock();
+ cpp_loop_offset();
+ clock_t t2 = clock();
+ cpp_bench1();
+ clock_t t3 = clock();
+
+ std::cout << std::setprecision(8)
+ << ((t3-t2) - (t2-t1))/((double)CLOCKS_PER_SEC*10.) << std::endl;
+
+ return 0;
+}
diff --git a/pypy/module/cppyy/test/bench1.py b/pypy/module/cppyy/test/bench1.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/bench1.py
@@ -0,0 +1,147 @@
+import commands, os, sys, time
+
+NNN = 10000000
+
+
+def run_bench(bench):
+ global t_loop_offset
+
+ t1 = time.time()
+ bench()
+ t2 = time.time()
+
+ t_bench = (t2-t1)-t_loop_offset
+ return bench.scale*t_bench
+
+def print_bench(name, t_bench):
+ global t_cppref
+ print ':::: %s cost: %#6.3fs (%#4.1fx)' % (name, t_bench, float(t_bench)/t_cppref)
+
+def python_loop_offset():
+ for i in range(NNN):
+ i
+ return i
+
+class PyCintexBench1(object):
+ scale = 10
+ def __init__(self):
+ import PyCintex
+ self.lib = PyCintex.gbl.gSystem.Load("./example01Dict.so")
+
+ self.cls = PyCintex.gbl.example01
+ self.inst = self.cls(0)
+
+ def __call__(self):
+ # note that PyCintex calls don't actually scale linearly, but worse
+ # than linear (leak or wrong filling of a cache??)
+ instance = self.inst
+ niter = NNN/self.scale
+ for i in range(niter):
+ instance.addDataToInt(i)
+ return i
+
+class PyROOTBench1(PyCintexBench1):
+ def __init__(self):
+ import ROOT
+ self.lib = ROOT.gSystem.Load("./example01Dict_cint.so")
+
+ self.cls = ROOT.example01
+ self.inst = self.cls(0)
+
+class CppyyInterpBench1(object):
+ scale = 1
+ def __init__(self):
+ import cppyy
+ self.lib = cppyy.load_reflection_info("./example01Dict.so")
+
+ self.cls = cppyy._scope_byname("example01")
+ self.inst = self.cls.get_overload(self.cls.type_name).call(None, 0)
+
+ def __call__(self):
+ addDataToInt = self.cls.get_overload("addDataToInt")
+ instance = self.inst
+ for i in range(NNN):
+ addDataToInt.call(instance, i)
+ return i
+
+class CppyyInterpBench2(CppyyInterpBench1):
+ def __call__(self):
+ addDataToInt = self.cls.get_overload("overloadedAddDataToInt")
+ instance = self.inst
+ for i in range(NNN):
+ addDataToInt.call(instance, i)
+ return i
+
+class CppyyInterpBench3(CppyyInterpBench1):
+ def __call__(self):
+ addDataToInt = self.cls.get_overload("addDataToIntConstRef")
+ instance = self.inst
+ for i in range(NNN):
+ addDataToInt.call(instance, i)
+ return i
+
+class CppyyPythonBench1(object):
+ scale = 1
+ def __init__(self):
+ import cppyy
+ self.lib = cppyy.load_reflection_info("./example01Dict.so")
+
+ self.cls = cppyy.gbl.example01
+ self.inst = self.cls(0)
+
+ def __call__(self):
+ instance = self.inst
+ for i in range(NNN):
+ instance.addDataToInt(i)
+ return i
+
+
+if __name__ == '__main__':
+ python_loop_offset();
+
+ # time python loop offset
+ t1 = time.time()
+ python_loop_offset()
+ t2 = time.time()
+ t_loop_offset = t2-t1
+
+ # special case for PyCintex (run under python, not pypy-c)
+ if '--pycintex' in sys.argv:
+ cintex_bench1 = PyCintexBench1()
+ print run_bench(cintex_bench1)
+ sys.exit(0)
+
+ # special case for PyCintex (run under python, not pypy-c)
+ if '--pyroot' in sys.argv:
+ pyroot_bench1 = PyROOTBench1()
+ print run_bench(pyroot_bench1)
+ sys.exit(0)
+
+ # get C++ reference point
+ if not os.path.exists("bench1.exe") or\
+ os.stat("bench1.exe").st_mtime < os.stat("bench1.cxx").st_mtime:
+ print "rebuilding bench1.exe ... "
+ os.system( "g++ -O2 bench1.cxx example01.cxx -o bench1.exe" )
+ stat, cppref = commands.getstatusoutput("./bench1.exe")
+ t_cppref = float(cppref)
+
+ # warm-up
+ print "warming up ... "
+ interp_bench1 = CppyyInterpBench1()
+ interp_bench2 = CppyyInterpBench2()
+ interp_bench3 = CppyyInterpBench3()
+ python_bench1 = CppyyPythonBench1()
+ interp_bench1(); interp_bench2(); python_bench1()
+
+ # to allow some consistency checking
+ print "C++ reference uses %.3fs" % t_cppref
+
+ # test runs ...
+ print_bench("cppyy interp", run_bench(interp_bench1))
+ print_bench("... overload", run_bench(interp_bench2))
+ print_bench("... constref", run_bench(interp_bench3))
+ print_bench("cppyy python", run_bench(python_bench1))
+ stat, t_cintex = commands.getstatusoutput("python bench1.py --pycintex")
+ print_bench("pycintex ", float(t_cintex))
+ #stat, t_pyroot = commands.getstatusoutput("python bench1.py --pyroot")
+ #print_bench("pyroot ", float(t_pyroot))
diff --git a/pypy/module/cppyy/test/conftest.py b/pypy/module/cppyy/test/conftest.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/conftest.py
@@ -0,0 +1,5 @@
+import py
+
+def pytest_runtest_setup(item):
+ if py.path.local.sysfind('genreflex') is None:
+ py.test.skip("genreflex is not installed")
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/crossing_LinkDef.h b/pypy/module/cppyy/test/crossing_LinkDef.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/crossing_LinkDef.h
@@ -0,0 +1,11 @@
+#ifdef __CINT__
+
+#pragma link off all globals;
+#pragma link off all classes;
+#pragma link off all functions;
+
+#pragma link C++ namespace crossing;
+
+#pragma link C++ class crossing::A;
+
+#endif
diff --git a/pypy/module/cppyy/test/datatypes.cxx b/pypy/module/cppyy/test/datatypes.cxx
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/datatypes.cxx
@@ -0,0 +1,211 @@
+#include "datatypes.h"
+
+#include <iostream>
+
+
+//===========================================================================
+cppyy_test_data::cppyy_test_data() : m_owns_arrays(false)
+{
+ m_bool = false;
+ m_char = 'a';
+ m_uchar = 'c';
+ m_short = -11;
+ m_ushort = 11u;
+ m_int = -22;
+ m_uint = 22u;
+ m_long = -33l;
+ m_ulong = 33ul;
+ m_llong = -44ll;
+ m_ullong = 55ull;
+ m_float = -66.f;
+ m_double = -77.;
+ m_enum = kNothing;
+
+ m_short_array2 = new short[N];
+ m_ushort_array2 = new unsigned short[N];
+ m_int_array2 = new int[N];
+ m_uint_array2 = new unsigned int[N];
+ m_long_array2 = new long[N];
+ m_ulong_array2 = new unsigned long[N];
+
+ m_float_array2 = new float[N];
+ m_double_array2 = new double[N];
+
+ for (int i = 0; i < N; ++i) {
+ m_short_array[i] = -1*i;
+ m_short_array2[i] = -2*i;
+ m_ushort_array[i] = 3u*i;
+ m_ushort_array2[i] = 4u*i;
+ m_int_array[i] = -5*i;
+ m_int_array2[i] = -6*i;
+ m_uint_array[i] = 7u*i;
+ m_uint_array2[i] = 8u*i;
+ m_long_array[i] = -9l*i;
+ m_long_array2[i] = -10l*i;
+ m_ulong_array[i] = 11ul*i;
+ m_ulong_array2[i] = 12ul*i;
+
+ m_float_array[i] = -13.f*i;
+ m_float_array2[i] = -14.f*i;
+ m_double_array[i] = -15.*i;
+ m_double_array2[i] = -16.*i;
+ }
+
+ m_owns_arrays = true;
+
+ m_pod.m_int = 888;
+ m_pod.m_double = 3.14;
+
+ m_ppod = &m_pod;
+};
+
+cppyy_test_data::~cppyy_test_data()
+{
+ destroy_arrays();
+}
+
+void cppyy_test_data::destroy_arrays() {
+ if (m_owns_arrays == true) {
+ delete[] m_short_array2;
+ delete[] m_ushort_array2;
+ delete[] m_int_array2;
+ delete[] m_uint_array2;
+ delete[] m_long_array2;
+ delete[] m_ulong_array2;
+
+ delete[] m_float_array2;
+ delete[] m_double_array2;
+
+ m_owns_arrays = false;
+ }
+}
+
+//- getters -----------------------------------------------------------------
+bool cppyy_test_data::get_bool() { return m_bool; }
+char cppyy_test_data::get_char() { return m_char; }
+unsigned char cppyy_test_data::get_uchar() { return m_uchar; }
+short cppyy_test_data::get_short() { return m_short; }
+unsigned short cppyy_test_data::get_ushort() { return m_ushort; }
+int cppyy_test_data::get_int() { return m_int; }
+unsigned int cppyy_test_data::get_uint() { return m_uint; }
+long cppyy_test_data::get_long() { return m_long; }
+unsigned long cppyy_test_data::get_ulong() { return m_ulong; }
+long long cppyy_test_data::get_llong() { return m_llong; }
+unsigned long long cppyy_test_data::get_ullong() { return m_ullong; }
+float cppyy_test_data::get_float() { return m_float; }
+double cppyy_test_data::get_double() { return m_double; }
+cppyy_test_data::what cppyy_test_data::get_enum() { return m_enum; }
+
+short* cppyy_test_data::get_short_array() { return m_short_array; }
+short* cppyy_test_data::get_short_array2() { return m_short_array2; }
+unsigned short* cppyy_test_data::get_ushort_array() { return m_ushort_array; }
+unsigned short* cppyy_test_data::get_ushort_array2() { return m_ushort_array2; }
+int* cppyy_test_data::get_int_array() { return m_int_array; }
+int* cppyy_test_data::get_int_array2() { return m_int_array2; }
+unsigned int* cppyy_test_data::get_uint_array() { return m_uint_array; }
+unsigned int* cppyy_test_data::get_uint_array2() { return m_uint_array2; }
+long* cppyy_test_data::get_long_array() { return m_long_array; }
+long* cppyy_test_data::get_long_array2() { return m_long_array2; }
+unsigned long* cppyy_test_data::get_ulong_array() { return m_ulong_array; }
+unsigned long* cppyy_test_data::get_ulong_array2() { return m_ulong_array2; }
+
+float* cppyy_test_data::get_float_array() { return m_float_array; }
+float* cppyy_test_data::get_float_array2() { return m_float_array2; }
+double* cppyy_test_data::get_double_array() { return m_double_array; }
+double* cppyy_test_data::get_double_array2() { return m_double_array2; }
+
+cppyy_test_pod cppyy_test_data::get_pod_val() { return m_pod; }
+cppyy_test_pod* cppyy_test_data::get_pod_ptr() { return &m_pod; }
+cppyy_test_pod& cppyy_test_data::get_pod_ref() { return m_pod; }
+cppyy_test_pod*& cppyy_test_data::get_pod_ptrref() { return m_ppod; }
+
+//- setters -----------------------------------------------------------------
+void cppyy_test_data::set_bool(bool b) { m_bool = b; }
+void cppyy_test_data::set_char(char c) { m_char = c; }
+void cppyy_test_data::set_uchar(unsigned char uc) { m_uchar = uc; }
+void cppyy_test_data::set_short(short s) { m_short = s; }
+void cppyy_test_data::set_short_c(const short& s) { m_short = s; }
+void cppyy_test_data::set_ushort(unsigned short us) { m_ushort = us; }
+void cppyy_test_data::set_ushort_c(const unsigned short& us) { m_ushort = us; }
+void cppyy_test_data::set_int(int i) { m_int = i; }
+void cppyy_test_data::set_int_c(const int& i) { m_int = i; }
+void cppyy_test_data::set_uint(unsigned int ui) { m_uint = ui; }
+void cppyy_test_data::set_uint_c(const unsigned int& ui) { m_uint = ui; }
+void cppyy_test_data::set_long(long l) { m_long = l; }
+void cppyy_test_data::set_long_c(const long& l) { m_long = l; }
+void cppyy_test_data::set_ulong(unsigned long ul) { m_ulong = ul; }
+void cppyy_test_data::set_ulong_c(const unsigned long& ul) { m_ulong = ul; }
+void cppyy_test_data::set_llong(long long ll) { m_llong = ll; }
+void cppyy_test_data::set_llong_c(const long long& ll) { m_llong = ll; }
+void cppyy_test_data::set_ullong(unsigned long long ull) { m_ullong = ull; }
+void cppyy_test_data::set_ullong_c(const unsigned long long& ull) { m_ullong = ull; }
+void cppyy_test_data::set_float(float f) { m_float = f; }
+void cppyy_test_data::set_float_c(const float& f) { m_float = f; }
+void cppyy_test_data::set_double(double d) { m_double = d; }
+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;
+unsigned short cppyy_test_data::s_ushort = 255u;
+int cppyy_test_data::s_int = -202;
+unsigned int cppyy_test_data::s_uint = 202u;
+long cppyy_test_data::s_long = -303l;
+unsigned long cppyy_test_data::s_ulong = 303ul;
+long long cppyy_test_data::s_llong = -404ll;
+unsigned long long cppyy_test_data::s_ullong = 505ull;
+float cppyy_test_data::s_float = -606.f;
+double cppyy_test_data::s_double = -707.;
+cppyy_test_data::what cppyy_test_data::s_enum = cppyy_test_data::kNothing;
+
+
+//= global functions ========================================================
+long get_pod_address(cppyy_test_data& c)
+{
+ return (long)&c.m_pod;
+}
+
+long get_int_address(cppyy_test_data& c)
+{
+ return (long)&c.m_pod.m_int;
+}
+
+long get_double_address(cppyy_test_data& c)
+{
+ return (long)&c.m_pod.m_double;
+}
+
+//= global variables/pointers ===============================================
+int g_int = 42;
+
+void set_global_int(int i) {
+ g_int = i;
+}
+
+int get_global_int() {
+ return g_int;
+}
+
+cppyy_test_pod* g_pod = (cppyy_test_pod*)0;
+
+bool is_global_pod(cppyy_test_pod* t) {
+ return t == g_pod;
+}
+
+void set_global_pod(cppyy_test_pod* t) {
+ g_pod = t;
+}
+
+cppyy_test_pod* get_global_pod() {
+ return g_pod;
+}
diff --git a/pypy/module/cppyy/test/datatypes.h b/pypy/module/cppyy/test/datatypes.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/datatypes.h
@@ -0,0 +1,171 @@
+const int N = 5;
+
+
+//===========================================================================
+struct cppyy_test_pod {
+ int m_int;
+ double m_double;
+};
+
+
+//===========================================================================
+class cppyy_test_data {
+public:
+ cppyy_test_data();
+ ~cppyy_test_data();
+
+// special cases
+ enum what { kNothing=6, kSomething=111, kLots=42 };
+
+// helper
+ void destroy_arrays();
+
+// getters
+ bool get_bool();
+ char get_char();
+ unsigned char get_uchar();
+ short get_short();
+ unsigned short get_ushort();
+ int get_int();
+ unsigned int get_uint();
+ long get_long();
+ unsigned long get_ulong();
+ long long get_llong();
+ unsigned long long get_ullong();
+ float get_float();
+ double get_double();
+ what get_enum();
+
+ short* get_short_array();
+ short* get_short_array2();
+ unsigned short* get_ushort_array();
+ unsigned short* get_ushort_array2();
+ int* get_int_array();
+ int* get_int_array2();
+ unsigned int* get_uint_array();
+ unsigned int* get_uint_array2();
+ long* get_long_array();
+ long* get_long_array2();
+ unsigned long* get_ulong_array();
+ unsigned long* get_ulong_array2();
+
+ float* get_float_array();
+ float* get_float_array2();
+ double* get_double_array();
+ double* get_double_array2();
+
+ cppyy_test_pod get_pod_val();
+ cppyy_test_pod* get_pod_ptr();
+ cppyy_test_pod& get_pod_ref();
+ cppyy_test_pod*& get_pod_ptrref();
+
+// setters
+ void set_bool(bool b);
+ void set_char(char c);
+ void set_uchar(unsigned char uc);
+ void set_short(short s);
+ void set_short_c(const short& s);
+ void set_ushort(unsigned short us);
+ void set_ushort_c(const unsigned short& us);
+ void set_int(int i);
+ void set_int_c(const int& i);
+ void set_uint(unsigned int ui);
+ void set_uint_c(const unsigned int& ui);
+ void set_long(long l);
+ void set_long_c(const long& l);
+ void set_llong(long long ll);
+ void set_llong_c(const long long& ll);
+ void set_ulong(unsigned long ul);
+ void set_ulong_c(const unsigned long& ul);
+ void set_ullong(unsigned long long ll);
+ void set_ullong_c(const unsigned long long& ll);
+ void set_float(float f);
+ void set_float_c(const float& f);
+ void set_double(double d);
+ 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;
+ char m_char;
+ unsigned char m_uchar;
+ short m_short;
+ unsigned short m_ushort;
+ int m_int;
+ unsigned int m_uint;
+ long m_long;
+ unsigned long m_ulong;
+ long long m_llong;
+ unsigned long long m_ullong;
+ float m_float;
+ double m_double;
+ what m_enum;
+
+// array types
+ short m_short_array[N];
+ short* m_short_array2;
+ unsigned short m_ushort_array[N];
+ unsigned short* m_ushort_array2;
+ int m_int_array[N];
+ int* m_int_array2;
+ unsigned int m_uint_array[N];
+ unsigned int* m_uint_array2;
+ long m_long_array[N];
+ long* m_long_array2;
+ unsigned long m_ulong_array[N];
+ unsigned long* m_ulong_array2;
+
+ float m_float_array[N];
+ float* m_float_array2;
+ double m_double_array[N];
+ double* m_double_array2;
+
+// object types
+ cppyy_test_pod m_pod;
+ cppyy_test_pod* m_ppod;
+
+public:
+ static char s_char;
+ static unsigned char s_uchar;
+ static short s_short;
+ static unsigned short s_ushort;
+ static int s_int;
+ static unsigned int s_uint;
+ static long s_long;
+ static unsigned long s_ulong;
+ static long long s_llong;
+ static unsigned long long s_ullong;
+ static float s_float;
+ static double s_double;
+ static what s_enum;
+
+private:
+ bool m_owns_arrays;
+};
+
+
+//= global functions ========================================================
+long get_pod_address(cppyy_test_data& c);
+long get_int_address(cppyy_test_data& c);
+long get_double_address(cppyy_test_data& c);
+
+
+//= global variables/pointers ===============================================
+extern int g_int;
+void set_global_int(int i);
+int get_global_int();
+
+extern cppyy_test_pod* g_pod;
+bool is_global_pod(cppyy_test_pod* t);
+void set_global_pod(cppyy_test_pod* t);
+cppyy_test_pod* get_global_pod();
diff --git a/pypy/module/cppyy/test/datatypes.xml b/pypy/module/cppyy/test/datatypes.xml
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/datatypes.xml
@@ -0,0 +1,14 @@
+<lcgdict>
+
+ <class pattern="cppyy_test_*" />
+
+ <function pattern="get_*" />
+ <function pattern="set_*" />
+ <function pattern="is_*" />
+
+ <variable name="N" />
+
+ <variable name="g_int" />
+ <variable name="g_pod" />
+
+</lcgdict>
diff --git a/pypy/module/cppyy/test/datatypes_LinkDef.h b/pypy/module/cppyy/test/datatypes_LinkDef.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/datatypes_LinkDef.h
@@ -0,0 +1,24 @@
+#ifdef __CINT__
+
+#pragma link off all globals;
+#pragma link off all classes;
+#pragma link off all functions;
+
+#pragma link C++ struct cppyy_test_pod;
+#pragma link C++ class cppyy_test_data;
+
+#pragma link C++ function get_pod_address(cppyy_test_data&);
+#pragma link C++ function get_int_address(cppyy_test_data&);
+#pragma link C++ function get_double_address(cppyy_test_data&);
+#pragma link C++ function set_global_int(int);
+#pragma link C++ function get_global_int();
+
+#pragma link C++ function is_global_pod(cppyy_test_pod*);
+#pragma link C++ function set_global_pod(cppyy_test_pod*);
+#pragma link C++ function get_global_pod();
+
+#pragma link C++ global N;
+#pragma link C++ global g_int;
+#pragma link C++ global g_pod;
+
+#endif
diff --git a/pypy/module/cppyy/test/example01.cxx b/pypy/module/cppyy/test/example01.cxx
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/test/example01.cxx
@@ -0,0 +1,209 @@
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <stdlib.h>
+#include <string.h>
+
+#include "example01.h"
+
+//===========================================================================
+payload::payload(double d) : m_data(d) {
+ count++;
+}
+payload::payload(const payload& p) : m_data(p.m_data) {
+ count++;
+}
+payload& payload::operator=(const payload& p) {
+ if (this != &p) {
+ m_data = p.m_data;
+ }
+ return *this;
+}
+payload::~payload() {
+ count--;
+}
+
+double payload::getData() { return m_data; }
+void payload::setData(double d) { m_data = d; }
+
+// class-level data
+int payload::count = 0;
+
+
+//===========================================================================
+example01::example01() : m_somedata(-99) {
+ count++;
+}
+example01::example01(int a) : m_somedata(a) {
+ count++;
+}
+example01::example01(const example01& e) : m_somedata(e.m_somedata) {
+ count++;
+}
+example01& example01::operator=(const example01& e) {
+ if (this != &e) {
+ m_somedata = e.m_somedata;
+ }
+ return *this;
+}
+example01::~example01() {
+ count--;
+}
+
+// class-level methods
+int example01::staticAddOneToInt(int a) {
+ return a + 1;
+}
+int example01::staticAddOneToInt(int a, int b) {
+ return a + b + 1;
+}
+double example01::staticAddToDouble(double a) {
+ return a + 0.01;
+}
+int example01::staticAtoi(const char* str) {
+ return ::atoi(str);
+}
+char* example01::staticStrcpy(const char* strin) {
+ char* strout = (char*)malloc(::strlen(strin)+1);
+ ::strcpy(strout, strin);
+ return strout;
+}
+void example01::staticSetPayload(payload* p, double d) {
+ p->setData(d);
+}
+
+payload* example01::staticCyclePayload(payload* p, double d) {
+ staticSetPayload(p, d);
+ return p;
+}
+
+payload example01::staticCopyCyclePayload(payload* p, double d) {
+ staticSetPayload(p, d);
+ return *p;
+}
+
+int example01::getCount() {
+ return count;
+}
+
+void example01::setCount(int value) {
+ count = value;
+}
+
+// instance methods
+int example01::addDataToInt(int a) {
+ return m_somedata + a;
+}
+
+int example01::addDataToIntConstRef(const int& a) {
+ return m_somedata + a;
+}
+
+int example01::overloadedAddDataToInt(int a, int b) {
+ return m_somedata + a + b;
+}
+
+int example01::overloadedAddDataToInt(int a) {
+ return m_somedata + a;
+}
+
+int example01::overloadedAddDataToInt(int a, int b, int c) {
+ return m_somedata + a + b + c;
+}
+
+double example01::addDataToDouble(double a) {
+ return m_somedata + a;
+}
+
+int example01::addDataToAtoi(const char* str) {
+ return ::atoi(str) + m_somedata;
+}
+
+char* example01::addToStringValue(const char* str) {
+ int out = ::atoi(str) + m_somedata;
+ std::ostringstream ss;
+ ss << out << std::ends;
+ std::string result = ss.str();
+ char* cresult = (char*)malloc(result.size()+1);
+ ::strcpy(cresult, result.c_str());
+ return cresult;
+}
+
+void example01::setPayload(payload* p) {
+ p->setData(m_somedata);
+}
+
+payload* example01::cyclePayload(payload* p) {
+ setPayload(p);
+ return p;
+}
+
+payload example01::copyCyclePayload(payload* p) {
+ setPayload(p);
+ return *p;
+}
+
+// class-level data
+int example01::count = 0;
+
+
+// global
+int globalAddOneToInt(int a) {
+ return a + 1;
+}
+
+int ns_example01::globalAddOneToInt(int a) {
+ return ::globalAddOneToInt(a);
+}
+
+
+// argument passing
+#define typeValueImp(itype, tname) \
+itype ArgPasser::tname##Value(itype arg0, int argn, itype arg1, itype arg2) \
+{ \
+ switch (argn) { \
+ case 0: \
+ return arg0; \
+ case 1: \
+ return arg1; \
+ case 2: \
+ return arg2; \
+ default: \
+ break; \
+ } \
+ \
+ return (itype)-1; \
+}
+
+typeValueImp(short, short)
+typeValueImp(unsigned short, ushort)
+typeValueImp(int, int)
+typeValueImp(unsigned int, uint)
+typeValueImp(long, long)
+typeValueImp(unsigned long, ulong)
+
+typeValueImp(float, float)
+typeValueImp(double, double)
+
+std::string ArgPasser::stringValue(std::string arg0, int argn, std::string arg1)
+{
+ switch (argn) {
More information about the pypy-commit
mailing list