Author: Wim Lavrijsen <[email protected]>
Branch: cling-support
Changeset: r87095:ff0990bd1f29
Date: 2016-09-13 11:09 -0700
http://bitbucket.org/pypy/pypy/changeset/ff0990bd1f29/
Log: optimization as used in the paper
diff --git a/pypy/module/cppyy/capi/__init__.py
b/pypy/module/cppyy/capi/__init__.py
--- a/pypy/module/cppyy/capi/__init__.py
+++ b/pypy/module/cppyy/capi/__init__.py
@@ -9,8 +9,8 @@
# the selection of the desired backend (default is Reflex).
# choose C-API access method:
-#from pypy.module.cppyy.capi.loadable_capi import *
-from pypy.module.cppyy.capi.builtin_capi import *
+from pypy.module.cppyy.capi.loadable_capi import *
+#from pypy.module.cppyy.capi.builtin_capi import *
from pypy.module.cppyy.capi.capi_types import C_OBJECT,\
C_NULL_TYPE, C_NULL_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,6 @@
[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_function_address(space, cppscope, index):
return _c_get_function_address(cppscope.handle, index)
@@ -215,8 +214,8 @@
[], rffi.SIZE_T,
releasegil=ts_memory,
compilation_info=backend.eci,
- elidable_function=True,
random_effects_on_gcobjs=False)
[email protected]
def c_function_arg_sizeof(space):
return _c_function_arg_sizeof()
_c_function_arg_typeoffset = rffi.llexternal(
@@ -224,8 +223,8 @@
[], rffi.SIZE_T,
releasegil=ts_memory,
compilation_info=backend.eci,
- elidable_function=True,
random_effects_on_gcobjs=False)
[email protected]
def c_function_arg_typeoffset(space):
return _c_function_arg_typeoffset()
@@ -300,9 +299,8 @@
[C_TYPE, C_TYPE], rffi.INT,
releasegil=ts_reflect,
compilation_info=backend.eci,
- elidable_function=True,
random_effects_on_gcobjs=False)
[email protected]_promote('2')
[email protected]
def c_is_subtype(space, derived, base):
if derived == base:
return 1
@@ -313,9 +311,8 @@
[C_TYPE, C_TYPE, C_OBJECT, rffi.INT], rffi.SIZE_T,
releasegil=ts_reflect,
compilation_info=backend.eci,
- elidable_function=True,
random_effects_on_gcobjs=False)
[email protected]_promote('1,2,4')
[email protected]
def c_base_offset(space, derived, base, address, direction):
if derived == base:
return 0
@@ -564,3 +561,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/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,12 +1,16 @@
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, lltype
from rpython.rlib.rarithmetic import intmask
-from rpython.rlib import libffi, rdynload
+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']
@@ -89,6 +93,9 @@
# TODO: factor these out ...
# pythonizations
+
+#
+# std::string behavior
def stdstring_c_str(space, w_self):
"""Return a python string taking into account \0"""
@@ -96,6 +103,60 @@
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):
@@ -106,6 +167,9 @@
### std::string
stdstring_c_str,
+ ### std::vector
+ stdvector_iter,
+
]
for f in allfuncs:
@@ -120,3 +184,13 @@
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
@@ -225,6 +225,10 @@
#stdstring2charp actually takes an size_t* as last parameter, but
this will do
'stdstring2charp' : ([c_object, c_voidp],
c_ccharp),
'stdstring2stdstring' : ([c_object],
c_object),
+
+ 'stdvector_valuetype' : ([c_ccharp],
c_ccharp),
+ 'stdvector_valuesize' : ([c_ccharp],
c_size_t),
+
}
# size/offset are backend-specific but fixed after load
@@ -550,6 +554,14 @@
def c_stdstring2stdstring(space, cppobject):
return _cdata_to_cobject(space, call_capi(space, 'stdstring2stdstring',
[_Arg(h=cppobject)]))
+def c_stdvector_valuetype(space, pystr):
+ return charp2str_free(space, call_capi(space, 'stdvector_valuetype',
[_Arg(s=pystr)]))
+
+def c_stdvector_valuetype(space, pystr):
+ return charp2str_free(space, call_capi(space, 'stdvector_valuetype',
[_Arg(s=pystr)]))
+def c_stdvector_valuesize(space, pystr):
+ return _cdata_to_size_t(space, call_capi(space, 'stdvector_valuesize',
[_Arg(s=pystr)]))
+
# TODO: factor these out ...
# pythonizations
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
@@ -183,6 +183,11 @@
RPY_EXTERN
cppyy_object_t cppyy_stdstring2stdstring(cppyy_object_t ptr);
+ RPY_EXTERN
+ const char* cppyy_stdvector_valuetype(const char* clname);
+ RPY_EXTERN
+ size_t cppyy_stdvector_valuesize(const char* clname);
+
#ifdef __cplusplus
}
#endif // ifdef __cplusplus
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
@@ -197,6 +197,8 @@
@jit.unroll_safe
def call(self, cppthis, args_w):
+ jit.promote(self)
+
assert lltype.typeOf(cppthis) == capi.C_OBJECT
# check number of given arguments against required (== total -
defaults)
@@ -325,8 +327,8 @@
# Each CPPMethod corresponds one-to-one to a C++ equivalent and cppthis
# has been offset to the matching class. Hence, the libffi pointer is
# uniquely defined and needs to be setup only once.
- self._funcaddr = capi.c_get_function_address(self.space, self.scope,
self.index)
- if self._funcaddr and cppthis: # methods only for now
+ funcaddr = capi.c_get_function_address(self.space, self.scope,
self.index)
+ if funcaddr and cppthis: # methods only for now
state = self.space.fromcache(ffitypes.State)
# argument type specification (incl. cppthis)
@@ -353,6 +355,9 @@
self.cif_descr = lltype.nullptr(jit_libffi.CIF_DESCRIPTION)
raise FastCallNotPossible
+ # success ...
+ self._funcaddr = funcaddr
+
@jit.unroll_safe
def prepare_arguments(self, args_w, call_local):
args = capi.c_allocate_function_args(self.space, len(args_w))
@@ -828,6 +833,9 @@
arg_defs.append((arg_type, arg_dflt))
return CPPFunction(self.space, self, index, arg_defs, args_required)
+ def _build_methods(self):
+ pass # force lazy lookups in namespaces
+
def _make_datamember(self, dm_name, dm_idx):
type_name = capi.c_datamember_type(self.space, self, dm_idx)
offset = capi.c_datamember_offset(self.space, self, dm_idx)
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
@@ -311,6 +311,7 @@
else:
return python_style_getitem(self, slice_or_idx)
+
_pythonizations = {}
def _pythonize(pyclass):
@@ -357,8 +358,8 @@
pyclass.__iadd__ = __iadd__
# map begin()/end() protocol to iter protocol on STL(-like) classes, but
- # not on vector, for which otherwise the user has to make sure that the
- # global == and != for its iterators are reflected, which is a hassle ...
+ # not on vector, which is pythonized in the capi (interp-level; there is
+ # also the fallback on the indexed __getitem__, but that is slower)
if not 'vector' in pyclass.__name__[:11] and \
('begin' in pyclass.__dict__ and 'end' in pyclass.__dict__):
if cppyy._scope_byname(pyclass.__name__+'::iterator') or \
diff --git a/pypy/module/cppyy/src/clingcwrapper.cxx
b/pypy/module/cppyy/src/clingcwrapper.cxx
--- a/pypy/module/cppyy/src/clingcwrapper.cxx
+++ b/pypy/module/cppyy/src/clingcwrapper.cxx
@@ -1540,4 +1540,24 @@
return (cppyy_object_t)new std::string(*(std::string*)ptr);
}
+const char* cppyy_stdvector_valuetype(const char* clname) {
+ const char* result = nullptr;
+ std::string name = clname;
+ TypedefInfo_t* ti =
gInterpreter->TypedefInfo_Factory((name+"::value_type").c_str());
+ if (gInterpreter->TypedefInfo_IsValid(ti))
+ result = cppstring_to_cstring(gInterpreter->TypedefInfo_TrueName(ti));
+ gInterpreter->TypedefInfo_Delete(ti);
+ return result;
+}
+
+size_t cppyy_stdvector_valuesize(const char* clname) {
+ size_t result = 0;
+ std::string name = clname;
+ TypedefInfo_t* ti =
gInterpreter->TypedefInfo_Factory((name+"::value_type").c_str());
+ if (gInterpreter->TypedefInfo_IsValid(ti))
+ result = (size_t)gInterpreter->TypedefInfo_Size(ti);
+ gInterpreter->TypedefInfo_Delete(ti);
+ return result;
+}
+
} // end C-linkage wrappers
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit