[pypy-commit] pypy cffi-1.0: ffi.addressof(lib, "var")

arigo noreply at buildbot.pypy.org
Mon May 11 15:55:57 CEST 2015


Author: Armin Rigo <arigo at tunes.org>
Branch: cffi-1.0
Changeset: r77293:abb305ea8684
Date: 2015-05-11 15:55 +0200
http://bitbucket.org/pypy/pypy/changeset/abb305ea8684/

Log:	ffi.addressof(lib, "var")

diff --git a/pypy/module/_cffi_backend/cglob.py b/pypy/module/_cffi_backend/cglob.py
--- a/pypy/module/_cffi_backend/cglob.py
+++ b/pypy/module/_cffi_backend/cglob.py
@@ -1,6 +1,7 @@
 from pypy.interpreter.baseobjspace import W_Root
 from pypy.interpreter.typedef import TypeDef
 from pypy.module._cffi_backend.cdataobj import W_CData
+from pypy.module._cffi_backend import newtype
 
 
 class W_GlobSupport(W_Root):
@@ -15,5 +16,9 @@
     def write_global_var(self, w_newvalue):
         self.w_ctype.convert_from_object(self.ptr, w_newvalue)
 
+    def address(self):
+        w_ctypeptr = newtype.new_pointer_type(self.space, self.w_ctype)
+        return W_CData(self.space, self.ptr, w_ctypeptr)
+
 W_GlobSupport.typedef = TypeDef("FFIGlobSupport")
 W_GlobSupport.typedef.acceptable_as_base_class = False
diff --git a/pypy/module/_cffi_backend/ffi_obj.py b/pypy/module/_cffi_backend/ffi_obj.py
--- a/pypy/module/_cffi_backend/ffi_obj.py
+++ b/pypy/module/_cffi_backend/ffi_obj.py
@@ -145,20 +145,34 @@
 
     def descr_addressof(self, w_arg, args_w):
         """\
-With a single arg, return the address of a <cdata 'struct-or-union'>.
-If 'fields_or_indexes' are given, returns the address of that field or
-array item in the structure or array, recursively in case of nested
-structures."""
+Limited equivalent to the '&' operator in C:
+
+1. ffi.addressof(<cdata 'struct-or-union'>) returns a cdata that is a
+pointer to this struct or union.
+
+2. ffi.addressof(<cdata>, field-or-index...) returns the address of a
+field or array item inside the given structure or array, recursively
+in case of nested structures or arrays.
+
+3. ffi.addressof(<library>, "name") returns the address of the named
+global variable."""
+        #
+        from pypy.module._cffi_backend.lib_obj import W_LibObject
+        space = self.space
+        if isinstance(w_arg, W_LibObject) and len(args_w) == 1:
+            # case 3 in the docstring
+            return w_arg.address_of_global_var(space.str_w(args_w[0]))
         #
         w_ctype = self.ffi_type(w_arg, ACCEPT_CDATA)
-        space = self.space
         if len(args_w) == 0:
+            # case 1 in the docstring
             if (not isinstance(w_ctype, ctypestruct.W_CTypeStructOrUnion) and
                 not isinstance(w_ctype, ctypearray.W_CTypeArray)):
                 raise oefmt(space.w_TypeError,
                             "expected a cdata struct/union/array object")
             offset = 0
         else:
+            # case 2 in the docstring
             if (not isinstance(w_ctype, ctypestruct.W_CTypeStructOrUnion) and
                 not isinstance(w_ctype, ctypearray.W_CTypeArray) and
                 not isinstance(w_ctype, ctypeptr.W_CTypePointer)):
diff --git a/pypy/module/_cffi_backend/lib_obj.py b/pypy/module/_cffi_backend/lib_obj.py
--- a/pypy/module/_cffi_backend/lib_obj.py
+++ b/pypy/module/_cffi_backend/lib_obj.py
@@ -10,6 +10,7 @@
 from pypy.module._cffi_backend import cffi_opcode, cglob
 from pypy.module._cffi_backend.realize_c_type import getop, getarg
 from pypy.module._cffi_backend.cdataobj import W_CData
+from pypy.module._cffi_backend.ctypefunc import W_CTypeFunc
 from pypy.module._cffi_backend.structwrapper import W_StructWrapper
 
 
@@ -173,6 +174,24 @@
                    for i in range(total)]
         return space.newlist(names_w)
 
+    def address_of_global_var(self, varname):
+        # rebuild a string object from 'varname', to do typechecks and
+        # to force a unicode back to a plain string
+        space = self.space
+        w_value = self._get_attr(space.wrap(varname))
+        if isinstance(w_value, cglob.W_GlobSupport):
+            # regular case: a global variable
+            return w_value.address()
+        #
+        if ((isinstance(w_value, W_CData) and
+                isinstance(w_value.ctype, W_CTypeFunc))
+            or isinstance(w_value, W_StructWrapper)):
+            # '&func' is 'func' in C, for a constant function 'func'
+            return w_value
+        #
+        raise oefmt(space.w_AttributeError,
+                    "cannot take the address of the constant '%s'", varname)
+
 
 W_LibObject.typedef = TypeDef(
         'CompiledLib',
diff --git a/pypy/module/_cffi_backend/test/test_recompiler.py b/pypy/module/_cffi_backend/test/test_recompiler.py
--- a/pypy/module/_cffi_backend/test/test_recompiler.py
+++ b/pypy/module/_cffi_backend/test/test_recompiler.py
@@ -695,3 +695,37 @@
         assert repr(ffi.typeof("foo_t")) == "<ctype 'foo_t'>"
         assert repr(ffi.typeof("bar_p")) == "<ctype 'struct $1 *'>"
         assert repr(ffi.typeof("baz_pp")) == "<ctype 'struct $2 * *'>"
+
+    def test_address_of_global_var(self):
+        ffi, lib = self.prepare("""
+            long bottom, bottoms[2];
+            long FetchRectBottom(void);
+            long FetchRectBottoms1(void);
+            #define FOOBAR 42
+        """, "test_address_of_global_var", """
+            long bottom, bottoms[2];
+            long FetchRectBottom(void) { return bottom; }
+            long FetchRectBottoms1(void) { return bottoms[1]; }
+            #define FOOBAR 42
+        """)
+        lib.bottom = 300
+        assert lib.FetchRectBottom() == 300
+        lib.bottom += 1
+        assert lib.FetchRectBottom() == 301
+        lib.bottoms[1] = 500
+        assert lib.FetchRectBottoms1() == 500
+        lib.bottoms[1] += 2
+        assert lib.FetchRectBottoms1() == 502
+        #
+        p = ffi.addressof(lib, 'bottom')
+        assert ffi.typeof(p) == ffi.typeof("long *")
+        assert p[0] == 301
+        p[0] += 1
+        assert lib.FetchRectBottom() == 302
+        p = ffi.addressof(lib, 'bottoms')
+        assert ffi.typeof(p) == ffi.typeof("long(*)[2]")
+        assert p[0] == lib.bottoms
+        #
+        raises(AttributeError, ffi.addressof, lib, 'unknown_var')
+        raises(AttributeError, ffi.addressof, lib, "FOOBAR")
+        assert ffi.addressof(lib, 'FetchRectBottom') == lib.FetchRectBottom


More information about the pypy-commit mailing list