Author: Wim Lavrijsen <wlavrij...@lbl.gov> 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) +@jit.elidable 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) +@jit.elidable 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) -@jit.elidable_promote('2') +@jit.elidable 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) -@jit.elidable_promote('1,2,4') +@jit.elidable 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 pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit