[pypy-commit] pypy reflex-support: offsets for calling base classes

wlav noreply at buildbot.pypy.org
Fri Jul 1 01:15:55 CEST 2011


Author: Wim Lavrijsen <WLavrijsen at lbl.gov>
Branch: reflex-support
Changeset: r45201:e58b8f224098
Date: 2011-06-30 13:20 -0700
http://bitbucket.org/pypy/pypy/changeset/e58b8f224098/

Log:	offsets for calling base classes

diff --git a/pypy/module/cppyy/capi.py b/pypy/module/cppyy/capi.py
--- a/pypy/module/cppyy/capi.py
+++ b/pypy/module/cppyy/capi.py
@@ -78,6 +78,10 @@
     "cppyy_is_subtype",
     [C_TYPEHANDLE, C_TYPEHANDLE], rffi.INT,
     compilation_info=eci)
+c_base_offset = rffi.llexternal(
+    "cppyy_base_offset",
+    [C_TYPEHANDLE, C_TYPEHANDLE], rffi.SIZE_T,
+    compilation_info=eci)
 
 
 c_call_v = rffi.llexternal(
@@ -168,7 +172,7 @@
     compilation_info=eci)
 c_data_member_offset = rffi.llexternal(
     "cppyy_data_member_offset",
-    [C_TYPEHANDLE, rffi.INT], rffi.INT,
+    [C_TYPEHANDLE, rffi.INT], rffi.SIZE_T,
     compilation_info=eci)
 
 c_is_staticdata = rffi.llexternal(
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
@@ -357,7 +357,10 @@
         obj = space.interpclass_w(w_obj)
         if isinstance(obj, W_CPPInstance):
             if capi.c_is_subtype(obj.cppclass.handle, self.cpptype.handle):
-                return obj.rawobject
+                offset = capi.c_base_offset(obj.cppclass.handle, self.cpptype.handle)
+                obj_address = lltype.direct_ptradd(obj.rawobject, offset)
+                objptr = rffi.cast(rffi.CCHARP, obj_address)
+                return objptr
         raise OperationError(space.w_TypeError,
                              space.wrap("cannot pass %s as %s" % (
                                  space.type(w_obj).getname(space, "?"),
diff --git a/pypy/module/cppyy/include/reflexcwrapper.h b/pypy/module/cppyy/include/reflexcwrapper.h
--- a/pypy/module/cppyy/include/reflexcwrapper.h
+++ b/pypy/module/cppyy/include/reflexcwrapper.h
@@ -36,7 +36,8 @@
     char* cppyy_final_name(cppyy_typehandle_t handle);
     int cppyy_num_bases(cppyy_typehandle_t handle);
     char* cppyy_base_name(cppyy_typehandle_t handle, int base_index);
-    int cppyy_is_subtype(cppyy_typehandle_t h1, cppyy_typehandle_t h2);
+    int cppyy_is_subtype(cppyy_typehandle_t dh, cppyy_typehandle_t bh);
+    size_t cppyy_base_offset(cppyy_typehandle_t dh, cppyy_typehandle_t bh);
 
     /* method/function reflection information */
     int cppyy_num_methods(cppyy_typehandle_t handle);
diff --git a/pypy/module/cppyy/src/reflexcwrapper.cxx b/pypy/module/cppyy/src/reflexcwrapper.cxx
--- a/pypy/module/cppyy/src/reflexcwrapper.cxx
+++ b/pypy/module/cppyy/src/reflexcwrapper.cxx
@@ -21,6 +21,36 @@
     return Reflex::Scope((Reflex::ScopeName*)handle);
 }
 
+static inline size_t base_offset(const Reflex::Type& td, const Reflex::Type& tb) {
+    // when dealing with virtual inheritance the only (reasonably) well-defined info is
+    // in a Reflex internal base table, that contains all offsets within the hierarchy
+    Reflex::Member getbases = td.FunctionMemberByName(
+           "__getBasesTable", Reflex::Type(), 0, Reflex::INHERITEDMEMBERS_NO, Reflex::DELAYEDLOAD_OFF);
+    if (getbases) {
+        typedef std::vector<std::pair<Reflex::Base, int> > Bases_t;
+        Bases_t* bases;
+        Reflex::Object bases_holder(Reflex::Type::ByTypeInfo(typeid(Bases_t)), &bases);
+        getbases.Invoke(&bases_holder);
+
+        for (Bases_t::iterator ibase = bases->begin(); ibase != bases->end(); ++ibase) {
+            if (ibase->first.ToType() == tb) {
+                if (ibase->first.IsVirtual()) {
+                    Reflex::Object o = td.Construct();
+                    size_t offset = ibase->first.Offset(o.Address());
+                    o.Destruct();
+                    return offset;
+                } else
+                   return ibase->first.Offset(0);
+            }
+        }
+
+        // contrary to typical invoke()s, the result of the internal getbases function
+        // is a pointer to a function static, so no delete
+    }
+
+    return 0;
+}
+
 
 /* name to handle --------------------------------------------------------- */
 cppyy_typehandle_t cppyy_get_typehandle(const char* class_name) {
@@ -171,12 +201,20 @@
     return cppstring_to_cstring(name);
 }
 
-int cppyy_is_subtype(cppyy_typehandle_t h1, cppyy_typehandle_t h2) {
-    if (h1 == h2)
+int cppyy_is_subtype(cppyy_typehandle_t dh, cppyy_typehandle_t bh) {
+    if (dh == bh)
         return 1;
-    Reflex::Type t1 = type_from_handle(h1);
-    Reflex::Type t2 = type_from_handle(h2);
-    return (int)t2.HasBase(t1);
+    Reflex::Type td = type_from_handle(dh);
+    Reflex::Type tb = type_from_handle(bh);
+    return (int)td.HasBase(tb);
+}
+
+size_t cppyy_base_offset(cppyy_typehandle_t dh, cppyy_typehandle_t bh) {
+    if (dh == bh)
+        return 0;
+    Reflex::Type td = type_from_handle(dh);
+    Reflex::Type tb = type_from_handle(bh);
+    return base_offset(td, tb);
 }
 
 
@@ -265,34 +303,8 @@
 
     if (s != m.DeclaringScope()) {
         // in case this data member is part of a base class, the offset is complicated
-        // when dealing with virtual inheritance and only (reasonably) well-defined with a
-        // Reflex internal base table, that contains all offsets within the full hierarchy
-        Reflex::Member getbases = s.FunctionMemberByName(
-            "__getBasesTable", Reflex::Type(), 0, Reflex::INHERITEDMEMBERS_NO, Reflex::DELAYEDLOAD_OFF);
-        if (getbases) {
-            typedef std::vector<std::pair<Reflex::Base, int> > Bases_t;
-            Bases_t* bases;
-            Reflex::Object bases_holder(Reflex::Type::ByTypeInfo(typeid(Bases_t)), &bases);
-            getbases.Invoke(&bases_holder);
-
-            Reflex::Type d = m.DeclaringType();
-
-            for (Bases_t::iterator ibase = bases->begin(); ibase != bases->end(); ++ibase) {
-                if (ibase->first.ToType() == d) {
-                    if (d.IsVirtual()) {
-                        Reflex::Type t = type_from_handle(handle);
-                        Reflex::Object o = t.Construct();
-                        size_t offset = ibase->first.Offset(o.Address()) + m.Offset();
-                        o.Destruct();
-                        return offset;
-                    } else
-                        return ibase->first.Offset(0);
-                }
-            }
-
-            // contrary to typical invoke()s, the result of the internal getbases function
-            // is a pointer to a function static, so no delete
-        }
+        // when dealing with virtual inheritance and needs to be calculated
+        return base_offset(s, m.DeclaringType()) + m.Offset();
     }
 
     return m.Offset();
diff --git a/pypy/module/cppyy/test/advancedcpp.xml b/pypy/module/cppyy/test/advancedcpp.xml
--- a/pypy/module/cppyy/test/advancedcpp.xml
+++ b/pypy/module/cppyy/test/advancedcpp.xml
@@ -12,6 +12,8 @@
   <class name="c_class_2" />
   <class name="d_class" />
 
+  <function pattern="get_*" />
+
   <class pattern="T1<*>" />
   <class pattern="T2<*>" />
   <class pattern="T3<*>" />
diff --git a/pypy/module/cppyy/test/test_advancedcpp.py b/pypy/module/cppyy/test/test_advancedcpp.py
--- a/pypy/module/cppyy/test/test_advancedcpp.py
+++ b/pypy/module/cppyy/test/test_advancedcpp.py
@@ -23,7 +23,7 @@
             import cppyy
             return cppyy.load_lib(%r)""" % (shared_lib, ))
 
-    def test01_default_argeumetns(self):
+    def test01_default_arguments(self):
         """Test usage of default arguments"""
 
         import cppyy
@@ -277,3 +277,36 @@
       # assert d.get_value()  == 44
 
         d.destruct()
+
+    def test07_pass_by_reference(self):
+        """Test reference passing when using virtual inheritance"""
+
+        import cppyy
+        gbl = cppyy.gbl
+        b_class = gbl.b_class
+        c_class = gbl.c_class_2
+        d_class = gbl.d_class
+
+        #-----
+        b = b_class()
+        b.m_a, b.m_b = 11, 22
+        assert gbl.get_a(b) == 11
+        assert gbl.get_b(b) == 22
+        b.destruct()
+
+        #-----
+        c = c_class()
+        c.m_a, c.m_b, c.m_c = 11, 22, 33
+        assert gbl.get_a(c) == 11
+        assert gbl.get_b(c) == 22
+        assert gbl.get_c(c) == 33
+        c.destruct()
+
+        #-----
+        d = d_class()
+        d.m_a, d.m_b, d.m_c, d.m_d = 11, 22, 33, 44
+        assert gbl.get_a(d) == 11
+        assert gbl.get_b(d) == 22
+        assert gbl.get_c(d) == 33
+        assert gbl.get_d(d) == 44
+        d.destruct()


More information about the pypy-commit mailing list