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

Reply via email to