[pypy-commit] pypy strbuf-as-buffer: merge default
plan_rich
pypy.commits at gmail.com
Tue Dec 20 09:30:06 EST 2016
Author: Richard Plangger <planrichi at gmail.com>
Branch: strbuf-as-buffer
Changeset: r89201:e5ac7ec7ab17
Date: 2016-12-20 15:29 +0100
http://bitbucket.org/pypy/pypy/changeset/e5ac7ec7ab17/
Log: merge default
diff too long, truncating to 2000 out of 16301 lines
diff --git a/.hgignore b/.hgignore
--- a/.hgignore
+++ b/.hgignore
@@ -77,3 +77,5 @@
^.hypothesis/
^release/
^rpython/_cache$
+
+pypy/module/cppyy/.+/*\.pcm
diff --git a/lib_pypy/greenlet.egg-info b/lib_pypy/greenlet.egg-info
--- a/lib_pypy/greenlet.egg-info
+++ b/lib_pypy/greenlet.egg-info
@@ -1,6 +1,6 @@
Metadata-Version: 1.0
Name: greenlet
-Version: 0.4.10
+Version: 0.4.11
Summary: Lightweight in-process concurrent programming
Home-page: https://github.com/python-greenlet/greenlet
Author: Ralf Schmitt (for CPython), PyPy team
diff --git a/lib_pypy/greenlet.py b/lib_pypy/greenlet.py
--- a/lib_pypy/greenlet.py
+++ b/lib_pypy/greenlet.py
@@ -1,7 +1,7 @@
import sys
import _continuation
-__version__ = "0.4.10"
+__version__ = "0.4.11"
# ____________________________________________________________
# Exceptions
diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py
--- a/pypy/config/pypyoption.py
+++ b/pypy/config/pypyoption.py
@@ -190,6 +190,12 @@
"make sure that all calls go through space.call_args",
default=False),
+ BoolOption("disable_entrypoints",
+ "Disable external entry points, notably the"
+ " cpyext module and cffi's embedding mode.",
+ default=False,
+ requires=[("objspace.usemodules.cpyext", False)]),
+
OptionDescription("std", "Standard Object Space Options", [
BoolOption("withtproxy", "support transparent proxies",
default=True),
diff --git a/pypy/doc/contributor.rst b/pypy/doc/contributor.rst
--- a/pypy/doc/contributor.rst
+++ b/pypy/doc/contributor.rst
@@ -1,3 +1,9 @@
+#encoding utf-8
+
+Contributors
+------------
+::
+
Armin Rigo
Maciej Fijalkowski
Carl Friedrich Bolz
@@ -307,7 +313,7 @@
Mads Kiilerich
Antony Lee
Jason Madden
- Daniel Neuh�user
+ Daniel Neuhäuser
reubano at gmail.com
Yaroslav Fedevych
Jim Hunziker
diff --git a/pypy/doc/cppyy.rst b/pypy/doc/cppyy.rst
--- a/pypy/doc/cppyy.rst
+++ b/pypy/doc/cppyy.rst
@@ -1,145 +1,61 @@
cppyy: C++ bindings for PyPy
============================
-The cppyy module creates, at run-time, Python-side classes and functions for
-C++, by querying a C++ reflection system.
-The default system used is `Reflex`_, which extracts the needed information
-from C++ header files.
-Another current backend is based on `CINT`_, and yet another, more important
-one for the medium- to long-term will be based on `cling`_.
-The latter sits on top of `llvm`_'s `clang`_, and will therefore allow the use
-of C++11.
-The work on the cling backend has so far been done only for CPython, but
-bringing it to PyPy is a lot less work than developing it in the first place.
+The cppyy module delivers dynamic Python-C++ bindings.
+It is designed for automation, high performance, scale, interactivity, and
+handling all of modern C++ (11, 14, etc.).
+It is based on `Cling`_ which, through `LLVM`_/`clang`_, provides C++
+reflection and interactivity.
+Reflection information is extracted from C++ header files.
+Cppyy itself is built into PyPy (an alternative exists for CPython), but
+it requires a `backend`_, installable through pip, to interface with Cling.
-.. _Reflex: https://root.cern.ch/how/how-use-reflex
-.. _CINT: https://root.cern.ch/introduction-cint
-.. _cling: https://root.cern.ch/cling
-.. _llvm: http://llvm.org/
+.. _Cling: https://root.cern.ch/cling
+.. _LLVM: http://llvm.org/
.. _clang: http://clang.llvm.org/
-
-This document describes the version of cppyy that lives in the main branch of
-PyPy.
-The development of cppyy happens in the "reflex-support" branch.
-
-
-Motivation
-----------
-
-To provide bindings to another language in CPython, you program to a
-generic C-API that exposes many of the interpreter features.
-With PyPy, however, there is no such generic C-API, because several of the
-interpreter features (e.g. the memory model) are pluggable and therefore
-subject to change.
-Furthermore, a generic API does not allow any assumptions about the calls
-into another language, forcing the JIT to behave conservatively around these
-calls and with the objects that cross language boundaries.
-In contrast, cppyy does not expose an API, but expects one to be implemented
-by a backend.
-It makes strong assumptions about the semantics of the API that it uses and
-that in turn allows the JIT to make equally strong assumptions.
-This is possible, because the expected API is only for providing C++ language
-bindings, and does not provide generic programmability.
-
-The cppyy module further offers two features, which result in improved
-performance as well as better functionality and cross-language integration.
-First, cppyy itself is written in RPython and therefore open to optimizations
-by the JIT up until the actual point of call into C++.
-This means for example, that if variables are already unboxed by the JIT, they
-can be passed through directly to C++.
-Second, a backend such as Reflex (and cling far more so) adds dynamic features
-to C++, thus greatly reducing impedance mismatches between the two languages.
-For example, Reflex is dynamic enough to allow writing runtime bindings
-generation in python (as opposed to RPython) and this is used to create very
-natural "pythonizations" of the bound code.
-As another example, cling allows automatic instantiations of templates.
-
-See this description of the `cppyy architecture`_ for further details.
-
-.. _cppyy architecture: http://morepypy.blogspot.com/2012/06/architecture-of-cppyy.html
+.. _backend: https://pypi.python.org/pypi/PyPy-cppyy-backend
Installation
------------
-There are two ways of using cppyy, and the choice depends on how pypy-c was
-built: the backend can be builtin, or dynamically loadable.
-The former has the disadvantage of requiring pypy-c to be linked with external
-C++ libraries (e.g. libReflex.so), but has the advantage of being faster in
-some cases.
-That advantage will disappear over time, however, with improvements in the
-JIT.
-Therefore, this document assumes that the dynamically loadable backend is
-chosen (it is, by default).
-See the :doc:`backend documentation <cppyy_backend>`.
+This assumes PyPy2.7 v5.7 or later; earlier versions use a Reflex-based cppyy
+module, which is no longer supported.
+Both the tooling and user-facing Python codes are very backwards compatible,
+however.
+Further dependencies are cmake (for general build), Python2.7 (for LLVM), and
+a modern C++ compiler (one that supports at least C++11).
-A standalone version of Reflex that also provides the dynamically loadable
-backend is available for `download`_. Note this is currently the only way to
-get the dynamically loadable backend, so use this first.
+Assuming you have a recent enough version of PyPy installed, use pip to
+complete the installation of cppyy::
-That version, as well as any other distribution of Reflex (e.g. the one that
-comes with `ROOT`_, which may be part of your Linux distribution as part of
-the selection of scientific software) will also work for a build with the
-builtin backend.
+ $ MAKE_NPROCS=4 pypy-c -m pip install --verbose PyPy-cppyy-backend
-.. _download: http://cern.ch/wlav/reflex-2014-10-20.tar.bz2
-.. _ROOT: http://root.cern.ch/
+Set the number of parallel builds ('4' in this example, through the MAKE_NPROCS
+environment variable) to a number appropriate for your machine.
+The building process may take quite some time as it includes a customized
+version of LLVM as part of Cling, which is why --verbose is recommended so that
+you can see the build progress.
-Besides Reflex, you probably need a version of `gccxml`_ installed, which is
-most easily provided by the packager of your system.
-If you read up on gccxml, you will probably notice that it is no longer being
-developed and hence will not provide C++11 support.
-That's why the medium term plan is to move to cling.
-Note that gccxml is only needed to generate reflection libraries.
-It is not needed to use them.
-
-.. _gccxml: http://www.gccxml.org
-
-To install the standalone version of Reflex, after download::
-
- $ tar jxf reflex-2014-10-20.tar.bz2
- $ cd reflex-2014-10-20
- $ ./build/autogen
- $ ./configure <usual set of options such as --prefix>
- $ make && make install
-
-The usual rules apply: <prefix>/bin needs to be added to the ``PATH`` and
-<prefix>/lib to the ``LD_LIBRARY_PATH`` environment variable.
-For convenience, this document will assume that there is a ``REFLEXHOME``
-variable that points to <prefix>.
-If you downloaded or built the whole of ROOT, ``REFLEXHOME`` should be equal
-to ``ROOTSYS``.
-
-The following is optional, and is only to show how pypy-c can be build
-:doc:`from source <build>`, for example to get at the main development branch of cppyy.
-The :doc:`backend documentation <cppyy_backend>` has more details on the backend-specific
-prerequisites.
-
-Then run the translation to build ``pypy-c``::
-
- $ hg clone https://bitbucket.org/pypy/pypy
- $ cd pypy
- $ hg up reflex-support # optional
-
- # This example shows python, but using pypy-c is faster and uses less memory
- $ python rpython/bin/rpython --opt=jit pypy/goal/targetpypystandalone --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 :ref:`to obtain a binary distribution <prebuilt-pypy>` to speed up the
-translation step.
+The default installation will be under
+$PYTHONHOME/site-packages/cppyy_backend/lib,
+which needs to be added to your dynamic loader path (LD_LIBRARY_PATH).
+If you need the dictionary and class map generation tools (used in the examples
+below), you need to add $PYTHONHOME/site-packages/cppyy_backend/bin to your
+executable path (PATH).
Basic bindings example
----------------------
-Now test with a trivial example whether all packages are properly installed
-and functional.
-First, create a C++ header file with some class in it (note that all functions
-are made inline for convenience; a real-world example would of course have a
-corresponding source file)::
+These examples assume that cppyy_backend is pointed to by the environment
+variable CPPYYHOME, and that CPPYYHOME/lib is added to LD_LIBRARY_PATH and
+CPPYYHOME/bin to PATH.
+
+Let's first test with a trivial example whether all packages are properly
+installed and functional.
+Create a C++ header file with some class in it (all functions are made inline
+for convenience; if you have out-of-line code, link with it as appropriate)::
$ cat MyClass.h
class MyClass {
@@ -153,11 +69,11 @@
int m_myint;
};
-Then, generate the bindings using ``genreflex`` (part of ROOT), and compile the
-code::
+Then, generate the bindings using ``genreflex`` (installed under
+cppyy_backend/bin in site_packages), and compile the code::
$ genreflex MyClass.h
- $ g++ -fPIC -rdynamic -O2 -shared -I$REFLEXHOME/include MyClass_rflx.cpp -o libMyClassDict.so -L$REFLEXHOME/lib -lReflex
+ $ g++ -std=c++11 -fPIC -rdynamic -O2 -shared -I$CPPYYHOME/include MyClass_rflx.cpp -o libMyClassDict.so -L$CPPYYHOME/lib -lCling
Next, make sure that the library can be found through the dynamic lookup path
(the ``LD_LIBRARY_PATH`` environment variable on Linux, ``PATH`` on Windows),
@@ -209,7 +125,7 @@
For example::
$ genreflex MyClass.h --rootmap=libMyClassDict.rootmap --rootmap-lib=libMyClassDict.so
- $ g++ -fPIC -rdynamic -O2 -shared -I$REFLEXHOME/include MyClass_rflx.cpp -o libMyClassDict.so -L$REFLEXHOME/lib -lReflex
+ $ g++ -std=c++11 -fPIC -rdynamic -O2 -shared -I$CPPYYHOME/include MyClass_rflx.cpp -o libMyClassDict.so -L$CPPYYHOME/lib -lCling
where the first option (``--rootmap``) specifies the output file name, and the
second option (``--rootmap-lib``) the name of the reflection library where
@@ -311,7 +227,7 @@
Now the reflection info can be generated and compiled::
$ genreflex MyAdvanced.h --selection=MyAdvanced.xml
- $ g++ -fPIC -rdynamic -O2 -shared -I$REFLEXHOME/include MyAdvanced_rflx.cpp -o libAdvExDict.so -L$REFLEXHOME/lib -lReflex
+ $ g++ -std=c++11 -fPIC -rdynamic -O2 -shared -I$CPPYYHOME/include MyAdvanced_rflx.cpp -o libAdvExDict.so -L$CPPYYHOME/lib -lCling
and subsequently be used from PyPy::
@@ -370,7 +286,7 @@
bound using::
$ genreflex example.h --deep --rootmap=libexampleDict.rootmap --rootmap-lib=libexampleDict.so
- $ g++ -fPIC -rdynamic -O2 -shared -I$REFLEXHOME/include example_rflx.cpp -o libexampleDict.so -L$REFLEXHOME/lib -lReflex
+ $ g++ -std=c++11 -fPIC -rdynamic -O2 -shared -I$CPPYYHOME/include example_rflx.cpp -o libexampleDict.so -L$CPPYYHOME/lib -lCling
* **abstract classes**: Are represented as python classes, since they are
needed to complete the inheritance hierarchies, but will raise an exception
@@ -666,13 +582,10 @@
Templates
---------
-A bit of special care needs to be taken for the use of templates.
-For a templated class to be completely available, it must be guaranteed that
-said class is fully instantiated, and hence all executable C++ code is
-generated and compiled in.
-The easiest way to fulfill that guarantee is by explicit instantiation in the
-header file that is handed to ``genreflex``.
-The following example should make that clear::
+Templates can be automatically instantiated, assuming the appropriate header
+files have been loaded or are accessible to the class loader.
+This is the case for example for all of STL.
+For example::
$ cat MyTemplate.h
#include <vector>
@@ -686,68 +599,10 @@
int m_i;
};
- #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``.
-An alternative is to add an object to an unnamed namespace::
-
- namespace {
- std::vector<MyClass> vmc;
- } // unnamed namespace
-
-Unfortunately, this is not always enough for gcc.
-The iterators of vectors, if they are going to be used, need to be
-instantiated as well, as do the comparison operators on those iterators, as
-these live in an internal namespace, rather than in the iterator classes.
-Note that you do NOT need this iterators to iterator over a vector.
-You only need them if you plan to explicitly call e.g. ``begin`` and ``end``
-methods, and do comparisons of iterators.
-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 (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 >; \
- template class __gnu_cxx::__normal_iterator<TTYPE*, std::STLTYPE< TTYPE > >; \
- template class __gnu_cxx::__normal_iterator<const TTYPE*, std::STLTYPE< TTYPE > >;\
- namespace __gnu_cxx { \
- template bool operator==(const std::STLTYPE< TTYPE >::iterator&, \
- const std::STLTYPE< TTYPE >::iterator&); \
- template bool operator!=(const std::STLTYPE< TTYPE >::iterator&, \
- const std::STLTYPE< TTYPE >::iterator&); \
- }
-
- STLTYPES_EXPLICIT_INSTANTIATION_DECL(vector, MyClass)
-
-Then, still for gcc, the selection file needs to contain the full hierarchy as
-well as the global overloads for comparisons for the iterators::
-
- $ cat MyTemplate.xml
- <lcgdict>
- <class pattern="std::vector<*>" />
- <class pattern="std::vector<*>::iterator" />
- <function name="__gnu_cxx::operator=="/>
- <function name="__gnu_cxx::operator!="/>
-
- <class name="MyClass" />
- </lcgdict>
-
Run the normal ``genreflex`` and compilation steps::
$ genreflex MyTemplate.h --selection=MyTemplate.xml
- $ g++ -fPIC -rdynamic -O2 -shared -I$REFLEXHOME/include MyTemplate_rflx.cpp -o libTemplateDict.so -L$REFLEXHOME/lib -lReflex
-
-Note: this is a dirty corner that clearly could do with some automation,
-even if the macro already helps.
-Such automation is planned.
-In fact, in the Cling world, the backend can perform the template
-instantations and generate the reflection info on the fly, and none of the
-above will any longer be necessary.
+ $ g++ -std=c++11 -fPIC -rdynamic -O2 -shared -I$CPPYYHOME/include MyTemplate_rflx.cpp -o libTemplateDict.so -L$CPPYYHOME/lib -lCling
Subsequent use should be as expected.
Note the meta-class style of "instantiating" the template::
@@ -764,8 +619,6 @@
1 2 3
>>>>
-Other templates work similarly, but are typically simpler, as there are no
-similar issues with iterators for e.g. ``std::list``.
The arguments to the template instantiation can either be a string with the
full list of arguments, or the explicit classes.
The latter makes for easier code writing if the classes passed to the
@@ -775,95 +628,40 @@
The fast lane
-------------
-The following is an experimental feature of cppyy.
-It mostly works, but there are some known issues (e.g. with return-by-value).
-Soon it should be the default mode, however.
+By default, cppyy will use direct function pointers through `CFFI`_ whenever
+possible. If this causes problems for you, you can disable it by setting the
+CPPYY_DISABLE_FASTPATH environment variable.
-With a slight modification of Reflex, it can provide function pointers for
-C++ methods, and hence allow PyPy to call those pointers directly, rather than
-calling C++ through a Reflex stub.
+.. _CFFI: https://cffi.readthedocs.io/en/latest/
-The standalone version of Reflex `provided`_ has been patched, but if you get
-Reflex from another source (most likely with a ROOT distribution), locate the
-file `genreflex-methptrgetter.patch`_ in pypy/module/cppyy and apply it to
-the genreflex python scripts found in ``$ROOTSYS/lib``::
-
- $ cd $ROOTSYS/lib
- $ patch -p2 < genreflex-methptrgetter.patch
-
-With this patch, ``genreflex`` will have grown the ``--with-methptrgetter``
-option.
-Use this option when running ``genreflex``, and add the
-``-Wno-pmf-conversions`` option to ``g++`` when compiling.
-The rest works the same way: the fast path will be used transparently (which
-also means that you can't actually find out whether it is in use, other than
-by running a micro-benchmark or a JIT test).
-
-.. _provided: http://cern.ch/wlav/reflex-2014-10-20.tar.bz2
-.. _genreflex-methptrgetter.patch: https://bitbucket.org/pypy/pypy/src/default/pypy/module/cppyy/genreflex-methptrgetter.patch
CPython
-------
-Most of the ideas in cppyy come originally from the `PyROOT`_ project.
-Although PyROOT does not support Reflex directly, it has an alter ego called
-"PyCintex" that, in a somewhat roundabout way, does.
-If you installed ROOT, rather than just Reflex, PyCintex should be available
-immediately if you add ``$ROOTSYS/lib`` to the ``PYTHONPATH`` environment
-variable.
+Most of the ideas in cppyy come originally from the `PyROOT`_ project, which
+contains a CPython-based cppyy.py module (with similar dependencies as the
+one that comes with PyPy).
+A standalone pip-installable version is planned, but for now you can install
+ROOT through your favorite distribution installer (available in the science
+section).
.. _PyROOT: https://root.cern.ch/pyroot
-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`` (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,
-so a more descriptive name was chosen for cppyy.
-In addition, PyCintex requires that the names of shared libraries so loaded
-start with "lib" in their name.
-The basic example above, rewritten for PyCintex thus goes like this::
-
- $ python
- >>> import PyCintex
- >>> PyCintex.loadDictionary("libMyClassDict.so")
- >>> myinst = PyCintex.gbl.MyClass(42)
- >>> print myinst.GetMyInt()
- 42
- >>> myinst.SetMyInt(33)
- >>> print myinst.m_myint
- 33
- >>> myinst.m_myint = 77
- >>> print myinst.GetMyInt()
- 77
- >>> help(PyCintex.gbl.MyClass) # shows that normal python introspection works
-
-Other naming differences are such things as taking an address of an object.
-In PyCintex, this is done with ``AddressOf`` whereas in cppyy the choice was
-made to follow the naming as in ``ctypes`` and hence use ``addressof``
-(PyROOT/PyCintex predate ``ctypes`` by several years, and the ROOT project
-follows camel-case, hence the differences).
-
-Of course, this is python, so if any of the naming is not to your liking, all
-you have to do is provide a wrapper script that you import instead of
-importing the ``cppyy`` or ``PyCintex`` modules directly.
-In that wrapper script you can rename methods exactly the way you need it.
-
-In the cling world, all these differences will be resolved.
+There are a couple of minor differences between the two versions of cppyy
+(the CPython version has a few more features).
+Work is on-going to integrate the nightly tests of both to make sure their
+feature sets are equalized.
Python3
-------
-To change versions of CPython (to Python3, another version of Python, or later
-to the `Py3k`_ version of PyPy), the only part that requires recompilation is
-the bindings module, be it ``cppyy`` or ``libPyROOT.so`` (in PyCintex).
-Although ``genreflex`` is indeed a Python tool, the generated reflection
-information is completely independent of Python.
+The CPython version of cppyy supports Python3, assuming your packager has
+build the backend for it.
+The cppyy module has not been tested with the `Py3k`_ version of PyPy.
+Note that the generated reflection information (from ``genreflex``) is fully
+independent of Python, and does not need to be rebuild when switching versions
+or interpreters.
.. _Py3k: https://bitbucket.org/pypy/pypy/src/py3k
@@ -871,5 +669,4 @@
.. toctree::
:hidden:
- cppyy_backend
cppyy_example
diff --git a/pypy/doc/cppyy_backend.rst b/pypy/doc/cppyy_backend.rst
deleted file mode 100644
--- a/pypy/doc/cppyy_backend.rst
+++ /dev/null
@@ -1,45 +0,0 @@
-Backends for cppyy
-==================
-
-The cppyy module needs a backend to provide the C++ reflection information on
-which the Python bindings are build.
-The backend is called through a C-API, which can be found in the PyPy sources
-in: :source:`pypy/module/cppyy/include/capi.h`.
-There are two kinds of API calls: querying about reflection information, which
-are used during the creation of Python-side constructs, and making the actual
-calls into C++.
-The objects passed around are all opaque: cppyy does not make any assumptions
-about them, other than that the opaque handles can be copied.
-Their definition, however, appears in two places: in the C code (in capi.h),
-and on the RPython side (in :source:`capi_types.py <pypy/module/cppyy/capi/capi_types.py>`), so if they are changed, they
-need to be changed on both sides.
-
-There are two places where selections in the RPython code affect the choice
-(and use) of the backend.
-The first is in :source:`pypy/module/cppyy/capi/__init__.py`::
-
- # choose C-API access method:
- from pypy.module.cppyy.capi.loadable_capi import *
- #from pypy.module.cppyy.capi.builtin_capi import *
-
-The default is the loadable C-API.
-Comment it and uncomment the builtin C-API line, to use the builtin version.
-
-Next, if the builtin C-API is chosen, the specific backend needs to be set as
-well (default is Reflex).
-This second choice is in :source:`pypy/module/cppyy/capi/builtin_capi.py`::
-
- import reflex_capi as backend
- #import cint_capi as backend
-
-After those choices have been made, built pypy-c as usual.
-
-When building pypy-c from source, keep the following in mind.
-If the loadable_capi is chosen, no further prerequisites are needed.
-However, for the build of the builtin_capi to succeed, the ``ROOTSYS``
-environment variable must point to the location of your ROOT (or standalone
-Reflex in the case of the Reflex backend) 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``.
diff --git a/pypy/doc/extending.rst b/pypy/doc/extending.rst
--- a/pypy/doc/extending.rst
+++ b/pypy/doc/extending.rst
@@ -12,7 +12,7 @@
* Write them in pure Python and use ctypes_.
-* Write them in C++ and bind them through Reflex_.
+* Write them in C++ and bind them through :doc:`cppyy <cppyy>` using Cling.
* Write them in as `RPython mixed modules`_.
@@ -61,11 +61,11 @@
.. _libffi: http://sourceware.org/libffi/
-Reflex
-------
+Cling and cppyy
+---------------
The builtin :doc:`cppyy <cppyy>` module uses reflection information, provided by
-`Reflex`_ (which needs to be `installed separately`_), of C/C++ code to
+`Cling`_ (which needs to be `installed separately`_), of C/C++ code to
automatically generate bindings at runtime.
In Python, classes and functions are always runtime structures, so when they
are generated matters not for performance.
@@ -76,11 +76,14 @@
The :doc:`cppyy <cppyy>` module is written in RPython, thus PyPy's JIT is able to remove
most cross-language call overhead.
-:doc:`Full details <cppyy>` are `available here <cppyy>`.
+:doc:Full details are `available here <cppyy>`.
-.. _installed separately: http://cern.ch/wlav/reflex-2013-08-14.tar.bz2
-.. _Reflex: https://root.cern.ch/how/how-use-reflex
+.. _installed separately: https://pypi.python.org/pypi/PyPy-cppyy-backend
+.. _Cling: https://root.cern.ch/cling
+.. toctree::
+
+ cppyy
RPython Mixed Modules
---------------------
@@ -94,7 +97,3 @@
This is how the numpy module is being developed.
-.. toctree::
- :hidden:
-
- cppyy
diff --git a/pypy/doc/index-of-release-notes.rst b/pypy/doc/index-of-release-notes.rst
--- a/pypy/doc/index-of-release-notes.rst
+++ b/pypy/doc/index-of-release-notes.rst
@@ -59,6 +59,7 @@
.. toctree::
+ release-pypy3.3-v5.5.0.rst
release-pypy3.3-v5.2-alpha1.rst
CPython 3.2 compatible versions
diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst
--- a/pypy/doc/whatsnew-head.rst
+++ b/pypy/doc/whatsnew-head.rst
@@ -45,3 +45,22 @@
Assign ``tp_doc`` to the new TypeObject's type dictionary ``__doc__`` key
so it will be picked up by app-level objects of that type
+
+.. branch: cling-support
+
+Module cppyy now uses cling as its backend (Reflex has been removed). The
+user-facing interface and main developer tools (genreflex, selection files,
+class loader, etc.) remain the same. A libcppyy_backend.so library is still
+needed but is now available through PyPI with pip: PyPy-cppyy-backend.
+
+The Cling-backend brings support for modern C++ (11, 14, etc.), dynamic
+template instantations, and improved integration with CFFI for better
+performance. It also provides interactive C++ (and bindings to that).
+
+.. branch: better-PyDict_Next
+
+Improve the performance of ``PyDict_Next``. When trying ``PyDict_Next`` on a
+typedef dict, the test exposed a problem converting a ``GetSetProperty`` to a
+``PyGetSetDescrObject``. The other direction seem to be fully implemented.
+This branch made a minimal effort to convert the basic fields to avoid
+segfaults, but trying to use the ``PyGetSetDescrObject`` will probably fail.
diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py
--- a/pypy/goal/targetpypystandalone.py
+++ b/pypy/goal/targetpypystandalone.py
@@ -83,12 +83,18 @@
return 1
return exitcode
+ return entry_point, get_additional_entrypoints(space, w_initstdio)
+
+
+def get_additional_entrypoints(space, w_initstdio):
# register the minimal equivalent of running a small piece of code. This
# should be used as sparsely as possible, just to register callbacks
-
from rpython.rlib.entrypoint import entrypoint_highlevel
from rpython.rtyper.lltypesystem import rffi, lltype
+ if space.config.objspace.disable_entrypoints:
+ return {}
+
@entrypoint_highlevel('main', [rffi.CCHARP, rffi.INT],
c_name='pypy_setup_home')
def pypy_setup_home(ll_home, verbose):
@@ -188,11 +194,11 @@
return -1
return 0
- return entry_point, {'pypy_execute_source': pypy_execute_source,
- 'pypy_execute_source_ptr': pypy_execute_source_ptr,
- 'pypy_init_threads': pypy_init_threads,
- 'pypy_thread_attach': pypy_thread_attach,
- 'pypy_setup_home': pypy_setup_home}
+ return {'pypy_execute_source': pypy_execute_source,
+ 'pypy_execute_source_ptr': pypy_execute_source_ptr,
+ 'pypy_init_threads': pypy_init_threads,
+ 'pypy_thread_attach': pypy_thread_attach,
+ 'pypy_setup_home': pypy_setup_home}
# _____ Define and setup target ___
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -428,6 +428,8 @@
make_finalizer_queue(W_Root, self)
self._code_of_sys_exc_info = None
+ self._builtin_functions_by_identifier = {'': None}
+
# can be overridden to a subclass
self.initialize()
diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py
--- a/pypy/interpreter/function.py
+++ b/pypy/interpreter/function.py
@@ -247,16 +247,15 @@
def descr_function_repr(self):
return self.getrepr(self.space, 'function %s' % (self.name,))
- # delicate
- _all = {'': None}
def _cleanup_(self):
+ # delicate
from pypy.interpreter.gateway import BuiltinCode
if isinstance(self.code, BuiltinCode):
# we have been seen by other means so rtyping should not choke
# on us
identifier = self.code.identifier
- previous = Function._all.get(identifier, self)
+ previous = self.space._builtin_functions_by_identifier.get(identifier, self)
assert previous is self, (
"duplicate function ids with identifier=%r: %r and %r" % (
identifier, previous, self))
@@ -264,10 +263,10 @@
return False
def add_to_table(self):
- Function._all[self.code.identifier] = self
+ self.space._builtin_functions_by_identifier[self.code.identifier] = self
- def find(identifier):
- return Function._all[identifier]
+ def find(space, identifier):
+ return space._builtin_functions_by_identifier[identifier]
find = staticmethod(find)
def descr_function__reduce__(self, space):
diff --git a/pypy/interpreter/gateway.py b/pypy/interpreter/gateway.py
--- a/pypy/interpreter/gateway.py
+++ b/pypy/interpreter/gateway.py
@@ -671,10 +671,10 @@
return space.newtuple([builtin_code,
space.newtuple([space.wrap(self.identifier)])])
- def find(indentifier):
+ @staticmethod
+ def find(space, identifier):
from pypy.interpreter.function import Function
- return Function._all[indentifier].code
- find = staticmethod(find)
+ return Function.find(space, identifier).code
def signature(self):
return self.sig
diff --git a/pypy/interpreter/pyframe.py b/pypy/interpreter/pyframe.py
--- a/pypy/interpreter/pyframe.py
+++ b/pypy/interpreter/pyframe.py
@@ -4,6 +4,7 @@
import sys
from rpython.rlib import jit
from rpython.rlib.debug import make_sure_not_resized, check_nonneg
+from rpython.rlib.debug import ll_assert_not_none
from rpython.rlib.jit import hint
from rpython.rlib.objectmodel import instantiate, specialize, we_are_translated
from rpython.rlib.rarithmetic import intmask, r_uint
@@ -298,7 +299,13 @@
# stack manipulation helpers
def pushvalue(self, w_object):
depth = self.valuestackdepth
- self.locals_cells_stack_w[depth] = w_object
+ self.locals_cells_stack_w[depth] = ll_assert_not_none(w_object)
+ self.valuestackdepth = depth + 1
+
+ def pushvalue_none(self):
+ depth = self.valuestackdepth
+ # the entry is already None, and remains None
+ assert self.locals_cells_stack_w[depth] is None
self.valuestackdepth = depth + 1
def _check_stack_index(self, index):
@@ -311,6 +318,9 @@
return index >= stackstart
def popvalue(self):
+ return ll_assert_not_none(self.popvalue_maybe_none())
+
+ def popvalue_maybe_none(self):
depth = self.valuestackdepth - 1
assert self._check_stack_index(depth)
assert depth >= 0
@@ -385,6 +395,9 @@
def peekvalue(self, index_from_top=0):
# NOTE: top of the stack is peekvalue(0).
# Contrast this with CPython where it's PEEK(-1).
+ return ll_assert_not_none(self.peekvalue_maybe_none(index_from_top))
+
+ def peekvalue_maybe_none(self, index_from_top=0):
index_from_top = hint(index_from_top, promote=True)
index = self.valuestackdepth + ~index_from_top
assert self._check_stack_index(index)
@@ -396,7 +409,7 @@
index = self.valuestackdepth + ~index_from_top
assert self._check_stack_index(index)
assert index >= 0
- self.locals_cells_stack_w[index] = w_object
+ self.locals_cells_stack_w[index] = ll_assert_not_none(w_object)
@jit.unroll_safe
def dropvaluesuntil(self, finaldepth):
diff --git a/pypy/interpreter/test/test_pyframe.py b/pypy/interpreter/test/test_pyframe.py
--- a/pypy/interpreter/test/test_pyframe.py
+++ b/pypy/interpreter/test/test_pyframe.py
@@ -580,3 +580,25 @@
pass
sys.settrace(None)
assert seen == ['call', 'exception', 'return']
+
+ def test_generator_trace_stopiteration(self):
+ import sys
+ def f():
+ yield 5
+ gen = f()
+ assert next(gen) == 5
+ seen = []
+ def trace_func(frame, event, *args):
+ print('TRACE:', frame, event, args)
+ seen.append(event)
+ return trace_func
+ def g():
+ for x in gen:
+ never_entered
+ sys.settrace(trace_func)
+ g()
+ sys.settrace(None)
+ print 'seen:', seen
+ # on Python 3 we get an extra 'exception' when 'for' catches
+ # StopIteration
+ assert seen == ['call', 'line', 'call', 'return', 'return']
diff --git a/pypy/module/_cffi_backend/__init__.py b/pypy/module/_cffi_backend/__init__.py
--- a/pypy/module/_cffi_backend/__init__.py
+++ b/pypy/module/_cffi_backend/__init__.py
@@ -1,6 +1,6 @@
import sys
from pypy.interpreter.mixedmodule import MixedModule
-from rpython.rlib import rdynload, clibffi, entrypoint
+from rpython.rlib import rdynload, clibffi
from rpython.rtyper.lltypesystem import rffi
VERSION = "1.9.1"
@@ -68,9 +68,14 @@
if has_stdcall:
interpleveldefs['FFI_STDCALL'] = 'space.wrap(%d)' % FFI_STDCALL
- def startup(self, space):
- from pypy.module._cffi_backend import embedding
- embedding.glob.space = space
+ def __init__(self, space, *args):
+ MixedModule.__init__(self, space, *args)
+ #
+ if not space.config.objspace.disable_entrypoints:
+ # import 'embedding', which has the side-effect of registering
+ # the 'pypy_init_embedded_cffi_module' entry point
+ from pypy.module._cffi_backend import embedding
+ embedding.glob.space = space
def get_dict_rtld_constants():
@@ -85,11 +90,3 @@
for _name, _value in get_dict_rtld_constants().items():
Module.interpleveldefs[_name] = 'space.wrap(%d)' % _value
-
-
-# write this entrypoint() here, to make sure it is registered early enough
- at entrypoint.entrypoint_highlevel('main', [rffi.INT, rffi.VOIDP],
- c_name='pypy_init_embedded_cffi_module')
-def pypy_init_embedded_cffi_module(version, init_struct):
- from pypy.module._cffi_backend import embedding
- return embedding.pypy_init_embedded_cffi_module(version, init_struct)
diff --git a/pypy/module/_cffi_backend/embedding.py b/pypy/module/_cffi_backend/embedding.py
--- a/pypy/module/_cffi_backend/embedding.py
+++ b/pypy/module/_cffi_backend/embedding.py
@@ -1,4 +1,5 @@
import os
+from rpython.rlib import entrypoint
from rpython.rtyper.lltypesystem import lltype, rffi
from rpython.translator.tool.cbuild import ExternalCompilationInfo
@@ -46,6 +47,8 @@
glob = Global()
+ at entrypoint.entrypoint_highlevel('main', [rffi.INT, rffi.VOIDP],
+ c_name='pypy_init_embedded_cffi_module')
def pypy_init_embedded_cffi_module(version, init_struct):
# called from __init__.py
name = "?"
diff --git a/pypy/module/_pickle_support/maker.py b/pypy/module/_pickle_support/maker.py
--- a/pypy/module/_pickle_support/maker.py
+++ b/pypy/module/_pickle_support/maker.py
@@ -77,7 +77,7 @@
def builtin_code(space, identifier):
from pypy.interpreter import gateway
try:
- return gateway.BuiltinCode.find(identifier)
+ return gateway.BuiltinCode.find(space, identifier)
except KeyError:
raise oefmt(space.w_RuntimeError,
"cannot unpickle builtin code: %s", identifier)
@@ -86,7 +86,7 @@
def builtin_function(space, identifier):
from pypy.interpreter import function
try:
- return function.Function.find(identifier)
+ return function.Function.find(space, identifier)
except KeyError:
raise oefmt(space.w_RuntimeError,
"cannot unpickle builtin function: %s", identifier)
diff --git a/pypy/module/_ssl/test/test_ssl.py b/pypy/module/_ssl/test/test_ssl.py
--- a/pypy/module/_ssl/test/test_ssl.py
+++ b/pypy/module/_ssl/test/test_ssl.py
@@ -169,8 +169,8 @@
}
def setup_method(self, method):
- # https://www.verisign.net/
- ADDR = "www.verisign.net", 443
+ # https://gmail.com/
+ ADDR = "gmail.com", 443
self.w_s = self.space.appexec([self.space.wrap(ADDR)], """(ADDR):
import socket
diff --git a/pypy/module/cppyy/__init__.py b/pypy/module/cppyy/__init__.py
--- a/pypy/module/cppyy/__init__.py
+++ b/pypy/module/cppyy/__init__.py
@@ -14,7 +14,6 @@
'_set_class_generator' : 'interp_cppyy.set_class_generator',
'_set_function_generator': 'interp_cppyy.set_function_generator',
'_register_class' : 'interp_cppyy.register_class',
- '_is_static' : 'interp_cppyy.is_static',
'_get_nullptr' : 'interp_cppyy.get_nullptr',
'CPPInstanceBase' : 'interp_cppyy.W_CPPInstance',
'addressof' : 'interp_cppyy.addressof',
diff --git a/pypy/module/cppyy/bench/Makefile b/pypy/module/cppyy/bench/Makefile
--- a/pypy/module/cppyy/bench/Makefile
+++ b/pypy/module/cppyy/bench/Makefile
@@ -26,4 +26,4 @@
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)
+ g++ -o $@ bench02.cxx bench02_rflx.cpp -I$(ROOTSYS)/include -shared -std=c++11 -lHistPainter `root-config --libs` $(cppflags) $(cppflags2)
diff --git a/pypy/module/cppyy/capi/builtin_capi.py b/pypy/module/cppyy/capi/builtin_capi.py
--- a/pypy/module/cppyy/capi/builtin_capi.py
+++ b/pypy/module/cppyy/capi/builtin_capi.py
@@ -1,12 +1,11 @@
from rpython.rtyper.lltypesystem import rffi, lltype
+from rpython.rlib.rarithmetic import intmask
from rpython.rlib import jit
-import reflex_capi as backend
-#import cint_capi as backend
+import cling_capi as backend
from pypy.module.cppyy.capi.capi_types import C_SCOPE, C_TYPE, C_OBJECT,\
- C_METHOD, C_INDEX, C_INDEX_ARRAY, WLAVC_INDEX,\
- C_METHPTRGETTER, C_METHPTRGETTER_PTR
+ C_METHOD, C_INDEX, C_INDEX_ARRAY, WLAVC_INDEX, C_FUNC_PTR
identify = backend.identify
pythonize = backend.pythonize
@@ -52,13 +51,6 @@
compilation_info=backend.eci)
def c_get_scope_opaque(space, name):
return _c_get_scope_opaque(name)
-_c_get_template = rffi.llexternal(
- "cppyy_get_template",
- [rffi.CCHARP], C_TYPE,
- releasegil=ts_reflect,
- compilation_info=backend.eci)
-def c_get_template(space, name):
- return _c_get_template(name)
_c_actual_class = rffi.llexternal(
"cppyy_actual_class",
[C_TYPE, C_OBJECT], C_TYPE,
@@ -154,6 +146,13 @@
compilation_info=backend.eci)
def c_call_d(space, cppmethod, cppobject, nargs, args):
return _c_call_d(cppmethod, cppobject, nargs, args)
+_c_call_ld = rffi.llexternal(
+ "cppyy_call_ld",
+ [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.LONGDOUBLE,
+ releasegil=ts_call,
+ compilation_info=backend.eci)
+def c_call_ld(space, cppmethod, cppobject, nargs, args):
+ return _c_call_ld(cppmethod, cppobject, nargs, args)
_c_call_r = rffi.llexternal(
"cppyy_call_r",
@@ -164,11 +163,17 @@
return _c_call_r(cppmethod, cppobject, nargs, args)
_c_call_s = rffi.llexternal(
"cppyy_call_s",
- [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.CCHARP,
+ [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP, rffi.SIZE_TP], rffi.CCHARP,
releasegil=ts_call,
compilation_info=backend.eci)
def c_call_s(space, cppmethod, cppobject, nargs, args):
- return _c_call_s(cppmethod, cppobject, nargs, args)
+ length = lltype.malloc(rffi.SIZE_TP.TO, 1, flavor='raw')
+ try:
+ cstr = _c_call_s(cppmethod, cppobject, nargs, args, length)
+ cstr_len = intmask(length[0])
+ finally:
+ lltype.free(length, flavor='raw')
+ return cstr, cstr_len
_c_constructor = rffi.llexternal(
"cppyy_constructor",
@@ -185,15 +190,14 @@
def c_call_o(space, method, cppobj, nargs, args, cppclass):
return _c_call_o(method, cppobj, nargs, args, cppclass.handle)
-_c_get_methptr_getter = rffi.llexternal(
- "cppyy_get_methptr_getter",
- [C_SCOPE, C_INDEX], C_METHPTRGETTER_PTR,
+_c_get_function_address = rffi.llexternal(
+ "cppyy_get_function_address",
+ [C_SCOPE, C_INDEX], C_FUNC_PTR,
releasegil=ts_reflect,
compilation_info=backend.eci,
- elidable_function=True,
random_effects_on_gcobjs=False)
-def c_get_methptr_getter(space, cppscope, index):
- return _c_get_methptr_getter(cppscope.handle, index)
+def c_get_function_address(space, cppscope, index):
+ return _c_get_function_address(cppscope.handle, index)
# handling of function argument buffer ---------------------------------------
_c_allocate_function_args = rffi.llexternal(
@@ -215,8 +219,8 @@
[], rffi.SIZE_T,
releasegil=ts_memory,
compilation_info=backend.eci,
- elidable_function=True,
random_effects_on_gcobjs=False)
+ at jit.elidable
def c_function_arg_sizeof(space):
return _c_function_arg_sizeof()
_c_function_arg_typeoffset = rffi.llexternal(
@@ -224,8 +228,8 @@
[], rffi.SIZE_T,
releasegil=ts_memory,
compilation_info=backend.eci,
- elidable_function=True,
random_effects_on_gcobjs=False)
+ at jit.elidable
def c_function_arg_typeoffset(space):
return _c_function_arg_typeoffset()
@@ -237,6 +241,20 @@
compilation_info=backend.eci)
def c_is_namespace(space, scope):
return _c_is_namespace(scope)
+_c_is_template = rffi.llexternal(
+ "cppyy_is_template",
+ [rffi.CCHARP], rffi.INT,
+ releasegil=ts_reflect,
+ compilation_info=backend.eci)
+def c_is_template(space, name):
+ return _c_is_template(name)
+_c_is_abstract = rffi.llexternal(
+ "cppyy_is_abstract",
+ [C_SCOPE], rffi.INT,
+ releasegil=ts_reflect,
+ compilation_info=backend.eci)
+def c_is_abstract(space, cpptype):
+ return _c_is_abstract(cpptype)
_c_is_enum = rffi.llexternal(
"cppyy_is_enum",
[rffi.CCHARP], rffi.INT,
@@ -286,9 +304,8 @@
[C_TYPE, C_TYPE], rffi.INT,
releasegil=ts_reflect,
compilation_info=backend.eci,
- elidable_function=True,
random_effects_on_gcobjs=False)
- at jit.elidable_promote('2')
+ at jit.elidable
def c_is_subtype(space, derived, base):
if derived == base:
return 1
@@ -296,12 +313,11 @@
_c_base_offset = rffi.llexternal(
"cppyy_base_offset",
- [C_TYPE, C_TYPE, C_OBJECT, rffi.INT], rffi.SIZE_T,
+ [C_TYPE, C_TYPE, C_OBJECT, rffi.INT], rffi.LONG, # actually ptrdiff_t
releasegil=ts_reflect,
compilation_info=backend.eci,
- elidable_function=True,
random_effects_on_gcobjs=False)
- at jit.elidable_promote('1,2,4')
+ at jit.elidable
def c_base_offset(space, derived, base, address, direction):
if derived == base:
return 0
@@ -340,7 +356,7 @@
i += 1
py_indices.append(index)
index = indices[i]
- c_free(rffi.cast(rffi.VOIDP, indices)) # c_free defined below
+ c_free(space, rffi.cast(rffi.VOIDP, indices)) # c_free defined below
return py_indices
_c_method_name = rffi.llexternal(
@@ -474,7 +490,7 @@
return charp2str_free(space, _c_datamember_type(cppscope.handle, datamember_index))
_c_datamember_offset = rffi.llexternal(
"cppyy_datamember_offset",
- [C_SCOPE, rffi.INT], rffi.SIZE_T,
+ [C_SCOPE, rffi.INT], rffi.LONG, # actually ptrdiff_t
releasegil=ts_reflect,
compilation_info=backend.eci)
def c_datamember_offset(space, cppscope, datamember_index):
@@ -519,27 +535,29 @@
compilation_info=backend.eci)
def c_strtoull(space, svalue):
return _c_strtoull(svalue)
-c_free = rffi.llexternal(
+_c_free = rffi.llexternal(
"cppyy_free",
[rffi.VOIDP], lltype.Void,
releasegil=ts_memory,
compilation_info=backend.eci)
+def c_free(space, voidp):
+ return _c_free(voidp)
def charp2str_free(space, charp):
string = rffi.charp2str(charp)
voidp = rffi.cast(rffi.VOIDP, charp)
- c_free(voidp)
+ _c_free(voidp)
return string
_c_charp2stdstring = rffi.llexternal(
"cppyy_charp2stdstring",
- [rffi.CCHARP], C_OBJECT,
+ [rffi.CCHARP, rffi.SIZE_T], C_OBJECT,
releasegil=ts_helper,
compilation_info=backend.eci)
-def c_charp2stdstring(space, svalue):
- with rffi.scoped_view_charp(svalue) as charp:
- result = _c_charp2stdstring(charp)
- return result
+def c_charp2stdstring(space, pystr, sz):
+ with rffi.scoped_view_charp(pystr) as cstr:
+ cppstr = _c_charp2stdstring(cstr, sz)
+ return cppstr
_c_stdstring2stdstring = rffi.llexternal(
"cppyy_stdstring2stdstring",
[C_OBJECT], C_OBJECT,
@@ -547,3 +565,26 @@
compilation_info=backend.eci)
def c_stdstring2stdstring(space, cppobject):
return _c_stdstring2stdstring(cppobject)
+
+_c_stdvector_valuetype = rffi.llexternal(
+ "cppyy_stdvector_valuetype",
+ [rffi.CCHARP], rffi.CCHARP,
+ releasegil=ts_helper,
+ compilation_info=backend.eci)
+def c_stdvector_valuetype(space, pystr):
+ cstr = rffi.str2charp(pystr)
+ result = _c_stdvector_valuetype(cstr)
+ rffi.free_charp(cstr)
+ if result:
+ return charp2str_free(space, result)
+ return ""
+_c_stdvector_valuesize = rffi.llexternal(
+ "cppyy_stdvector_valuesize",
+ [rffi.CCHARP], rffi.SIZE_T,
+ releasegil=ts_helper,
+ compilation_info=backend.eci)
+def c_stdvector_valuesize(space, pystr):
+ cstr = rffi.str2charp(pystr)
+ result = _c_stdvector_valuesize(cstr)
+ rffi.free_charp(cstr)
+ return result
diff --git a/pypy/module/cppyy/capi/capi_types.py b/pypy/module/cppyy/capi/capi_types.py
--- a/pypy/module/cppyy/capi/capi_types.py
+++ b/pypy/module/cppyy/capi/capi_types.py
@@ -18,5 +18,4 @@
C_INDEX_ARRAY = rffi.LONGP
WLAVC_INDEX = rffi.LONG
-C_METHPTRGETTER = lltype.FuncType([C_OBJECT], rffi.VOIDP)
-C_METHPTRGETTER_PTR = lltype.Ptr(C_METHPTRGETTER)
+C_FUNC_PTR = rffi.VOIDP
diff --git a/pypy/module/cppyy/capi/cint_capi.py b/pypy/module/cppyy/capi/cint_capi.py
deleted file mode 100644
--- a/pypy/module/cppyy/capi/cint_capi.py
+++ /dev/null
@@ -1,437 +0,0 @@
-import py, os, sys
-
-from pypy.interpreter.error import OperationError
-from pypy.interpreter.gateway import interp2app, unwrap_spec
-from pypy.interpreter.typedef import TypeDef
-from pypy.interpreter.baseobjspace import W_Root
-
-from rpython.translator.tool.cbuild import ExternalCompilationInfo
-from rpython.rtyper.lltypesystem import rffi, lltype
-from rpython.rlib import libffi, rdynload
-from rpython.tool.udir import udir
-
-from pypy.module.cppyy.capi.capi_types import C_OBJECT
-
-
-__all__ = ['identify', 'std_string_name', '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:
- rootincpath = [os.path.join(os.environ["ROOTSYS"], "include"), py.path.local(udir)]
- rootlibpath = [os.path.join(os.environ["ROOTSYS"], "lib64"), os.path.join(os.environ["ROOTSYS"], "lib")]
- else:
- rootincpath = [incdir, py.path.local(udir)]
- rootlibpath = commands.getoutput("root-config --libdir").split()
-else:
- rootincpath = [py.path.local(udir)]
- rootlibpath = []
-
-def identify():
- return 'CINT'
-
-ts_reflect = True
-ts_call = True
-ts_memory = False
-ts_helper = False
-
-std_string_name = 'string'
-
-# 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)
-with rffi.scoped_str2charp('libHist.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,
- libraries=["Hist", "Core", "Cint"],
- use_cpp_linker=True,
-)
-
-_c_load_dictionary = rffi.llexternal(
- "cppyy_load_dictionary",
- [rffi.CCHARP], rdynload.DLLHANDLE,
- releasegil=False,
- compilation_info=eci)
-
-def c_load_dictionary(name):
- result = _c_load_dictionary(name)
- # ignore result: libffi.CDLL(name) either returns a handle to the already
- # open file, or will fail as well and produce a correctly formatted error
- return libffi.CDLL(name)
-
-
-# CINT-specific pythonizations ===============================================
-_c_charp2TString = rffi.llexternal(
- "cppyy_charp2TString",
- [rffi.CCHARP], C_OBJECT,
- releasegil=ts_helper,
- compilation_info=eci)
-def c_charp2TString(space, svalue):
- with rffi.scoped_view_charp(svalue) as charp:
- result = _c_charp2TString(charp)
- return result
-_c_TString2TString = rffi.llexternal(
- "cppyy_TString2TString",
- [C_OBJECT], C_OBJECT,
- releasegil=ts_helper,
- compilation_info=eci)
-def c_TString2TString(space, cppobject):
- return _c_TString2TString(cppobject)
-
-def _get_string_data(space, w_obj, m1, m2 = None):
- from pypy.module.cppyy import interp_cppyy
- obj = space.interp_w(interp_cppyy.W_CPPInstance, w_obj)
- w_1 = obj.space.call_method(w_obj, m1)
- if m2 is None:
- return w_1
- return obj.space.call_method(w_1, m2)
-
-### TF1 ----------------------------------------------------------------------
-class State(object):
- def __init__(self, space):
- self.tfn_pyfuncs = []
- self.tfn_callbacks = []
-
-_create_tf1 = rffi.llexternal(
- "cppyy_create_tf1",
- [rffi.CCHARP, rffi.ULONG, rffi.DOUBLE, rffi.DOUBLE, rffi.INT], C_OBJECT,
- releasegil=False,
- compilation_info=eci)
-
- at unwrap_spec(args_w='args_w')
-def tf1_tf1(space, w_self, args_w):
- """Pythonized version of TF1 constructor:
- takes functions and callable objects, and allows a callback into them."""
-
- from pypy.module.cppyy import interp_cppyy
- tf1_class = interp_cppyy.scope_byname(space, "TF1")
-
- # expected signature:
- # 1. (char* name, pyfunc, double xmin, double xmax, int npar = 0)
- argc = len(args_w)
-
- try:
- if argc < 4 or 5 < argc:
- raise TypeError("wrong number of arguments")
-
- # first argument must be a name
- funcname = space.str_w(args_w[0])
-
- # last (optional) argument is number of parameters
- npar = 0
- if argc == 5: npar = space.int_w(args_w[4])
-
- # second argument must be a callable python object
- w_callable = args_w[1]
- if not space.is_true(space.callable(w_callable)):
- raise TypeError("2nd argument is not a valid python callable")
-
- # generate a pointer to function
- from pypy.module._cffi_backend import newtype, ctypefunc, func
-
- c_double = newtype.new_primitive_type(space, 'double')
- c_doublep = newtype.new_pointer_type(space, c_double)
-
- # wrap the callable as the signature needs modifying
- w_ifunc = interp_cppyy.get_interface_func(space, w_callable, npar)
-
- w_cfunc = ctypefunc.W_CTypeFunc(space, [c_doublep, c_doublep], c_double, False)
- w_callback = func.callback(space, w_cfunc, w_ifunc, None)
- funcaddr = rffi.cast(rffi.ULONG, w_callback.get_closure())
-
- # so far, so good; leaves on issue: CINT is expecting a wrapper, but
- # we need the overload that takes a function pointer, which is not in
- # the dictionary, hence this helper:
- newinst = _create_tf1(space.str_w(args_w[0]), funcaddr,
- space.float_w(args_w[2]), space.float_w(args_w[3]), npar)
-
- # w_self is a null-ptr bound as TF1
- from pypy.module.cppyy.interp_cppyy import W_CPPInstance, memory_regulator
- cppself = space.interp_w(W_CPPInstance, w_self, can_be_None=False)
- cppself._rawobject = newinst
- memory_regulator.register(cppself)
-
- # tie all the life times to the TF1 instance
- space.setattr(w_self, space.wrap('_callback'), w_callback)
-
- # by definition for __init__
- return None
-
- except (OperationError, TypeError, IndexError) as e:
- newargs_w = args_w[1:] # drop class
-
- # return control back to the original, unpythonized overload
- ol = tf1_class.get_overload("TF1")
- return ol.call(None, newargs_w)
-
-### TTree --------------------------------------------------------------------
-_ttree_Branch = rffi.llexternal(
- "cppyy_ttree_Branch",
- [rffi.VOIDP, rffi.CCHARP, rffi.CCHARP, rffi.VOIDP, rffi.INT, rffi.INT], C_OBJECT,
- releasegil=False,
- compilation_info=eci)
-
- at unwrap_spec(args_w='args_w')
-def ttree_Branch(space, w_self, args_w):
- """Pythonized version of TTree::Branch(): takes proxy objects and by-passes
- the CINT-manual layer."""
-
- from pypy.module.cppyy import interp_cppyy
- tree_class = interp_cppyy.scope_byname(space, "TTree")
-
- # sigs to modify (and by-pass CINT):
- # 1. (const char*, const char*, T**, Int_t=32000, Int_t=99)
- # 2. (const char*, T**, Int_t=32000, Int_t=99)
- argc = len(args_w)
-
- # basic error handling of wrong arguments is best left to the original call,
- # so that error messages etc. remain consistent in appearance: the following
- # block may raise TypeError or IndexError to break out anytime
-
- try:
- if argc < 2 or 5 < argc:
- raise TypeError("wrong number of arguments")
-
- tree = space.interp_w(interp_cppyy.W_CPPInstance, w_self, can_be_None=True)
- if (tree is None) or (tree.cppclass != tree_class):
- raise TypeError("not a TTree")
-
- # first argument must always always be cont char*
- branchname = space.str_w(args_w[0])
-
- # if args_w[1] is a classname, then case 1, else case 2
- try:
- classname = space.str_w(args_w[1])
- addr_idx = 2
- w_address = args_w[addr_idx]
- except (OperationError, TypeError):
- addr_idx = 1
- w_address = args_w[addr_idx]
-
- bufsize, splitlevel = 32000, 99
- if addr_idx+1 < argc: bufsize = space.c_int_w(args_w[addr_idx+1])
- if addr_idx+2 < argc: splitlevel = space.c_int_w(args_w[addr_idx+2])
-
- # now retrieve the W_CPPInstance and build other stub arguments
- space = tree.space # holds the class cache in State
- cppinstance = space.interp_w(interp_cppyy.W_CPPInstance, w_address)
- address = rffi.cast(rffi.VOIDP, cppinstance.get_rawobject())
- klassname = cppinstance.cppclass.full_name()
- vtree = rffi.cast(rffi.VOIDP, tree.get_rawobject())
-
- # call the helper stub to by-pass CINT
- vbranch = _ttree_Branch(vtree, branchname, klassname, address, bufsize, splitlevel)
- branch_class = interp_cppyy.scope_byname(space, "TBranch")
- w_branch = interp_cppyy.wrap_cppobject(space, vbranch, branch_class)
- return w_branch
- except (OperationError, TypeError, IndexError):
- pass
-
- # return control back to the original, unpythonized overload
- ol = tree_class.get_overload("Branch")
- return ol.call(w_self, args_w)
-
-def activate_branch(space, w_branch):
- w_branches = space.call_method(w_branch, "GetListOfBranches")
- for i in range(space.r_longlong_w(space.call_method(w_branches, "GetEntriesFast"))):
- w_b = space.call_method(w_branches, "At", space.wrap(i))
- activate_branch(space, w_b)
- space.call_method(w_branch, "SetStatus", space.wrap(1))
- space.call_method(w_branch, "ResetReadEntry")
-
-c_ttree_GetEntry = rffi.llexternal(
- "cppyy_ttree_GetEntry",
- [rffi.VOIDP, rffi.LONGLONG], rffi.LONGLONG,
- releasegil=False,
- compilation_info=eci)
-
- at unwrap_spec(args_w='args_w')
-def ttree_getattr(space, w_self, args_w):
- """Specialized __getattr__ for TTree's that allows switching on/off the
- reading of individual branchs."""
-
- from pypy.module.cppyy import interp_cppyy
- tree = space.interp_w(interp_cppyy.W_CPPInstance, w_self)
-
- space = tree.space # holds the class cache in State
-
- # prevent recursion
- attr = space.str_w(args_w[0])
- if attr and attr[0] == '_':
- raise OperationError(space.w_AttributeError, args_w[0])
-
- # try the saved cdata (for builtin types)
- try:
- w_cdata = space.getattr(w_self, space.wrap('_'+attr))
- from pypy.module._cffi_backend import cdataobj
- cdata = space.interp_w(cdataobj.W_CData, w_cdata, can_be_None=False)
- return cdata.convert_to_object()
- except OperationError:
- pass
-
- # setup branch as a data member and enable it for reading
- w_branch = space.call_method(w_self, "GetBranch", args_w[0])
- if not space.is_true(w_branch):
- raise OperationError(space.w_AttributeError, args_w[0])
- activate_branch(space, w_branch)
-
- # figure out from where we're reading
- entry = space.r_longlong_w(space.call_method(w_self, "GetReadEntry"))
- if entry == -1:
- entry = 0
-
- # setup cache structure
- w_klassname = space.call_method(w_branch, "GetClassName")
- if space.is_true(w_klassname):
- # some instance
- klass = interp_cppyy.scope_byname(space, space.str_w(w_klassname))
- w_obj = klass.construct()
- # 0x10000 = kDeleteObject; reset because we own the object
- space.call_method(w_branch, "ResetBit", space.wrap(0x10000))
- space.call_method(w_branch, "SetObject", w_obj)
- space.call_method(w_branch, "GetEntry", space.wrap(entry))
- space.setattr(w_self, args_w[0], w_obj)
- return w_obj
- else:
- # builtin data
- w_leaf = space.call_method(w_self, "GetLeaf", args_w[0])
- space.call_method(w_branch, "GetEntry", space.wrap(entry))
-
- # location
- w_address = space.call_method(w_leaf, "GetValuePointer")
- buf = space.getarg_w('s*', w_address)
- from pypy.module._rawffi import buffer
- assert isinstance(buf, buffer.RawFFIBuffer)
- address = rffi.cast(rffi.CCHARP, buf.datainstance.ll_buffer)
-
- # placeholder
- w_typename = space.call_method(w_leaf, "GetTypeName" )
- from pypy.module.cppyy import capi
- typename = capi.c_resolve_name(space, space.str_w(w_typename))
- if typename == 'bool': typename = '_Bool'
- w_address = space.call_method(w_leaf, "GetValuePointer")
- from pypy.module._cffi_backend import cdataobj, newtype
- cdata = cdataobj.W_CData(space, address, newtype.new_primitive_type(space, typename))
-
- # cache result
- space.setattr(w_self, space.wrap('_'+attr), space.wrap(cdata))
- return space.getattr(w_self, args_w[0])
-
-class W_TTreeIter(W_Root):
- def __init__(self, space, w_tree):
- from pypy.module.cppyy import interp_cppyy
- tree = space.interp_w(interp_cppyy.W_CPPInstance, w_tree)
- self.vtree = rffi.cast(rffi.VOIDP, tree.get_cppthis(tree.cppclass))
- self.w_tree = w_tree
-
- self.current = 0
- self.maxentry = space.r_longlong_w(space.call_method(w_tree, "GetEntriesFast"))
-
- space = self.space = tree.space # holds the class cache in State
- space.call_method(w_tree, "SetBranchStatus", space.wrap("*"), space.wrap(0))
-
- def iter_w(self):
- return self.space.wrap(self)
-
- def next_w(self):
- if self.current == self.maxentry:
- raise OperationError(self.space.w_StopIteration, self.space.w_None)
- # TODO: check bytes read?
- c_ttree_GetEntry(self.vtree, self.current)
- self.current += 1
- return self.w_tree
-
-W_TTreeIter.typedef = TypeDef(
- 'TTreeIter',
- __iter__ = interp2app(W_TTreeIter.iter_w),
- next = interp2app(W_TTreeIter.next_w),
-)
-
-def ttree_iter(space, w_self):
- """Allow iteration over TTree's. Also initializes branch data members and
- sets addresses, if needed."""
- w_treeiter = W_TTreeIter(space, w_self)
- return w_treeiter
-
-# setup pythonizations for later use at run-time
-_pythonizations = {}
-def register_pythonizations(space):
- "NOT_RPYTHON"
-
- allfuncs = [
-
- ### TF1
- tf1_tf1,
-
- ### TTree
- ttree_Branch, ttree_iter, ttree_getattr,
- ]
-
- for f in allfuncs:
- _pythonizations[f.__name__] = space.wrap(interp2app(f))
-
-def _method_alias(space, w_pycppclass, m1, m2):
- space.setattr(w_pycppclass, space.wrap(m1),
- space.getattr(w_pycppclass, space.wrap(m2)))
-
-# callback coming in when app-level bound classes have been created
-def pythonize(space, name, w_pycppclass):
-
- if name == "TCollection":
- _method_alias(space, w_pycppclass, "append", "Add")
- _method_alias(space, w_pycppclass, "__len__", "GetSize")
-
- elif name == "TF1":
- space.setattr(w_pycppclass, space.wrap("__init__"), _pythonizations["tf1_tf1"])
-
- elif name == "TFile":
- _method_alias(space, w_pycppclass, "__getattr__", "Get")
-
- elif name == "TObjString":
- _method_alias(space, w_pycppclass, "__str__", "GetName")
- _method_alias(space, w_pycppclass, "_cppyy_as_builtin", "GetString")
-
- elif name == "TString":
- _method_alias(space, w_pycppclass, "__str__", "Data")
- _method_alias(space, w_pycppclass, "__len__", "Length")
- _method_alias(space, w_pycppclass, "__cmp__", "CompareTo")
- _method_alias(space, w_pycppclass, "_cppyy_as_builtin", "Data")
-
- elif name == "TTree":
- _method_alias(space, w_pycppclass, "_unpythonized_Branch", "Branch")
-
- space.setattr(w_pycppclass, space.wrap("Branch"), _pythonizations["ttree_Branch"])
- space.setattr(w_pycppclass, space.wrap("__iter__"), _pythonizations["ttree_iter"])
- space.setattr(w_pycppclass, space.wrap("__getattr__"), _pythonizations["ttree_getattr"])
-
- elif name[0:8] == "TVectorT": # TVectorT<> template
- _method_alias(space, w_pycppclass, "__len__", "GetNoElements")
-
-# destruction callback (needs better solution, but this is for CINT
-# only and should not appear outside of ROOT-specific uses)
-from pypy.module.cpyext.api import cpython_api, CANNOT_FAIL
-
- at cpython_api([rffi.VOIDP], lltype.Void, error=CANNOT_FAIL)
-def _Py_cppyy_recursive_remove(space, cppobject):
- from pypy.module.cppyy.interp_cppyy import memory_regulator
- from pypy.module.cppyy.capi import C_OBJECT, C_NULL_OBJECT
-
- obj = memory_regulator.retrieve(rffi.cast(C_OBJECT, cppobject))
- if obj is not None:
- memory_regulator.unregister(obj)
- obj._rawobject = C_NULL_OBJECT
diff --git a/pypy/module/cppyy/capi/cling_capi.py b/pypy/module/cppyy/capi/cling_capi.py
--- a/pypy/module/cppyy/capi/cling_capi.py
+++ b/pypy/module/cppyy/capi/cling_capi.py
@@ -1,8 +1,17 @@
import py, os
+from pypy.objspace.std.iterobject import W_AbstractSeqIterObject
+
+from pypy.interpreter.error import OperationError
+from pypy.interpreter.gateway import interp2app
+
from rpython.translator.tool.cbuild import ExternalCompilationInfo
-from rpython.rtyper.lltypesystem import rffi
-from rpython.rlib import libffi, rdynload
+from rpython.rtyper.lltypesystem import rffi, lltype
+from rpython.rlib.rarithmetic import intmask
+from rpython.rlib import jit, libffi, rdynload
+
+from pypy.module._rawffi.array import W_ArrayInstance
+from pypy.module.cppyy.capi.capi_types import C_OBJECT
__all__ = ['identify', 'std_string_name', 'eci', 'c_load_dictionary']
@@ -16,7 +25,8 @@
if os.environ.get("ROOTSYS"):
if config_stat != 0: # presumably Reflex-only
rootincpath = [os.path.join(os.environ["ROOTSYS"], "interpreter/cling/include"),
- os.path.join(os.environ["ROOTSYS"], "interpreter/llvm/inst/include")]
+ os.path.join(os.environ["ROOTSYS"], "interpreter/llvm/inst/include"),
+ 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]
@@ -39,13 +49,21 @@
std_string_name = 'std::basic_string<char>'
+# force loading (and exposure) of libCore symbols
+with rffi.scoped_str2charp('libCore.so') as ll_libname:
+ _coredll = rdynload.dlopen(ll_libname, rdynload.RTLD_GLOBAL | rdynload.RTLD_NOW)
+
+# require local translator path to pickup common defs
+from rpython.translator import cdir
+translator_c_dir = py.path.local(cdir)
+
eci = ExternalCompilationInfo(
separate_module_files=[srcpath.join("clingcwrapper.cxx")],
- include_dirs=[incpath] + rootincpath,
+ include_dirs=[incpath, translator_c_dir] + rootincpath,
includes=["clingcwrapper.h"],
library_dirs=rootlibpath,
libraries=["Cling"],
- compile_extra=["-fno-strict-aliasing"],
+ compile_extra=["-fno-strict-aliasing", "-std=c++11"],
use_cpp_linker=True,
)
@@ -59,11 +77,120 @@
pch = _c_load_dictionary(name)
return pch
+_c_stdstring2charp = rffi.llexternal(
+ "cppyy_stdstring2charp",
+ [C_OBJECT, rffi.SIZE_TP], rffi.CCHARP,
+ releasegil=ts_helper,
+ compilation_info=eci)
+def c_stdstring2charp(space, cppstr):
+ sz = lltype.malloc(rffi.SIZE_TP.TO, 1, flavor='raw')
+ try:
+ cstr = _c_stdstring2charp(cppstr, sz)
+ cstr_len = intmask(sz[0])
+ finally:
+ lltype.free(sz, flavor='raw')
+ return rffi.charpsize2str(cstr, cstr_len)
-# Cling-specific pythonizations
+# TODO: factor these out ...
+# pythonizations
+
+#
+# std::string behavior
+def stdstring_c_str(space, w_self):
+ """Return a python string taking into account \0"""
+
+ from pypy.module.cppyy import interp_cppyy
+ cppstr = space.interp_w(interp_cppyy.W_CPPInstance, w_self, can_be_None=False)
+ return space.wrap(c_stdstring2charp(space, cppstr._rawobject))
+
+#
+# std::vector behavior
+class W_STLVectorIter(W_AbstractSeqIterObject):
+ _immutable_fields_ = ['overload', 'len']#'data', 'converter', 'len', 'stride', 'vector']
+
+ def __init__(self, space, w_vector):
+ W_AbstractSeqIterObject.__init__(self, w_vector)
+ # TODO: this should live in rpythonize.py or something so that the
+ # imports can move to the top w/o getting circles
+ from pypy.module.cppyy import interp_cppyy
+ assert isinstance(w_vector, interp_cppyy.W_CPPInstance)
+ vector = space.interp_w(interp_cppyy.W_CPPInstance, w_vector)
+ self.overload = vector.cppclass.get_overload("__getitem__")
+
+ from pypy.module.cppyy import capi
+ v_type = capi.c_stdvector_valuetype(space, vector.cppclass.name)
+ v_size = capi.c_stdvector_valuesize(space, vector.cppclass.name)
+
+ if not v_type or not v_size:
+ raise NotImplementedError # fallback on getitem
+
+ w_arr = vector.cppclass.get_overload("data").call(w_vector, [])
+ arr = space.interp_w(W_ArrayInstance, w_arr, can_be_None=True)
+ if not arr:
+ raise OperationError(space.w_StopIteration, space.w_None)
+
+ self.data = rffi.cast(rffi.VOIDP, space.uint_w(arr.getbuffer(space)))
+
+ from pypy.module.cppyy import converter
+ self.converter = converter.get_converter(space, v_type, '')
+ self.len = space.uint_w(vector.cppclass.get_overload("size").call(w_vector, []))
+ self.stride = v_size
+
+ def descr_next(self, space):
+ if self.w_seq is None:
+ raise OperationError(space.w_StopIteration, space.w_None)
+ if self.len <= self.index:
+ self.w_seq = None
+ raise OperationError(space.w_StopIteration, space.w_None)
+ try:
+ from pypy.module.cppyy import capi # TODO: refector
+ offset = capi.direct_ptradd(rffi.cast(C_OBJECT, self.data), self.index*self.stride)
+ w_item = self.converter.from_memory(space, space.w_None, space.w_None, offset)
+ except OperationError as e:
+ self.w_seq = None
+ if not e.match(space, space.w_IndexError):
+ raise
+ raise OperationError(space.w_StopIteration, space.w_None)
+ self.index += 1
+ return w_item
+
+def stdvector_iter(space, w_self):
+ return W_STLVectorIter(space, w_self)
+
+# setup pythonizations for later use at run-time
+_pythonizations = {}
def register_pythonizations(space):
"NOT_RPYTHON"
- pass
+
+ allfuncs = [
+
+ ### std::string
+ stdstring_c_str,
+
+ ### std::vector
+ stdvector_iter,
+
+ ]
+
+ for f in allfuncs:
+ _pythonizations[f.__name__] = space.wrap(interp2app(f))
+
+def _method_alias(space, w_pycppclass, m1, m2):
+ space.setattr(w_pycppclass, space.wrap(m1),
+ space.getattr(w_pycppclass, space.wrap(m2)))
def pythonize(space, name, w_pycppclass):
- pass
+ if name == "string":
+ space.setattr(w_pycppclass, space.wrap("c_str"), _pythonizations["stdstring_c_str"])
+ _method_alias(space, w_pycppclass, "_cppyy_as_builtin", "c_str")
+ _method_alias(space, w_pycppclass, "__str__", "c_str")
+
+ if "vector" in name[:11]: # len('std::vector') == 11
+ from pypy.module.cppyy import capi
+ v_type = capi.c_stdvector_valuetype(space, name)
+ if v_type:
+ space.setattr(w_pycppclass, space.wrap("value_type"), space.wrap(v_type))
+ v_size = capi.c_stdvector_valuesize(space, name)
+ if v_size:
+ space.setattr(w_pycppclass, space.wrap("value_size"), space.wrap(v_size))
+ space.setattr(w_pycppclass, space.wrap("__iter__"), _pythonizations["stdvector_iter"])
diff --git a/pypy/module/cppyy/capi/loadable_capi.py b/pypy/module/cppyy/capi/loadable_capi.py
--- a/pypy/module/cppyy/capi/loadable_capi.py
+++ b/pypy/module/cppyy/capi/loadable_capi.py
@@ -1,14 +1,18 @@
from rpython.rtyper.lltypesystem import rffi, lltype
+from rpython.rlib.rarithmetic import intmask
from rpython.rlib import jit, jit_libffi, libffi, rdynload, objectmodel
from rpython.rlib.rarithmetic import r_singlefloat
from rpython.tool import leakfinder
+from pypy.interpreter.gateway import interp2app
from pypy.interpreter.error import oefmt
from pypy.module._cffi_backend import ctypefunc, ctypeprim, cdataobj, misc
+from pypy.module._cffi_backend import newtype
+from pypy.module.cppyy import ffitypes
from pypy.module.cppyy.capi.capi_types import C_SCOPE, C_TYPE, C_OBJECT,\
- C_METHOD, C_INDEX, C_INDEX_ARRAY, WLAVC_INDEX, C_METHPTRGETTER_PTR
+ C_METHOD, C_INDEX, C_INDEX_ARRAY, WLAVC_INDEX, C_FUNC_PTR
reflection_library = 'libcppyy_backend.so'
@@ -21,11 +25,32 @@
class _Arg: # poor man's union
_immutable_ = True
- def __init__(self, h = 0, l = -1, s = '', vp = rffi.cast(rffi.VOIDP, 0)):
+ def __init__(self, tc, h = 0, l = -1, s = '', p = rffi.cast(rffi.VOIDP, 0)):
+ self.tc = tc
self._handle = h
self._long = l
self._string = s
- self._voidp = vp
+ self._voidp = p
+
+class _ArgH(_Arg):
+ _immutable_ = True
+ def __init__(self, val):
+ _Arg.__init__(self, 'h', h = val)
+
+class _ArgL(_Arg):
+ _immutable_ = True
+ def __init__(self, val):
+ _Arg.__init__(self, 'l', l = val)
+
+class _ArgS(_Arg):
+ _immutable_ = True
+ def __init__(self, val):
+ _Arg.__init__(self, 's', s = val)
+
+class _ArgP(_Arg):
+ _immutable_ = True
+ def __init__(self, val):
+ _Arg.__init__(self, 'p', p = val)
# For the loadable CAPI, the calls start and end in RPython. Therefore, the standard
# _call of W_CTypeFunc, which expects wrapped objects, does not quite work: some
@@ -55,14 +80,18 @@
argtype = self.fargs[i]
# the following is clumsy, but the data types used as arguments are
# very limited, so it'll do for now
- if isinstance(argtype, ctypeprim.W_CTypePrimitiveSigned):
+ if obj.tc == 'l':
+ assert isinstance(argtype, ctypeprim.W_CTypePrimitiveSigned)
misc.write_raw_signed_data(data, rffi.cast(rffi.LONG, obj._long), argtype.size)
- elif isinstance(argtype, ctypeprim.W_CTypePrimitiveUnsigned):
+ elif obj.tc == 'h':
+ assert isinstance(argtype, ctypeprim.W_CTypePrimitiveUnsigned)
misc.write_raw_unsigned_data(data, rffi.cast(rffi.ULONG, obj._handle), argtype.size)
- elif obj._voidp != rffi.cast(rffi.VOIDP, 0):
+ elif obj.tc == 'p':
+ assert obj._voidp != rffi.cast(rffi.VOIDP, 0)
data = rffi.cast(rffi.VOIDPP, data)
data[0] = obj._voidp
else: # only other use is sring
+ assert obj.tc == 's'
n = len(obj._string)
assert raw_string == rffi.cast(rffi.CCHARP, 0)
# XXX could use rffi.get_nonmovingbuffer_final_null()
@@ -89,35 +118,36 @@
self.library = None
self.capi_calls = {}
- import pypy.module._cffi_backend.newtype as nt
+ nt = newtype # module from _cffi_backend
+ state = space.fromcache(ffitypes.State) # factored out common types
# TODO: the following need to match up with the globally defined C_XYZ low-level
# types (see capi/__init__.py), but by using strings here, that isn't guaranteed
- c_opaque_ptr = nt.new_primitive_type(space, 'unsigned long')
+ c_opaque_ptr = state.c_ulong
- c_scope = c_opaque_ptr
- c_type = c_scope
- c_object = c_opaque_ptr
- c_method = c_opaque_ptr
- c_index = nt.new_primitive_type(space, 'long')
+ c_scope = c_opaque_ptr
+ c_type = c_scope
+ c_object = c_opaque_ptr
+ c_method = c_opaque_ptr
+ c_index = state.c_long
+ c_index_array = state.c_voidp
- c_void = nt.new_void_type(space)
- c_char = nt.new_primitive_type(space, 'char')
- c_uchar = nt.new_primitive_type(space, 'unsigned char')
- c_short = nt.new_primitive_type(space, 'short')
- c_int = nt.new_primitive_type(space, 'int')
- c_long = nt.new_primitive_type(space, 'long')
- c_llong = nt.new_primitive_type(space, 'long long')
- c_ullong = nt.new_primitive_type(space, 'unsigned long long')
- c_float = nt.new_primitive_type(space, 'float')
- c_double = nt.new_primitive_type(space, 'double')
+ c_void = state.c_void
+ c_char = state.c_char
+ c_uchar = state.c_uchar
+ c_short = state.c_short
+ c_int = state.c_int
+ c_long = state.c_long
+ c_llong = state.c_llong
+ c_ullong = state.c_ullong
+ c_float = state.c_float
+ c_double = state.c_double
+ c_ldouble = state.c_ldouble
- c_ccharp = nt.new_pointer_type(space, c_char)
- c_index_array = nt.new_pointer_type(space, c_void)
+ c_ccharp = state.c_ccharp
+ c_voidp = state.c_voidp
- c_voidp = nt.new_pointer_type(space, c_void)
c_size_t = nt.new_primitive_type(space, 'size_t')
-
c_ptrdiff_t = nt.new_primitive_type(space, 'ptrdiff_t')
self.capi_call_ifaces = {
@@ -127,7 +157,6 @@
'resolve_name' : ([c_ccharp], c_ccharp),
'get_scope' : ([c_ccharp], c_scope),
- 'get_template' : ([c_ccharp], c_type),
'actual_class' : ([c_type, c_object], c_type),
# memory management
@@ -146,14 +175,16 @@
'call_ll' : ([c_method, c_object, c_int, c_voidp], c_llong),
'call_f' : ([c_method, c_object, c_int, c_voidp], c_float),
'call_d' : ([c_method, c_object, c_int, c_voidp], c_double),
+ 'call_ld' : ([c_method, c_object, c_int, c_voidp], c_ldouble),
'call_r' : ([c_method, c_object, c_int, c_voidp], c_voidp),
- 'call_s' : ([c_method, c_object, c_int, c_voidp], c_ccharp),
+ # call_s actually takes an size_t* as last parameter, but this will do
+ 'call_s' : ([c_method, c_object, c_int, c_voidp, c_voidp], c_ccharp),
'constructor' : ([c_method, c_object, c_int, c_voidp], c_object),
'call_o' : ([c_method, c_object, c_int, c_voidp, c_type], c_object),
- 'get_methptr_getter' : ([c_scope, c_index], c_voidp), # TODO: verify
+ 'get_function_address' : ([c_scope, c_index], c_voidp), # TODO: verify
# handling of function argument buffer
'allocate_function_args' : ([c_int], c_voidp),
@@ -163,6 +194,8 @@
# scope reflection information
More information about the pypy-commit
mailing list