[pypy-commit] pypy refactor-buffer-api: merge default
bdkearns
noreply at buildbot.pypy.org
Thu Apr 24 01:06:56 CEST 2014
Author: Brian Kearns <bdkearns at gmail.com>
Branch: refactor-buffer-api
Changeset: r70899:82aedd1ea884
Date: 2014-04-23 19:05 -0400
http://bitbucket.org/pypy/pypy/changeset/82aedd1ea884/
Log: merge default
diff too long, truncating to 2000 out of 5612 lines
diff --git a/pypy/doc/release-2.3.0.rst b/pypy/doc/release-2.3.0.rst
new file mode 100644
--- /dev/null
+++ b/pypy/doc/release-2.3.0.rst
@@ -0,0 +1,88 @@
+=======================================
+PyPy 2.3 - XXXX TODO
+=======================================
+
+We're pleased to announce PyPy 2.3, which targets version 2.7.6 of the Python
+language. This release updates the stdlib from 2.7.3, jumping directly to 2.7.6.
+
+This release also contains several bugfixes and performance improvements.
+
+You can download the PyPy 2.3 release here:
+
+ http://pypy.org/download.html
+
+We would like to thank our donors for the continued support of the PyPy
+project. We showed quite a bit of progress on all three projects (see below)
+and we're slowly running out of funds.
+Please consider donating more so we can finish those projects! The three
+projects are:
+
+* Py3k (supporting Python 3.x): the release PyPy3 2.2 is imminent.
+
+* STM (software transactional memory): a preview will be released very soon,
+ as soon as we fix a few bugs
+
+* NumPy: the work done is included in the PyPy 2.2 release. More details below.
+
+.. _`Raspberry Pi Foundation`: http://www.raspberrypi.org
+
+What is PyPy?
+=============
+
+PyPy is a very compliant Python interpreter, almost a drop-in replacement for
+CPython 2.7. It's fast (`pypy 2.2 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, Windows
+32, or ARM (ARMv6 or ARMv7, with VFPv3).
+
+Work on the native Windows 64 is still stalling, we would welcome a volunteer
+to handle that.
+
+.. _`pypy 2.2 and cpython 2.7.2`: http://speed.pypy.org
+
+Highlights
+==========
+
+* Our Garbage Collector is now "incremental". It should avoid almost
+ all pauses due to a major collection taking place. Previously, it
+ would pause the program (rarely) to walk all live objects, which
+ could take arbitrarily long if your process is using a whole lot of
+ RAM. Now the same work is done in steps. This should make PyPy
+ more responsive, e.g. in games. There are still other pauses, from
+ the GC and the JIT, but they should be on the order of 5
+ milliseconds each.
+
+* The JIT counters for hot code were never reset, which meant that a
+ process running for long enough would eventually JIT-compile more
+ and more rarely executed code. Not only is it useless to compile
+ such code, but as more compiled code means more memory used, this
+ gives the impression of a memory leak. This has been tentatively
+ fixed by decreasing the counters from time to time.
+
+* NumPy has been split: now PyPy only contains the core module, called
+ ``_numpypy``. The ``numpy`` module itself has been moved to
+ ``https://bitbucket.org/pypy/numpy`` and ``numpypy`` disappeared.
+ You need to install NumPy separately with a virtualenv:
+ ``pip install git+https://bitbucket.org/pypy/numpy.git``;
+ or directly:
+ ``git clone https://bitbucket.org/pypy/numpy.git``;
+ ``cd numpy``; ``pypy setup.py install``.
+
+* non-inlined calls have less overhead
+
+* Things that use ``sys.set_trace`` are now JITted (like coverage)
+
+* JSON decoding is now very fast (JSON encoding was already very fast)
+
+* various buffer copying methods experience speedups (like list-of-ints to
+ ``int[]`` buffer from cffi)
+
+* We finally wrote (hopefully) all the missing ``os.xxx()`` functions,
+ including ``os.startfile()`` on Windows and a handful of rare ones
+ on Posix.
+
+* numpy has a rudimentary C API that cooperates with ``cpyext``
+
+Cheers,
+Armin Rigo and Maciej Fijalkowski
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
@@ -5,7 +5,7 @@
.. this is a revision shortly after release-2.3.x
.. startrev: ba569fe1efdb
-
-
.. branch: small-unroll-improvements
Improve optimiziation of small allocation-heavy loops in the JIT
+
+.. branch: reflex-support
diff --git a/pypy/module/_sre/interp_sre.py b/pypy/module/_sre/interp_sre.py
--- a/pypy/module/_sre/interp_sre.py
+++ b/pypy/module/_sre/interp_sre.py
@@ -34,8 +34,8 @@
def slice_w(space, ctx, start, end, w_default):
if 0 <= start <= end:
- if isinstance(ctx, rsre_core.StrMatchContext):
- return space.wrap(ctx._string[start:end])
+ if isinstance(ctx, rsre_core.BufMatchContext):
+ return space.wrap(ctx._buffer.getslice(start, end, 1, end-start))
elif isinstance(ctx, rsre_core.UnicodeMatchContext):
return space.wrap(ctx._unicodestr[start:end])
else:
@@ -98,7 +98,7 @@
space.wrap("cannot copy this pattern object"))
def make_ctx(self, w_string, pos=0, endpos=sys.maxint):
- """Make a StrMatchContext or a UnicodeMatchContext for searching
+ """Make a BufMatchContext or a UnicodeMatchContext for searching
in the given w_string object."""
space = self.space
if pos < 0:
@@ -114,12 +114,14 @@
return rsre_core.UnicodeMatchContext(self.code, unicodestr,
pos, endpos, self.flags)
else:
- str = space.bufferstr_w(w_string)
- if pos > len(str):
- pos = len(str)
- if endpos > len(str):
- endpos = len(str)
- return rsre_core.StrMatchContext(self.code, str,
+ buf = space.buffer_w(w_string)
+ size = buf.getlength()
+ assert size >= 0
+ if pos > size:
+ pos = size
+ if endpos > size:
+ endpos = size
+ return rsre_core.BufMatchContext(self.code, buf,
pos, endpos, self.flags)
def getmatch(self, ctx, found):
@@ -477,8 +479,8 @@
def fget_string(self, space):
ctx = self.ctx
- if isinstance(ctx, rsre_core.StrMatchContext):
- return space.wrap(ctx._string)
+ if isinstance(ctx, rsre_core.BufMatchContext):
+ return space.wrap(ctx._buffer.as_str())
elif isinstance(ctx, rsre_core.UnicodeMatchContext):
return space.wrap(ctx._unicodestr)
else:
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
@@ -12,8 +12,10 @@
'_template_byname' : 'interp_cppyy.template_byname',
'_std_string_name' : 'interp_cppyy.std_string_name',
'_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',
'CPPInstance' : 'interp_cppyy.W_CPPInstance',
'addressof' : 'interp_cppyy.addressof',
'bind_object' : 'interp_cppyy.bind_object',
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
@@ -190,7 +190,8 @@
[C_SCOPE, C_INDEX], C_METHPTRGETTER_PTR,
releasegil=ts_reflect,
compilation_info=backend.eci,
- elidable_function=True)
+ elidable_function=True,
+ random_effects_on_gcobjs=False)
def c_get_methptr_getter(space, cppscope, index):
return _c_get_methptr_getter(cppscope.handle, index)
@@ -214,7 +215,8 @@
[], rffi.SIZE_T,
releasegil=ts_memory,
compilation_info=backend.eci,
- elidable_function=True)
+ elidable_function=True,
+ random_effects_on_gcobjs=False)
def c_function_arg_sizeof(space):
return _c_function_arg_sizeof()
_c_function_arg_typeoffset = rffi.llexternal(
@@ -222,7 +224,8 @@
[], rffi.SIZE_T,
releasegil=ts_memory,
compilation_info=backend.eci,
- elidable_function=True)
+ elidable_function=True,
+ random_effects_on_gcobjs=False)
def c_function_arg_typeoffset(space):
return _c_function_arg_typeoffset()
@@ -283,7 +286,8 @@
[C_TYPE, C_TYPE], rffi.INT,
releasegil=ts_reflect,
compilation_info=backend.eci,
- elidable_function=True)
+ elidable_function=True,
+ random_effects_on_gcobjs=False)
@jit.elidable_promote('2')
def c_is_subtype(space, derived, base):
if derived == base:
@@ -295,7 +299,8 @@
[C_TYPE, C_TYPE, C_OBJECT, rffi.INT], rffi.SIZE_T,
releasegil=ts_reflect,
compilation_info=backend.eci,
- elidable_function=True)
+ elidable_function=True,
+ random_effects_on_gcobjs=False)
@jit.elidable_promote('1,2,4')
def c_base_offset(space, derived, base, address, direction):
if derived == base:
@@ -543,19 +548,3 @@
compilation_info=backend.eci)
def c_stdstring2stdstring(space, cppobject):
return _c_stdstring2stdstring(cppobject)
-_c_assign2stdstring = rffi.llexternal(
- "cppyy_assign2stdstring",
- [C_OBJECT, rffi.CCHARP], lltype.Void,
- releasegil=ts_helper,
- compilation_info=backend.eci)
-def c_assign2stdstring(space, cppobject, svalue):
- charp = rffi.str2charp(svalue)
- _c_assign2stdstring(cppobject, charp)
- rffi.free_charp(charp)
-_c_free_stdstring = rffi.llexternal(
- "cppyy_free_stdstring",
- [C_OBJECT], lltype.Void,
- releasegil=ts_helper,
- compilation_info=backend.eci)
-def c_free_stdstring(space, cppobject):
- _c_free_stdstring(cppobject)
diff --git a/pypy/module/cppyy/capi/cint_capi.py b/pypy/module/cppyy/capi/cint_capi.py
--- a/pypy/module/cppyy/capi/cint_capi.py
+++ b/pypy/module/cppyy/capi/cint_capi.py
@@ -6,8 +6,11 @@
from pypy.interpreter.baseobjspace import W_Root
from rpython.translator.tool.cbuild import ExternalCompilationInfo
-from rpython.rtyper.lltypesystem import rffi
+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']
@@ -19,21 +22,21 @@
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")]
+ 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]
+ rootincpath = [incdir, py.path.local(udir)]
rootlibpath = commands.getoutput("root-config --libdir").split()
else:
- rootincpath = []
+ rootincpath = [py.path.local(udir)]
rootlibpath = []
def identify():
return 'CINT'
-ts_reflect = False
-ts_call = False
+ts_reflect = True
+ts_call = True
ts_memory = False
ts_helper = False
@@ -47,13 +50,15 @@
_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=["Core", "Cint"],
+ libraries=["Hist", "Core", "Cint"],
use_cpp_linker=True,
)
@@ -71,6 +76,23 @@
# CINT-specific pythonizations ===============================================
+_c_charp2TString = rffi.llexternal(
+ "cppyy_charp2TString",
+ [rffi.CCHARP], C_OBJECT,
+ releasegil=ts_helper,
+ compilation_info=eci)
+def c_charp2TString(space, svalue):
+ charp = rffi.str2charp(svalue)
+ result = _c_charp2TString(charp)
+ rffi.free_charp(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
@@ -80,10 +102,85 @@
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:
+ # Note: argcount is +1 for the class (== w_self)
+ if argc < 5 or 6 < argc:
+ raise TypeError("wrong number of arguments")
+
+ # second argument must be a name
+ funcname = space.str_w(args_w[1])
+
+ # last (optional) argument is number of parameters
+ npar = 0
+ if argc == 6: npar = space.int_w(args_w[5])
+
+ # third argument must be a callable python object
+ w_callable = args_w[2]
+ 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[1]), funcaddr,
+ space.float_w(args_w[3]), space.float_w(args_w[4]), npar)
+
+ from pypy.module.cppyy import interp_cppyy
+ w_instance = interp_cppyy.wrap_cppobject(space, newinst, tf1_class,
+ do_cast=False, python_owns=True, fresh=True)
+
+ # tie all the life times to the TF1 instance
+ space.setattr(w_instance, space.wrap('_callback'), w_callback)
+
+ return w_instance
+ except (OperationError, TypeError, IndexError), 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], rffi.LONG,
+ [rffi.VOIDP, rffi.CCHARP, rffi.CCHARP, rffi.VOIDP, rffi.INT, rffi.INT], C_OBJECT,
releasegil=False,
compilation_info=eci)
@@ -202,6 +299,8 @@
# 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)
@@ -274,6 +373,9 @@
allfuncs = [
+ ### TF1
+ tf1_tf1,
+
### TTree
ttree_Branch, ttree_iter, ttree_getattr,
]
@@ -288,7 +390,14 @@
# callback coming in when app-level bound classes have been created
def pythonize(space, name, w_pycppclass):
- if name == "TFile":
+ 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("__new__"), _pythonizations["tf1_tf1"])
+
+ elif name == "TFile":
_method_alias(space, w_pycppclass, "__getattr__", "Get")
elif name == "TObjString":
@@ -310,3 +419,17 @@
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
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/capi/cling_capi.py
@@ -0,0 +1,69 @@
+import py, os
+
+from rpython.translator.tool.cbuild import ExternalCompilationInfo
+from rpython.rtyper.lltypesystem import rffi
+from rpython.rlib import libffi, rdynload
+
+__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")
+
+import commands
+(config_stat, incdir) = commands.getstatusoutput("root-config --incdir")
+
+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")]
+ 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:
+ if config_stat == 0:
+ rootincpath = [incdir]
+ rootlibpath = commands.getoutput("root-config --libdir").split()
+ else:
+ rootincpath = []
+ rootlibpath = []
+
+def identify():
+ return 'Cling'
+
+ts_reflect = False
+ts_call = 'auto'
+ts_memory = 'auto'
+ts_helper = 'auto'
+
+std_string_name = 'std::basic_string<char>'
+
+eci = ExternalCompilationInfo(
+ separate_module_files=[srcpath.join("clingcwrapper.cxx")],
+ include_dirs=[incpath] + rootincpath,
+ includes=["clingcwrapper.h"],
+ library_dirs=rootlibpath,
+ libraries=["Cling"],
+ compile_extra=["-fno-strict-aliasing"],
+ 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):
+ pch = _c_load_dictionary(name)
+ return pch
+
+
+# Cling-specific pythonizations
+def register_pythonizations(space):
+ "NOT_RPYTHON"
+ pass
+
+def pythonize(space, name, w_pycppclass):
+ pass
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
@@ -214,15 +214,22 @@
'charp2stdstring' : ([c_ccharp], c_object),
'stdstring2stdstring' : ([c_object], c_object),
- 'assign2stdstring' : ([c_object, c_ccharp], c_void),
- 'free_stdstring' : ([c_object], c_void),
}
+ # size/offset are backend-specific but fixed after load
+ self.c_sizeof_farg = 0
+ self.c_offset_farg = 0
+
+
def load_reflection_library(space):
state = space.fromcache(State)
if state.library is None:
from pypy.module._cffi_backend.libraryobj import W_Library
state.library = W_Library(space, reflection_library, rdynload.RTLD_LOCAL | rdynload.RTLD_LAZY)
+ if state.library:
+ # fix constants
+ state.c_sizeof_farg = _cdata_to_size_t(space, call_capi(space, 'function_arg_sizeof', []))
+ state.c_offset_farg = _cdata_to_size_t(space, call_capi(space, 'function_arg_typeoffset', []))
return state.library
def verify_backend(space):
@@ -342,12 +349,12 @@
return _cdata_to_ptr(space, call_capi(space, 'allocate_function_args', [_Arg(l=size)]))
def c_deallocate_function_args(space, cargs):
call_capi(space, 'deallocate_function_args', [_Arg(vp=cargs)])
- at jit.elidable
def c_function_arg_sizeof(space):
- return _cdata_to_size_t(space, call_capi(space, 'function_arg_sizeof', []))
- at jit.elidable
+ state = space.fromcache(State)
+ return state.c_sizeof_farg
def c_function_arg_typeoffset(space):
- return _cdata_to_size_t(space, call_capi(space, 'function_arg_typeoffset', []))
+ state = space.fromcache(State)
+ return state.c_offset_farg
# scope reflection information -----------------------------------------------
def c_is_namespace(space, scope):
@@ -367,13 +374,12 @@
def c_base_name(space, cppclass, base_index):
args = [_Arg(l=cppclass.handle), _Arg(l=base_index)]
return charp2str_free(space, call_capi(space, 'base_name', args))
- at jit.elidable_promote('2')
def c_is_subtype(space, derived, base):
+ jit.promote(base)
if derived == base:
return bool(1)
return space.bool_w(call_capi(space, 'is_subtype', [_Arg(l=derived.handle), _Arg(l=base.handle)]))
- at jit.elidable_promote('1,2,4')
def _c_base_offset(space, derived_h, base_h, address, direction):
args = [_Arg(l=derived_h), _Arg(l=base_h), _Arg(l=address), _Arg(l=direction)]
return _cdata_to_size_t(space, call_capi(space, 'base_offset', args))
@@ -504,11 +510,6 @@
return _cdata_to_cobject(space, call_capi(space, 'charp2stdstring', [_Arg(s=svalue)]))
def c_stdstring2stdstring(space, cppobject):
return _cdata_to_cobject(space, call_capi(space, 'stdstring2stdstring', [_Arg(l=cppobject)]))
-def c_assign2stdstring(space, cppobject, svalue):
- args = [_Arg(l=cppobject), _Arg(s=svalue)]
- call_capi(space, 'assign2stdstring', args)
-def c_free_stdstring(space, cppobject):
- call_capi(space, 'free_stdstring', [_Arg(l=cppobject)])
# loadable-capi-specific pythonizations (none, as the capi isn't known until runtime)
def register_pythonizations(space):
diff --git a/pypy/module/cppyy/converter.py b/pypy/module/cppyy/converter.py
--- a/pypy/module/cppyy/converter.py
+++ b/pypy/module/cppyy/converter.py
@@ -6,8 +6,8 @@
from rpython.rlib.rarithmetic import r_singlefloat
from rpython.rlib import jit_libffi, rfloat
-from pypy.module._rawffi.interp_rawffi import unpack_simple_shape
-from pypy.module._rawffi.array import W_Array
+from pypy.module._rawffi.interp_rawffi import letter2tp
+from pypy.module._rawffi.array import W_Array, W_ArrayInstance
from pypy.module.cppyy import helper, capi, ffitypes
@@ -47,21 +47,35 @@
return rawobject
return capi.C_NULL_OBJECT
+def is_nullpointer_specialcase(space, w_obj):
+ # 0, None, and nullptr may serve as "NULL", check for any of them
+
+ # integer 0
+ try:
+ return space.int_w(w_obj) == 0
+ except Exception:
+ pass
+ # None or nullptr
+ from pypy.module.cppyy import interp_cppyy
+ return space.is_true(space.is_(w_obj, space.w_None)) or \
+ space.is_true(space.is_(w_obj, interp_cppyy.get_nullptr(space)))
+
def get_rawbuffer(space, w_obj):
+ # raw buffer
try:
buf = space.buffer_w(w_obj, space.BUF_SIMPLE)
return rffi.cast(rffi.VOIDP, buf.get_raw_address())
except Exception:
pass
- # special case: allow integer 0 as NULL
+ # array type
try:
- buf = space.int_w(w_obj)
- if buf == 0:
- return rffi.cast(rffi.VOIDP, 0)
+ arr = space.interp_w(W_ArrayInstance, w_obj, can_be_None=True)
+ if arr:
+ return rffi.cast(rffi.VOIDP, space.uint_w(arr.getbuffer(space)))
except Exception:
pass
- # special case: allow None as NULL
- if space.is_true(space.is_(w_obj, space.w_None)):
+ # pre-defined NULL
+ if is_nullpointer_specialcase(space, w_obj):
return rffi.cast(rffi.VOIDP, 0)
raise TypeError("not an addressable buffer")
@@ -118,7 +132,7 @@
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)))
+ arr = self.space.interp_w(W_Array, letter2tp(self.space, typecode))
setattr(self, name, arr)
return arr
raise AttributeError(name)
@@ -139,8 +153,6 @@
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)
@@ -261,8 +273,7 @@
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))
+ self._is_abstract(space)
class BoolConverter(ffitypes.typeid(bool), TypeConverter):
@@ -372,7 +383,12 @@
try:
obj = get_rawbuffer(space, w_obj)
except TypeError:
- obj = rffi.cast(rffi.VOIDP, get_rawobject(space, w_obj))
+ try:
+ # TODO: accept a 'capsule' rather than naked int
+ # (do accept int(0), though)
+ obj = rffi.cast(rffi.VOIDP, space.int_w(w_obj))
+ except Exception:
+ obj = rffi.cast(rffi.VOIDP, get_rawobject(space, w_obj))
return obj
def convert_argument(self, space, w_obj, address, call_local):
@@ -385,6 +401,24 @@
x = rffi.cast(rffi.VOIDPP, address)
x[0] = self._unwrap_object(space, w_obj)
+ def from_memory(self, space, w_obj, w_pycppclass, offset):
+ # returned as a long value for the address (INTPTR_T is not proper
+ # per se, but rffi does not come with a PTRDIFF_T)
+ address = self._get_raw_address(space, w_obj, offset)
+ ptrval = rffi.cast(rffi.ULONG, rffi.cast(rffi.VOIDPP, address)[0])
+ if ptrval == 0:
+ from pypy.module.cppyy import interp_cppyy
+ return interp_cppyy.get_nullptr(space)
+ arr = space.interp_w(W_Array, letter2tp(space, 'P'))
+ return arr.fromaddress(space, ptrval, sys.maxint)
+
+ def to_memory(self, space, w_obj, w_value, offset):
+ address = rffi.cast(rffi.VOIDPP, self._get_raw_address(space, w_obj, offset))
+ if is_nullpointer_specialcase(space, w_value):
+ address[0] = rffi.cast(rffi.VOIDP, 0)
+ else:
+ address[0] = rffi.cast(rffi.VOIDP, self._unwrap_object(space, w_value))
+
class VoidPtrPtrConverter(TypeConverter):
_immutable_fields_ = ['uses_local']
@@ -412,7 +446,7 @@
_immutable_fields_ = ['uses_local']
uses_local = True
-class InstancePtrConverter(TypeConverter):
+class InstanceRefConverter(TypeConverter):
_immutable_fields_ = ['libffitype', 'cppclass']
libffitype = jit_libffi.types.pointer
@@ -444,17 +478,7 @@
x = rffi.cast(rffi.VOIDPP, address)
x[0] = rffi.cast(rffi.VOIDP, 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(space, address, self.cppclass,
- do_cast=False, is_ref=True)
-
- 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):
+class InstanceConverter(InstanceRefConverter):
def convert_argument_libffi(self, space, w_obj, address, call_local):
from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
@@ -468,6 +492,28 @@
def to_memory(self, space, w_obj, w_value, offset):
self._is_abstract(space)
+
+class InstancePtrConverter(InstanceRefConverter):
+
+ def _unwrap_object(self, space, w_obj):
+ try:
+ return InstanceRefConverter._unwrap_object(self, space, w_obj)
+ except OperationError, e:
+ # if not instance, allow certain special cases
+ if is_nullpointer_specialcase(space, w_obj):
+ return capi.C_NULL_OBJECT
+ raise e
+
+ 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(space, address, self.cppclass,
+ do_cast=False, is_ref=True)
+
+ 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 InstancePtrPtrConverter(InstancePtrConverter):
_immutable_fields_ = ['uses_local']
@@ -487,12 +533,6 @@
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):
from pypy.module.cppyy.interp_cppyy import W_CPPInstance
assert isinstance(w_obj, W_CPPInstance)
@@ -501,7 +541,6 @@
class StdStringConverter(InstanceConverter):
- _immutable_fields_ = ['cppclass']
def __init__(self, space, extra):
from pypy.module.cppyy import interp_cppyy
@@ -509,24 +548,25 @@
InstanceConverter.__init__(self, space, cppclass)
def _unwrap_object(self, space, w_obj):
- try:
+ from pypy.module.cppyy.interp_cppyy import W_CPPInstance
+ if isinstance(w_obj, W_CPPInstance):
+ arg = InstanceConverter._unwrap_object(self, space, w_obj)
+ return capi.c_stdstring2stdstring(space, arg)
+ else:
return capi.c_charp2stdstring(space, space.str_w(w_obj))
- except Exception, e:
- arg = InstanceConverter._unwrap_object(self, space, w_obj)
- result = capi.c_stdstring2stdstring(space, arg)
- return result
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))
- capi.c_assign2stdstring(space, address, space.str_w(w_value))
- return
+ assign = self.cppclass.get_overload("__assign__")
+ from pypy.module.cppyy import interp_cppyy
+ assign.call(
+ interp_cppyy.wrap_cppobject(space, address, self.cppclass, do_cast=False), [w_value])
except Exception:
- pass
- return InstanceConverter.to_memory(self, space, w_obj, w_value, offset)
+ InstanceConverter.to_memory(self, space, w_obj, w_value, offset)
def free_argument(self, space, arg, call_local):
- capi.c_free_stdstring(space, rffi.cast(capi.C_OBJECT, rffi.cast(rffi.VOIDPP, arg)[0]))
+ capi.c_destruct(space, self.cppclass, rffi.cast(capi.C_OBJECT, rffi.cast(rffi.VOIDPP, arg)[0]))
class StdStringRefConverter(InstancePtrConverter):
_immutable_fields_ = ['cppclass']
@@ -570,6 +610,7 @@
def free_argument(self, space, arg, call_local):
if hasattr(space, "fake"):
raise NotImplementedError
+ space.getbuiltinmodule("cpyext")
from pypy.module.cpyext.pyobject import Py_DecRef, PyObject
Py_DecRef(space, rffi.cast(PyObject, rffi.cast(rffi.VOIDPP, arg)[0]))
@@ -627,8 +668,10 @@
# 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 == "&":
+ if compound == "*":
return InstancePtrConverter(space, cppclass)
+ elif compound == "&":
+ return InstanceRefConverter(space, cppclass)
elif compound == "**":
return InstancePtrPtrConverter(space, cppclass)
elif compound == "":
@@ -654,7 +697,7 @@
_converters["void**"] = VoidPtrPtrConverter
_converters["void*&"] = VoidPtrRefConverter
-# special cases (note: CINT backend requires the simple name 'string')
+# special cases (note: 'string' aliases added below)
_converters["std::basic_string<char>"] = StdStringConverter
_converters["const std::basic_string<char>&"] = StdStringConverter # TODO: shouldn't copy
_converters["std::basic_string<char>&"] = StdStringRefConverter
@@ -776,3 +819,27 @@
for c_type, alias in aliases:
_converters[alias] = _converters[c_type]
_add_aliased_converters()
+
+# ROOT-specific converters (TODO: this is a general use case and should grow
+# an API; putting it here is done only to circumvent circular imports)
+if capi.identify() == "CINT":
+
+ class TStringConverter(InstanceConverter):
+ def __init__(self, space, extra):
+ from pypy.module.cppyy import interp_cppyy
+ cppclass = interp_cppyy.scope_byname(space, "TString")
+ InstanceConverter.__init__(self, space, cppclass)
+
+ def _unwrap_object(self, space, w_obj):
+ from pypy.module.cppyy import interp_cppyy
+ if isinstance(w_obj, interp_cppyy.W_CPPInstance):
+ arg = InstanceConverter._unwrap_object(self, space, w_obj)
+ return capi.backend.c_TString2TString(space, arg)
+ else:
+ return capi.backend.c_charp2TString(space, space.str_w(w_obj))
+
+ def free_argument(self, space, arg, call_local):
+ capi.c_destruct(space, self.cppclass, rffi.cast(capi.C_OBJECT, rffi.cast(rffi.VOIDPP, arg)[0]))
+
+ _converters["TString"] = TStringConverter
+ _converters["const TString&"] = TStringConverter
diff --git a/pypy/module/cppyy/executor.py b/pypy/module/cppyy/executor.py
--- a/pypy/module/cppyy/executor.py
+++ b/pypy/module/cppyy/executor.py
@@ -53,17 +53,12 @@
if hasattr(space, "fake"):
raise NotImplementedError
lresult = capi.c_call_l(space, cppmethod, cppthis, num_args, args)
- address = rffi.cast(rffi.ULONG, lresult)
+ ptrval = rffi.cast(rffi.ULONG, lresult)
arr = space.interp_w(W_Array, unpack_simple_shape(space, space.wrap(self.typecode)))
- if address == 0:
- # TODO: fix this hack; fromaddress() will allocate memory if address
- # is null and there seems to be no way around it (ll_buffer can not
- # be touched directly)
- nullarr = arr.fromaddress(space, address, 0)
- assert isinstance(nullarr, W_ArrayInstance)
- nullarr.free(space)
- return nullarr
- return arr.fromaddress(space, address, sys.maxint)
+ if ptrval == 0:
+ from pypy.module.cppyy import interp_cppyy
+ return interp_cppyy.get_nullptr(space)
+ return arr.fromaddress(space, ptrval, sys.maxint)
class VoidExecutor(FunctionExecutor):
@@ -144,7 +139,7 @@
from pypy.module.cppyy import interp_cppyy
newthis = capi.c_constructor(space, cppmethod, cpptype, num_args, args)
assert lltype.typeOf(newthis) == capi.C_OBJECT
- return space.wrap(newthis)
+ return space.wrap(rffi.cast(rffi.LONG, newthis)) # really want ptrdiff_t here
class InstancePtrExecutor(FunctionExecutor):
@@ -160,7 +155,8 @@
from pypy.module.cppyy import interp_cppyy
long_result = capi.c_call_l(space, cppmethod, cppthis, num_args, args)
ptr_result = rffi.cast(capi.C_OBJECT, long_result)
- return interp_cppyy.wrap_cppobject(space, ptr_result, self.cppclass)
+ pyres = interp_cppyy.wrap_cppobject(space, ptr_result, self.cppclass)
+ return pyres
def execute_libffi(self, space, cif_descr, funcaddr, buffer):
jit_libffi.jit_ffi_call(cif_descr, funcaddr, buffer)
@@ -189,7 +185,7 @@
long_result = capi.c_call_o(space, cppmethod, cppthis, num_args, args, self.cppclass)
ptr_result = rffi.cast(capi.C_OBJECT, long_result)
return interp_cppyy.wrap_cppobject(space, ptr_result, self.cppclass,
- do_cast=False, python_owns=True)
+ do_cast=False, python_owns=True, fresh=True)
def execute_libffi(self, space, cif_descr, funcaddr, buffer):
from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
@@ -206,6 +202,13 @@
from pypy.module.cppyy.interp_cppyy import FastCallNotPossible
raise FastCallNotPossible
+class StdStringRefExecutor(InstancePtrExecutor):
+
+ def __init__(self, space, cppclass):
+ from pypy.module.cppyy import interp_cppyy
+ cppclass = interp_cppyy.scope_byname(space, capi.std_string_name)
+ InstancePtrExecutor.__init__(self, space, cppclass)
+
class PyObjectExecutor(PtrTypeExecutor):
@@ -295,12 +298,12 @@
_executors["void*"] = PtrTypeExecutor
_executors["const char*"] = CStringExecutor
-# special cases
+# special cases (note: 'string' aliases added below)
_executors["constructor"] = ConstructorExecutor
_executors["std::basic_string<char>"] = StdStringExecutor
-_executors["const std::basic_string<char>&"] = StdStringExecutor
-_executors["std::basic_string<char>&"] = StdStringExecutor # TODO: shouldn't copy
+_executors["const std::basic_string<char>&"] = StdStringRefExecutor
+_executors["std::basic_string<char>&"] = StdStringRefExecutor
_executors["PyObject*"] = PyObjectExecutor
@@ -363,7 +366,11 @@
"NOT_RPYTHON"
aliases = (
("const char*", "char*"),
+
("std::basic_string<char>", "string"),
+ ("const std::basic_string<char>&", "const string&"),
+ ("std::basic_string<char>&", "string&"),
+
("PyObject*", "_object*"),
)
diff --git a/pypy/module/cppyy/include/capi.h b/pypy/module/cppyy/include/capi.h
--- a/pypy/module/cppyy/include/capi.h
+++ b/pypy/module/cppyy/include/capi.h
@@ -89,11 +89,11 @@
cppyy_index_t cppyy_get_global_operator(
cppyy_scope_t scope, cppyy_scope_t lc, cppyy_scope_t rc, const char* op);
- /* method properties ----------------------------------------------------- */
+ /* method properties ------------------------------------------------------ */
int cppyy_is_constructor(cppyy_type_t type, cppyy_index_t idx);
int cppyy_is_staticmethod(cppyy_type_t type, cppyy_index_t idx);
- /* data member reflection information ------------------------------------ */
+ /* 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);
@@ -101,7 +101,7 @@
int cppyy_datamember_index(cppyy_scope_t scope, const char* name);
- /* data member properties ------------------------------------------------ */
+ /* 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);
@@ -112,8 +112,6 @@
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
}
diff --git a/pypy/module/cppyy/include/cintcwrapper.h b/pypy/module/cppyy/include/cintcwrapper.h
--- a/pypy/module/cppyy/include/cintcwrapper.h
+++ b/pypy/module/cppyy/include/cintcwrapper.h
@@ -11,12 +11,18 @@
void* cppyy_load_dictionary(const char* lib_name);
/* pythonization helpers */
+ cppyy_object_t cppyy_create_tf1(const char* funcname, unsigned long address,
+ double xmin, double xmax, int npar);
+
cppyy_object_t cppyy_ttree_Branch(
void* vtree, const char* branchname, const char* classname,
void* addobj, int bufsize, int splitlevel);
long long cppyy_ttree_GetEntry(void* vtree, long long entry);
+ cppyy_object_t cppyy_charp2TString(const char* str);
+ cppyy_object_t cppyy_TString2TString(cppyy_object_t ptr);
+
#ifdef __cplusplus
}
#endif // ifdef __cplusplus
diff --git a/pypy/module/cppyy/include/clingcwrapper.h b/pypy/module/cppyy/include/clingcwrapper.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/include/clingcwrapper.h
@@ -0,0 +1,37 @@
+#ifndef CPPYY_CLINGCWRAPPER
+#define CPPYY_CLINGCWRAPPER
+
+#include "capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif // ifdef __cplusplus
+
+ /* misc helpers */
+ void* cppyy_load_dictionary(const char* lib_name);
+
+#ifdef __cplusplus
+}
+#endif // ifdef __cplusplus
+
+// TODO: pick up from llvm-config --cxxflags
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#ifndef __STDC_CONSTANT_MACROS
+#define __STDC_CONSTANT_MACROS
+#endif
+
+#ifndef __STDC_FORMAT_MACROS
+#define __STDC_FORMAT_MACROS
+#endif
+
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS
+#endif
+
+// Wrapper callback: except this to become available from Cling directly
+typedef void (*CPPYY_Cling_Wrapper_t)(void*, int, void**, void*);
+
+#endif // ifndef CPPYY_CLINGCWRAPPER
diff --git a/pypy/module/cppyy/include/cppyy.h b/pypy/module/cppyy/include/cppyy.h
--- a/pypy/module/cppyy/include/cppyy.h
+++ b/pypy/module/cppyy/include/cppyy.h
@@ -17,7 +17,7 @@
#ifdef __cplusplus
struct CPPYY_G__p2p {
#else
-#typedef struct
+typedef struct {
#endif
long i;
int reftype;
diff --git a/pypy/module/cppyy/interp_cppyy.py b/pypy/module/cppyy/interp_cppyy.py
--- a/pypy/module/cppyy/interp_cppyy.py
+++ b/pypy/module/cppyy/interp_cppyy.py
@@ -40,9 +40,28 @@
def __init__(self, space):
self.cppscope_cache = {
"void" : W_CPPClass(space, "void", capi.C_NULL_TYPE) }
+ self.w_nullptr = None
self.cpptemplate_cache = {}
self.cppclass_registry = {}
self.w_clgen_callback = None
+ self.w_fngen_callback = None
+
+def get_nullptr(space):
+ if hasattr(space, "fake"):
+ raise NotImplementedError
+ state = space.fromcache(State)
+ if state.w_nullptr is None:
+ from pypy.module._rawffi.interp_rawffi import unpack_simple_shape
+ from pypy.module._rawffi.array import W_Array, W_ArrayInstance
+ arr = space.interp_w(W_Array, unpack_simple_shape(space, space.wrap('P')))
+ # TODO: fix this hack; fromaddress() will allocate memory if address
+ # is null and there seems to be no way around it (ll_buffer can not
+ # be touched directly)
+ nullarr = arr.fromaddress(space, rffi.cast(rffi.ULONG, 0), 0)
+ assert isinstance(nullarr, W_ArrayInstance)
+ nullarr.free(space)
+ state.w_nullptr = space.wrap(nullarr)
+ return state.w_nullptr
@unwrap_spec(name=str)
def resolve_name(space, name):
@@ -101,6 +120,11 @@
state = space.fromcache(State)
state.w_clgen_callback = w_callback
+ at unwrap_spec(w_callback=W_Root)
+def set_function_generator(space, w_callback):
+ state = space.fromcache(State)
+ state.w_fngen_callback = w_callback
+
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)
@@ -108,7 +132,7 @@
# class allows simple aliasing of methods)
capi.pythonize(space, cppclass.name, w_pycppclass)
state = space.fromcache(State)
- state.cppclass_registry[cppclass.handle] = w_pycppclass
+ state.cppclass_registry[rffi.cast(rffi.LONG, cppclass.handle)] = w_pycppclass
class W_CPPLibrary(W_Root):
@@ -580,12 +604,10 @@
def get_returntype(self):
return self.space.wrap(self.converter.name)
- @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(self.space,
- cppinstance.cppclass, self.scope, cppinstance.get_rawobject(), 1)
+ offset = self.offset + cppinstance.cppclass.get_base_offset(cppinstance, self.scope)
else:
offset = self.offset
return offset
@@ -694,7 +716,6 @@
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]
@@ -707,7 +728,6 @@
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]
@@ -717,7 +737,6 @@
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
@@ -886,6 +905,10 @@
def find_datamember(self, name):
raise self.missing_attribute_error(name)
+ def get_base_offset(self, cppinstance, calling_scope):
+ assert self == cppinstance.cppclass
+ return 0
+
def get_cppthis(self, cppinstance, calling_scope):
assert self == cppinstance.cppclass
return cppinstance.get_rawobject()
@@ -917,10 +940,15 @@
class W_ComplexCPPClass(W_CPPClass):
- def get_cppthis(self, cppinstance, calling_scope):
+ def get_base_offset(self, cppinstance, calling_scope):
assert self == cppinstance.cppclass
offset = capi.c_base_offset(self.space,
self, calling_scope, cppinstance.get_rawobject(), 1)
+ return offset
+
+ def get_cppthis(self, cppinstance, calling_scope):
+ assert self == cppinstance.cppclass
+ offset = self.get_base_offset(cppinstance, calling_scope)
return capi.direct_ptradd(cppinstance.get_rawobject(), offset)
W_ComplexCPPClass.typedef = TypeDef(
@@ -1130,19 +1158,23 @@
def get_pythonized_cppclass(space, handle):
state = space.fromcache(State)
try:
- w_pycppclass = state.cppclass_registry[handle]
+ w_pycppclass = state.cppclass_registry[rffi.cast(rffi.LONG, handle)]
except KeyError:
final_name = capi.c_scoped_final_name(space, handle)
# the callback will cache the class by calling register_class
w_pycppclass = space.call_function(state.w_clgen_callback, space.wrap(final_name))
return w_pycppclass
+def get_interface_func(space, w_callable, npar):
+ state = space.fromcache(State)
+ return space.call_function(state.w_fngen_callback, w_callable, space.wrap(npar))
+
def wrap_cppobject(space, rawobject, cppclass,
do_cast=True, python_owns=False, is_ref=False, fresh=False):
rawobject = rffi.cast(capi.C_OBJECT, rawobject)
- # cast to actual cast if requested and possible
- w_pycppclass = space.w_None
+ # cast to actual if requested and possible
+ w_pycppclass = None
if do_cast and rawobject:
actual = capi.c_actual_class(space, cppclass, rawobject)
if actual != cppclass.handle:
@@ -1158,7 +1190,7 @@
# the variables are re-assigned yet)
pass
- if space.is_w(w_pycppclass, space.w_None):
+ if w_pycppclass is None:
w_pycppclass = get_pythonized_cppclass(space, cppclass.handle)
# try to recycle existing object if this one is not newly created
@@ -1174,16 +1206,30 @@
memory_regulator.register(cppinstance)
return w_cppinstance
- at unwrap_spec(w_cppinstance=W_CPPInstance)
-def addressof(space, w_cppinstance):
- """Takes a bound C++ instance, returns the raw address."""
- address = rffi.cast(rffi.LONG, w_cppinstance.get_rawobject())
+def _addressof(space, w_obj):
+ try:
+ # attempt to extract address from array
+ return rffi.cast(rffi.INTPTR_T, converter.get_rawbuffer(space, w_obj))
+ except TypeError:
+ pass
+ # attempt to get address of C++ instance
+ return rffi.cast(rffi.INTPTR_T, converter.get_rawobject(space, w_obj))
+
+ at unwrap_spec(w_obj=W_Root)
+def addressof(space, w_obj):
+ """Takes a bound C++ instance or array, returns the raw address."""
+ address = _addressof(space, w_obj)
return space.wrap(address)
- at unwrap_spec(address=int, owns=bool)
-def bind_object(space, address, w_pycppclass, owns=False):
+ at unwrap_spec(owns=bool, cast=bool)
+def bind_object(space, w_obj, w_pycppclass, owns=False, cast=False):
"""Takes an address and a bound C++ class proxy, returns a bound instance."""
- rawobject = rffi.cast(capi.C_OBJECT, address)
+ try:
+ # attempt address from array or C++ instance
+ rawobject = rffi.cast(capi.C_OBJECT, _addressof(space, w_obj))
+ except Exception:
+ # accept integer value as address
+ rawobject = rffi.cast(capi.C_OBJECT, space.uint_w(w_obj))
w_cppclass = space.findattr(w_pycppclass, space.wrap("_cpp_proxy"))
if not w_cppclass:
w_cppclass = scope_byname(space, space.str_w(w_pycppclass))
@@ -1191,4 +1237,4 @@
raise OperationError(space.w_TypeError,
space.wrap("no such class: %s" % space.str_w(w_pycppclass)))
cppclass = space.interp_w(W_CPPClass, w_cppclass, can_be_None=False)
- return wrap_cppobject(space, rawobject, cppclass, do_cast=False, python_owns=owns)
+ return wrap_cppobject(space, rawobject, cppclass, do_cast=cast, python_owns=owns)
diff --git a/pypy/module/cppyy/pythonify.py b/pypy/module/cppyy/pythonify.py
--- a/pypy/module/cppyy/pythonify.py
+++ b/pypy/module/cppyy/pythonify.py
@@ -55,6 +55,19 @@
def clgen_callback(name):
return get_pycppclass(name)
+def fngen_callback(func, npar): # todo, some kind of arg transform spec
+ if npar == 0:
+ def wrapper(a0, a1):
+ la0 = [a0[0], a0[1], a0[2], a0[3]]
+ return func(la0)
+ return wrapper
+ else:
+ def wrapper(a0, a1):
+ la0 = [a0[0], a0[1], a0[2], a0[3]]
+ la1 = [a1[i] for i in range(npar)]
+ return func(la0, la1)
+ return wrapper
+
def make_static_function(func_name, cppol):
def function(*args):
@@ -416,6 +429,9 @@
# class generator callback
cppyy._set_class_generator(clgen_callback)
+ # function generator callback
+ cppyy._set_function_generator(fngen_callback)
+
# 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)
@@ -431,6 +447,9 @@
# be the same issue for all typedef'd builtin types
setattr(gbl, 'unsigned int', int)
+ # install nullptr as a unique reference
+ setattr(gbl, 'nullptr', cppyy._get_nullptr())
+
# install for user access
cppyy.gbl = gbl
diff --git a/pypy/module/cppyy/src/cintcwrapper.cxx b/pypy/module/cppyy/src/cintcwrapper.cxx
--- a/pypy/module/cppyy/src/cintcwrapper.cxx
+++ b/pypy/module/cppyy/src/cintcwrapper.cxx
@@ -8,6 +8,7 @@
#include "TApplication.h"
#include "TInterpreter.h"
+#include "TVirtualMutex.h"
#include "Getline.h"
#include "TBaseClass.h"
@@ -24,6 +25,8 @@
// for pythonization
#include "TTree.h"
#include "TBranch.h"
+#include "TF1.h"
+#include "TString.h"
#include "Api.h"
@@ -34,15 +37,15 @@
#include <string>
#include <utility>
+// for recursive_remove callback
+#include "pypy_macros.h"
+
/* ROOT/CINT internals --------------------------------------------------- */
extern long G__store_struct_offset;
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 {
@@ -57,6 +60,16 @@
TList* fAllPubMethod; //all public methods (including from base classes)
};
+// memory regulation (cppyy_recursive_remove is generated as a cpyext capi call)
+extern "C" void _Py_cppyy_recursive_remove(void*);
+
+class Cppyy_MemoryRegulator : public TObject {
+public:
+ virtual void RecursiveRemove(TObject* object) {
+ _Py_cppyy_recursive_remove((void*)object);
+ }
+};
+
} // unnamed namespace
@@ -82,6 +95,8 @@
/* initialization of the ROOT system (debatable ... ) --------------------- */
namespace {
+static Cppyy_MemoryRegulator s_memreg;
+
class TCppyyApplication : public TApplication {
public:
TCppyyApplication(const char* acn, Int_t* argc, char** argv, Bool_t do_load = kTRUE)
@@ -114,10 +129,13 @@
// enable auto-loader
gInterpreter->EnableAutoLoading();
+
+ // enable memory regulation
+ gROOT->GetListOfCleanups()->Add(&s_memreg);
}
};
-static const char* appname = "pypy-cppyy";
+static const char* appname = "PyPyROOT";
class ApplicationStarter {
public:
@@ -126,11 +144,10 @@
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.
-
+ // CINT ignores std/::std, so point them to the global namespace
+ g_classref_indices["std"] = (ClassRefs_t::size_type)GLOBAL_HANDLE;
+ g_classref_indices["::std"] = (ClassRefs_t::size_type)GLOBAL_HANDLE;
+
// an offset for the interpreted methods
g_interpreted.push_back(G__MethodInfo());
@@ -182,6 +199,7 @@
TClassRef& cr = type_from_handle(handle);
if (cr.GetClass())
return (TFunction*)cr->GetListOfMethods()->At(idx);
+ assert(handle == (cppyy_type_t)GLOBAL_HANDLE);
return (TFunction*)idx;
}
@@ -220,21 +238,25 @@
/* name to opaque C++ scope representation -------------------------------- */
int cppyy_num_scopes(cppyy_scope_t handle) {
+ R__LOCKGUARD2(gCINTMutex);
TClassRef& cr = type_from_handle(handle);
if (cr.GetClass()) {
/* not supported as CINT does not store classes hierarchically */
return 0;
}
+ assert(handle == (cppyy_type_t)GLOBAL_HANDLE);
return gClassTable->Classes();
}
char* cppyy_scope_name(cppyy_scope_t handle, int iscope) {
+ R__LOCKGUARD2(gCINTMutex);
TClassRef& cr = type_from_handle(handle);
if (cr.GetClass()) {
/* not supported as CINT does not store classes hierarchically */
assert(!"scope name lookup not supported on inner scopes");
return 0;
}
+ assert(handle == (cppyy_type_t)GLOBAL_HANDLE);
std::string name = gClassTable->At(iscope);
if (name.find("::") == std::string::npos)
return cppstring_to_cstring(name);
@@ -242,6 +264,7 @@
}
char* cppyy_resolve_name(const char* cppitem_name) {
+ R__LOCKGUARD2(gCINTMutex);
std::string tname = cppitem_name;
// global namespace?
@@ -260,7 +283,7 @@
if (ti.Property() & G__BIT_ISENUM)
return cppstring_to_cstring("unsigned int");
- // actual typedef resolution; add back array declartion portion, if needed
+ // actual typedef resolution; add back array declaration portion, if needed
std::string rt = ti.TrueName();
// builtin STL types have fake typedefs :/
@@ -274,6 +297,8 @@
}
cppyy_scope_t cppyy_get_scope(const char* scope_name) {
+ R__LOCKGUARD2(gCINTMutex);
+
// CINT still has trouble with std:: sometimes ...
if (strncmp(scope_name, "std::", 5) == 0)
scope_name = &scope_name[5];
@@ -303,6 +328,8 @@
}
cppyy_type_t cppyy_get_template(const char* template_name) {
+ R__LOCKGUARD2(gCINTMutex);
+
ClassRefIndices_t::iterator icr = g_classref_indices.find(template_name);
if (icr != g_classref_indices.end())
return (cppyy_type_t)icr->second;
@@ -322,6 +349,7 @@
}
cppyy_type_t cppyy_actual_class(cppyy_type_t klass, cppyy_object_t obj) {
+ R__LOCKGUARD2(gCINTMutex);
TClassRef& cr = type_from_handle(klass);
TClass* clActual = cr->GetActualClass( (void*)obj );
if (clActual && clActual != cr.GetClass()) {
@@ -334,6 +362,7 @@
/* memory management ------------------------------------------------------ */
cppyy_object_t cppyy_allocate(cppyy_type_t handle) {
+ R__LOCKGUARD2(gCINTMutex);
TClassRef& cr = type_from_handle(handle);
return (cppyy_object_t)malloc(cr->Size());
}
@@ -343,6 +372,7 @@
}
void cppyy_destruct(cppyy_type_t handle, cppyy_object_t self) {
+ R__LOCKGUARD2(gCINTMutex);
TClassRef& cr = type_from_handle(handle);
cr->Destructor((void*)self, true);
}
@@ -352,6 +382,8 @@
static inline G__value cppyy_call_T(cppyy_method_t method,
cppyy_object_t self, int nargs, void* args) {
+ R__LOCKGUARD2(gCINTMutex);
+
G__param* libp = (G__param*)((char*)args - offsetof(G__param, para));
assert(libp->paran == nargs);
fixup_args(libp);
@@ -378,7 +410,6 @@
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;
@@ -392,7 +423,6 @@
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();
@@ -449,6 +479,7 @@
}
char* cppyy_call_s(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+ R__LOCKGUARD2(gCINTMutex);
G__value result = cppyy_call_T(method, self, nargs, args);
G__pop_tempobject_nodel();
if (result.ref && *(long*)result.ref) {
@@ -460,6 +491,7 @@
}
cppyy_object_t cppyy_constructor(cppyy_method_t method, cppyy_type_t handle, int nargs, void* args) {
+ R__LOCKGUARD2(gCINTMutex);
cppyy_object_t self = (cppyy_object_t)NULL;
if ((InterpretedFuncs_t::size_type)method >= g_interpreted.size()) {
G__setgvp((long)G__PVOID);
@@ -476,9 +508,10 @@
cppyy_object_t cppyy_call_o(cppyy_type_t method, cppyy_object_t self, int nargs, void* args,
cppyy_type_t /*result_type*/ ) {
+ R__LOCKGUARD2(gCINTMutex);
G__value result = cppyy_call_T(method, self, nargs, args);
G__pop_tempobject_nodel();
- return G__int(result);
+ return (cppyy_object_t)G__int(result);
}
cppyy_methptrgetter_t cppyy_get_methptr_getter(cppyy_type_t /*handle*/, cppyy_index_t /*idx*/) {
@@ -512,15 +545,17 @@
/* scope reflection information ------------------------------------------- */
int cppyy_is_namespace(cppyy_scope_t handle) {
+ R__LOCKGUARD2(gCINTMutex);
TClassRef& cr = type_from_handle(handle);
if (cr.GetClass() && cr->GetClassInfo())
return cr->Property() & G__BIT_ISNAMESPACE;
- if (strcmp(cr.GetClassName(), "") == 0)
+ if (handle == (cppyy_scope_t)GLOBAL_HANDLE)
return true;
return false;
}
int cppyy_is_enum(const char* type_name) {
+ R__LOCKGUARD2(gCINTMutex);
G__TypeInfo ti(type_name);
return (ti.Property() & G__BIT_ISENUM);
}
@@ -528,6 +563,7 @@
/* type/class reflection information -------------------------------------- */
char* cppyy_final_name(cppyy_type_t handle) {
+ R__LOCKGUARD2(gCINTMutex);
TClassRef& cr = type_from_handle(handle);
if (cr.GetClass() && cr->GetClassInfo()) {
std::string true_name = G__TypeInfo(cr->GetName()).TrueName();
@@ -540,6 +576,7 @@
}
char* cppyy_scoped_final_name(cppyy_type_t handle) {
+ R__LOCKGUARD2(gCINTMutex);
TClassRef& cr = type_from_handle(handle);
if (cr.GetClass() && cr->GetClassInfo()) {
std::string true_name = G__TypeInfo(cr->GetName()).TrueName();
@@ -555,6 +592,7 @@
}
int cppyy_num_bases(cppyy_type_t handle) {
+ R__LOCKGUARD2(gCINTMutex);
TClassRef& cr = type_from_handle(handle);
if (cr.GetClass() && cr->GetListOfBases() != 0)
return cr->GetListOfBases()->GetSize();
@@ -562,12 +600,14 @@
}
char* cppyy_base_name(cppyy_type_t handle, int base_index) {
+ R__LOCKGUARD2(gCINTMutex);
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) {
+ R__LOCKGUARD2(gCINTMutex);
TClassRef& derived_type = type_from_handle(derived_handle);
TClassRef& base_type = type_from_handle(base_handle);
return derived_type->GetBaseClass(base_type) != 0;
@@ -575,6 +615,8 @@
size_t cppyy_base_offset(cppyy_type_t derived_handle, cppyy_type_t base_handle,
cppyy_object_t address, int /* direction */) {
+ R__LOCKGUARD2(gCINTMutex);
+
// WARNING: CINT can not handle actual dynamic casts!
TClassRef& derived_type = type_from_handle(derived_handle);
TClassRef& base_type = type_from_handle(base_handle);
@@ -606,10 +648,11 @@
/* method/function reflection information --------------------------------- */
int cppyy_num_methods(cppyy_scope_t handle) {
+ R__LOCKGUARD2(gCINTMutex);
TClassRef& cr = type_from_handle(handle);
if (cr.GetClass() && cr->GetListOfMethods())
return cr->GetListOfMethods()->GetSize();
- else if (strcmp(cr.GetClassName(), "") == 0) {
+ else if (handle == (cppyy_scope_t)GLOBAL_HANDLE) {
if (g_globalfuncs.empty()) {
TCollection* funcs = gROOT->GetListOfGlobalFunctions(kTRUE);
g_globalfuncs.reserve(funcs->GetSize());
@@ -628,13 +671,17 @@
}
cppyy_index_t cppyy_method_index_at(cppyy_scope_t handle, int imeth) {
+ R__LOCKGUARD2(gCINTMutex);
TClassRef& cr = type_from_handle(handle);
if (cr.GetClass())
return (cppyy_index_t)imeth;
+ assert(handle == (cppyy_type_t)GLOBAL_HANDLE);
return (cppyy_index_t)&g_globalfuncs[imeth];
}
cppyy_index_t* cppyy_method_indices_from_name(cppyy_scope_t handle, const char* name) {
+ R__LOCKGUARD2(gCINTMutex);
+
std::vector<cppyy_index_t> result;
TClassRef& cr = type_from_handle(handle);
if (cr.GetClass()) {
@@ -649,14 +696,12 @@
}
++imeth;
}
- }
-
- if (result.empty()) {
+ } else if (handle == (cppyy_scope_t)GLOBAL_HANDLE) {
TCollection* funcs = gROOT->GetListOfGlobalFunctions(kTRUE);
TFunction* func = 0;
TIter ifunc(funcs);
while ((func = (TFunction*)ifunc.Next())) {
- if (strcmp(func->GetName(), name) == 0) {
+ if (strcmp(name, func->GetName()) == 0) {
g_globalfuncs.push_back(*func);
result.push_back((cppyy_index_t)func);
}
@@ -666,7 +711,7 @@
if (result.empty())
return (cppyy_index_t*)0;
- cppyy_index_t* llresult = (cppyy_index_t*)malloc(sizeof(cppyy_index_t)*result.size()+1);
+ cppyy_index_t* llresult = (cppyy_index_t*)malloc(sizeof(cppyy_index_t)*(result.size()+1));
for (int i = 0; i < (int)result.size(); ++i) llresult[i] = result[i];
llresult[result.size()] = -1;
return llresult;
@@ -674,6 +719,7 @@
char* cppyy_method_name(cppyy_scope_t handle, cppyy_index_t idx) {
+ R__LOCKGUARD2(gCINTMutex);
TFunction* f = type_get_method(handle, idx);
std::string name = f->GetName();
TClassRef& cr = type_from_handle(handle);
@@ -685,6 +731,7 @@
}
char* cppyy_method_result_type(cppyy_scope_t handle, cppyy_index_t idx) {
+ R__LOCKGUARD2(gCINTMutex);
TClassRef& cr = type_from_handle(handle);
if (cr.GetClass() && cppyy_is_constructor(handle, idx))
return cppstring_to_cstring("constructor");
@@ -693,16 +740,19 @@
}
int cppyy_method_num_args(cppyy_scope_t handle, cppyy_index_t idx) {
+ R__LOCKGUARD2(gCINTMutex);
TFunction* f = type_get_method(handle, idx);
return f->GetNargs();
}
int cppyy_method_req_args(cppyy_scope_t handle, cppyy_index_t idx) {
+ R__LOCKGUARD2(gCINTMutex);
TFunction* f = type_get_method(handle, idx);
return f->GetNargs() - f->GetNargsOpt();
}
char* cppyy_method_arg_type(cppyy_scope_t handle, cppyy_index_t idx, int arg_index) {
+ R__LOCKGUARD2(gCINTMutex);
TFunction* f = type_get_method(handle, idx);
TMethodArg* arg = (TMethodArg*)f->GetListOfMethodArgs()->At(arg_index);
return type_cppstring_to_cstring(arg->GetFullTypeName());
@@ -714,6 +764,7 @@
}
char* cppyy_method_signature(cppyy_scope_t handle, cppyy_index_t idx) {
+ R__LOCKGUARD2(gCINTMutex);
TClassRef& cr = type_from_handle(handle);
TFunction* f = type_get_method(handle, idx);
std::ostringstream sig;
@@ -733,6 +784,7 @@
int cppyy_method_is_template(cppyy_scope_t handle, cppyy_index_t idx) {
+ R__LOCKGUARD2(gCINTMutex);
TClassRef& cr = type_from_handle(handle);
TFunction* f = type_get_method(handle, idx);
std::string name = f->GetName();
@@ -746,6 +798,7 @@
char* cppyy_method_template_arg_name(
cppyy_scope_t handle, cppyy_index_t idx, cppyy_index_t /*iarg*/) {
+ R__LOCKGUARD2(gCINTMutex);
// TODO: return only the name for the requested arg
TClassRef& cr = type_from_handle(handle);
TFunction* f = type_get_method(handle, idx);
@@ -756,6 +809,8 @@
cppyy_method_t cppyy_get_method(cppyy_scope_t handle, cppyy_index_t idx) {
+ R__LOCKGUARD2(gCINTMutex);
+
TClassRef& cr = type_from_handle(handle);
TFunction* f = type_get_method(handle, idx);
if (cr && cr.GetClass() && !cr->IsLoaded()) {
@@ -780,10 +835,12 @@
}
cppyy_index_t cppyy_get_global_operator(cppyy_scope_t scope, cppyy_scope_t lc, cppyy_scope_t rc, const char* op) {
+ R__LOCKGUARD2(gCINTMutex);
+
TClassRef& lccr = type_from_handle(lc);
TClassRef& rccr = type_from_handle(rc);
- if (!lccr.GetClass() || !rccr.GetClass() || scope != GLOBAL_HANDLE)
+ if (!lccr.GetClass() || !rccr.GetClass() || scope != (cppyy_scope_t)GLOBAL_HANDLE)
return (cppyy_index_t)-1; // (void*)-1 is in kernel space, so invalid as a method handle
std::string lcname = lccr->GetName();
@@ -811,12 +868,14 @@
/* method properties ----------------------------------------------------- */
int cppyy_is_constructor(cppyy_type_t handle, cppyy_index_t idx) {
+ R__LOCKGUARD2(gCINTMutex);
TClassRef& cr = type_from_handle(handle);
TMethod* m = (TMethod*)cr->GetListOfMethods()->At(idx);
return strcmp(m->GetName(), ((G__ClassInfo*)cr->GetClassInfo())->Name()) == 0;
}
int cppyy_is_staticmethod(cppyy_type_t handle, cppyy_index_t idx) {
+ R__LOCKGUARD2(gCINTMutex);
TClassRef& cr = type_from_handle(handle);
TMethod* m = (TMethod*)cr->GetListOfMethods()->At(idx);
return m->Property() & G__BIT_ISSTATIC;
@@ -825,10 +884,12 @@
/* data member reflection information ------------------------------------- */
int cppyy_num_datamembers(cppyy_scope_t handle) {
+ R__LOCKGUARD2(gCINTMutex);
+
TClassRef& cr = type_from_handle(handle);
if (cr.GetClass() && cr->GetListOfDataMembers())
return cr->GetListOfDataMembers()->GetSize();
- else if (strcmp(cr.GetClassName(), "") == 0) {
+ else if (handle == (cppyy_scope_t)GLOBAL_HANDLE) {
TCollection* vars = gROOT->GetListOfGlobals(kTRUE);
if (g_globalvars.size() != (GlobalVars_t::size_type)vars->GetSize()) {
g_globalvars.clear();
@@ -847,16 +908,21 @@
}
char* cppyy_datamember_name(cppyy_scope_t handle, int datamember_index) {
+ R__LOCKGUARD2(gCINTMutex);
+
TClassRef& cr = type_from_handle(handle);
if (cr.GetClass()) {
TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At(datamember_index);
return cppstring_to_cstring(m->GetName());
}
+ assert(handle == (cppyy_type_t)GLOBAL_HANDLE);
TGlobal& gbl = g_globalvars[datamember_index];
return cppstring_to_cstring(gbl.GetName());
}
char* cppyy_datamember_type(cppyy_scope_t handle, int datamember_index) {
+ R__LOCKGUARD2(gCINTMutex);
+
TClassRef& cr = type_from_handle(handle);
if (cr.GetClass()) {
TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At(datamember_index);
@@ -870,21 +936,26 @@
}
return cppstring_to_cstring(fullType);
}
+ assert(handle == (cppyy_type_t)GLOBAL_HANDLE);
TGlobal& gbl = g_globalvars[datamember_index];
return cppstring_to_cstring(gbl.GetFullTypeName());
}
size_t cppyy_datamember_offset(cppyy_scope_t handle, int datamember_index) {
+ R__LOCKGUARD2(gCINTMutex);
TClassRef& cr = type_from_handle(handle);
if (cr.GetClass()) {
TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At(datamember_index);
return (size_t)m->GetOffsetCint();
}
+ assert(handle == (cppyy_type_t)GLOBAL_HANDLE);
TGlobal& gbl = g_globalvars[datamember_index];
return (size_t)gbl.GetAddress();
}
int cppyy_datamember_index(cppyy_scope_t handle, const char* name) {
+ R__LOCKGUARD2(gCINTMutex);
+
TClassRef& cr = type_from_handle(handle);
if (cr.GetClass()) {
// called from updates; add a hard reset as the code itself caches in
@@ -908,32 +979,38 @@
}
++idm;
}
+ } else if (handle == (cppyy_type_t)GLOBAL_HANDLE) {
+ TGlobal* gbl = (TGlobal*)gROOT->GetListOfGlobals(kTRUE)->FindObject(name);
+ if (!gbl)
+ return -1;
+ int idx = g_globalvars.size();
+ g_globalvars.push_back(*gbl);
+ return idx;
}
- TGlobal* gbl = (TGlobal*)gROOT->GetListOfGlobals(kTRUE)->FindObject(name);
- if (!gbl)
- return -1;
- int idx = g_globalvars.size();
- g_globalvars.push_back(*gbl);
- return idx;
+ return -1;
}
/* data member properties ------------------------------------------------ */
int cppyy_is_publicdata(cppyy_scope_t handle, int datamember_index) {
+ R__LOCKGUARD2(gCINTMutex);
TClassRef& cr = type_from_handle(handle);
if (cr.GetClass()) {
TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At(datamember_index);
return m->Property() & G__BIT_ISPUBLIC;
}
+ assert(handle == (cppyy_type_t)GLOBAL_HANDLE);
return 1; // global data is always public
}
int cppyy_is_staticdata(cppyy_scope_t handle, int datamember_index) {
+ R__LOCKGUARD2(gCINTMutex);
TClassRef& cr = type_from_handle(handle);
if (cr.GetClass()) {
TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At(datamember_index);
return m->Property() & G__BIT_ISSTATIC;
}
+ assert(handle == (cppyy_type_t)GLOBAL_HANDLE);
return 1; // global data is always static
}
@@ -959,16 +1036,9 @@
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;
-}
-
void* cppyy_load_dictionary(const char* lib_name) {
+ R__LOCKGUARD2(gCINTMutex);
if (0 <= gSystem->Load(lib_name))
return (void*)1;
return (void*)0;
@@ -976,6 +1046,13 @@
/* pythonization helpers -------------------------------------------------- */
+typedef double (*tfn_callback)(double*, double*);
+
+cppyy_object_t cppyy_create_tf1(const char* funcname, unsigned long address,
+ double xmin, double xmax, int npar) {
+ return (cppyy_object_t)new TF1(funcname, (tfn_callback)address, xmin, xmax, npar);
+}
+
cppyy_object_t cppyy_ttree_Branch(void* vtree, const char* branchname, const char* classname,
void* addobj, int bufsize, int splitlevel) {
// this little song-and-dance is to by-pass the handwritten Branch methods
@@ -987,3 +1064,11 @@
long long cppyy_ttree_GetEntry(void* vtree, long long entry) {
return (long long)((TTree*)vtree)->GetEntry((Long64_t)entry);
}
+
+cppyy_object_t cppyy_charp2TString(const char* str) {
+ return (cppyy_object_t)new TString(str);
+}
+
+cppyy_object_t cppyy_TString2TString(cppyy_object_t ptr) {
+ return (cppyy_object_t)new TString(*(TString*)ptr);
+}
diff --git a/pypy/module/cppyy/src/clingcwrapper.cxx b/pypy/module/cppyy/src/clingcwrapper.cxx
new file mode 100644
--- /dev/null
+++ b/pypy/module/cppyy/src/clingcwrapper.cxx
@@ -0,0 +1,1810 @@
+#include "cppyy.h"
+#include "clingcwrapper.h"
+
+/*************************************************************************
+ * Copyright (C) 1995-2014, the ROOT team. *
+ * LICENSE: LGPLv2.1; see http://root.cern.ch/drupal/content/license *
+ * CONTRIBUTORS: see http://root.cern.ch/drupal/content/contributors *
+ *************************************************************************/
+
+#include <stdint.h>
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclBase.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/PrettyPrinter.h"
+#include "clang/AST/Type.h"
More information about the pypy-commit
mailing list