[pypy-commit] pypy cffi-1.0: ffi.new_handle(), ffi.from_handle()

arigo noreply at buildbot.pypy.org
Sun May 3 11:16:43 CEST 2015


Author: Armin Rigo <arigo at tunes.org>
Branch: cffi-1.0
Changeset: r77000:b7ff7697276d
Date: 2015-05-03 11:16 +0200
http://bitbucket.org/pypy/pypy/changeset/b7ff7697276d/

Log:	ffi.new_handle(), ffi.from_handle()

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
@@ -7,7 +7,7 @@
 
 from pypy.module._cffi_backend import parse_c_type, realize_c_type
 from pypy.module._cffi_backend import newtype, cerrno, ccallback, ctypearray
-from pypy.module._cffi_backend import ctypestruct, ctypeptr
+from pypy.module._cffi_backend import ctypestruct, ctypeptr, handle
 from pypy.module._cffi_backend.ctypeobj import W_CType
 from pypy.module._cffi_backend.cdataobj import W_CData
 
@@ -154,6 +154,17 @@
                     _cffi_backend.callback(ctype, python_callable, error))""")
 
 
+    @unwrap_spec(w_arg=W_CData)
+    def descr_from_handle(self, w_arg):
+        """\
+Cast a 'void *' back to a Python object.  Must be used *only* on the
+pointers returned by new_handle(), and *only* as long as the exact
+cdata object returned by new_handle() is still alive (somewhere else
+in the program).  Failure to follow these rules will crash."""
+        #
+        return handle.from_handle(self.space, w_arg)
+
+
     @unwrap_spec(replace_with=str)
     def descr_getctype(self, w_cdecl, replace_with=''):
         """\
@@ -211,6 +222,17 @@
         return w_ctype.newp(w_init)
 
 
+    def descr_new_handle(self, w_arg):
+        """\
+Return a non-NULL cdata of type 'void *' that contains an opaque
+reference to the argument, which can be any Python object.  To cast it
+back to the original object, use from_handle().  You must keep alive
+the cdata object returned by new_handle()!"""
+        #
+        space = self.space
+        return handle._newp_handle(space, newtype.new_voidp_type(space), w_arg)
+
+
     @unwrap_spec(w_cdata=W_CData, maxlen=int)
     def descr_string(self, w_cdata, maxlen=-1):
         """\
@@ -273,15 +295,17 @@
         addressof   = interp2app(W_FFIObject.descr_addressof),
         alignof     = interp2app(W_FFIObject.descr_alignof),
         callback    = interp2app(W_FFIObject.descr_callback),
+        from_handle = interp2app(W_FFIObject.descr_from_handle),
         getctype    = interp2app(W_FFIObject.descr_getctype),
         new         = interp2app(W_FFIObject.descr_new),
+        new_handle  = interp2app(W_FFIObject.descr_new_handle),
         sizeof      = interp2app(W_FFIObject.descr_sizeof),
         string      = interp2app(W_FFIObject.descr_string),
         typeof      = interp2app(W_FFIObject.descr_typeof),
         )
 
 def _startup(space):
-    ctvoidp = newtype.new_pointer_type(space, newtype.new_void_type(space))
+    ctvoidp = newtype.new_voidp_type(space)
     w_NULL = ctvoidp.cast(space.wrap(0))
     w_ffitype = space.gettypefor(W_FFIObject)
     w_ffitype.dict_w['NULL'] = w_NULL
diff --git a/pypy/module/_cffi_backend/handle.py b/pypy/module/_cffi_backend/handle.py
--- a/pypy/module/_cffi_backend/handle.py
+++ b/pypy/module/_cffi_backend/handle.py
@@ -14,17 +14,20 @@
 
 # ____________________________________________________________
 
+def _newp_handle(space, w_ctype, w_x):
+    index = get(space).reserve_next_handle_index()
+    _cdata = rffi.cast(rffi.CCHARP, index + 1)
+    new_cdataobj = cdataobj.W_CDataHandle(space, _cdata, w_ctype, w_x)
+    get(space).store_handle(index, new_cdataobj)
+    return new_cdataobj
+
 @unwrap_spec(w_ctype=ctypeobj.W_CType)
 def newp_handle(space, w_ctype, w_x):
     if (not isinstance(w_ctype, ctypeptr.W_CTypePointer) or
         not w_ctype.is_void_ptr):
         raise oefmt(space.w_TypeError,
                     "needs 'void *', got '%s'", w_ctype.name)
-    index = get(space).reserve_next_handle_index()
-    _cdata = rffi.cast(rffi.CCHARP, index + 1)
-    new_cdataobj = cdataobj.W_CDataHandle(space, _cdata, w_ctype, w_x)
-    get(space).store_handle(index, new_cdataobj)
-    return new_cdataobj
+    return _newp_handle(space, w_ctype, w_x)
 
 @unwrap_spec(w_cdata=cdataobj.W_CData)
 def from_handle(space, w_cdata):
diff --git a/pypy/module/_cffi_backend/newtype.py b/pypy/module/_cffi_backend/newtype.py
--- a/pypy/module/_cffi_backend/newtype.py
+++ b/pypy/module/_cffi_backend/newtype.py
@@ -4,6 +4,7 @@
 
 from rpython.rlib.objectmodel import specialize, r_dict, compute_identity_hash
 from rpython.rlib.rarithmetic import ovfcheck, intmask
+from rpython.rlib import jit
 from rpython.rtyper.lltypesystem import lltype, rffi
 from rpython.rtyper.tool import rffi_platform
 
@@ -23,6 +24,7 @@
 class UniqueCache:
     def __init__(self, space):
         self.ctvoid = None      # There can be only one
+        self.ctvoidp = None     # Cache for self.pointers[self.ctvoid]
         self.primitives = {}    # Keys: name
         self.pointers = {}      # Keys: base_ctype
         self.arrays = {}        # Keys: (ptr_ctype, length_or_-1)
@@ -137,6 +139,7 @@
     eptypesize("int_fast64_t",  8, _WCTSigned)
     eptypesize("uint_fast64_t", 8, _WCTUnsign)
 
+ at jit.elidable
 @unwrap_spec(name=str)
 def new_primitive_type(space, name):
     unique_cache = space.fromcache(UniqueCache)
@@ -154,6 +157,7 @@
 
 # ____________________________________________________________
 
+ at jit.elidable
 @unwrap_spec(w_ctype=ctypeobj.W_CType)
 def new_pointer_type(space, w_ctype):
     unique_cache = space.fromcache(UniqueCache)
@@ -167,6 +171,7 @@
 
 # ____________________________________________________________
 
+ at jit.elidable
 @unwrap_spec(w_ctptr=ctypeobj.W_CType)
 def new_array_type(space, w_ctptr, w_length):
     if space.is_w(w_length, space.w_None):
@@ -178,6 +183,7 @@
                                  space.wrap("negative array length"))
     return _new_array_type(space, w_ctptr, length)
 
+ at jit.elidable
 def _new_array_type(space, w_ctptr, length):
     unique_cache = space.fromcache(UniqueCache)
     unique_key = (w_ctptr, length)
@@ -493,12 +499,20 @@
 
 # ____________________________________________________________
 
+ at jit.elidable
 def new_void_type(space):
     unique_cache = space.fromcache(UniqueCache)
     if unique_cache.ctvoid is None:
         unique_cache.ctvoid = ctypevoid.W_CTypeVoid(space)
     return unique_cache.ctvoid
 
+ at jit.elidable
+def new_voidp_type(space):
+    unique_cache = space.fromcache(UniqueCache)
+    if unique_cache.ctvoidp is None:
+        unique_cache.ctvoidp = new_pointer_type(space, new_void_type(space))
+    return unique_cache.ctvoidp
+
 # ____________________________________________________________
 
 @unwrap_spec(name=str, w_basectype=ctypeobj.W_CType)
@@ -537,6 +551,7 @@
 
 # ____________________________________________________________
 
+ at jit.elidable
 @unwrap_spec(w_fresult=ctypeobj.W_CType, ellipsis=int)
 def new_function_type(space, w_fargs, w_fresult, ellipsis=0):
     fargs = []
@@ -549,6 +564,7 @@
         fargs.append(w_farg)
     return _new_function_type(space, fargs, w_fresult, bool(ellipsis))
 
+ at jit.elidable
 def _new_function_type(space, fargs, w_fresult, ellipsis=False):
     from pypy.module._cffi_backend import ctypefunc
     #
diff --git a/pypy/module/_cffi_backend/realize_c_type.py b/pypy/module/_cffi_backend/realize_c_type.py
--- a/pypy/module/_cffi_backend/realize_c_type.py
+++ b/pypy/module/_cffi_backend/realize_c_type.py
@@ -71,7 +71,7 @@
     w_ctype = realize_cache.all_primitives[num]
     if w_ctype is None:
         if num == cffi_opcode.PRIM_VOID:
-            w_ctype = newtype.new_void_type()
+            w_ctype = newtype.new_void_type(space)
         elif 0 <= num < len(RealizeCache.NAMES) and RealizeCache.NAMES[num]:
             w_ctype = newtype.new_primitive_type(space, RealizeCache.NAMES[num])
         else:


More information about the pypy-commit mailing list