[pypy-commit] pypy default: Kill most of the fragile keepalive_until_here() logic. Replace it with a

arigo noreply at buildbot.pypy.org
Wed Mar 4 15:32:43 CET 2015


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r76242:1a44b21df005
Date: 2015-03-04 15:32 +0100
http://bitbucket.org/pypy/pypy/changeset/1a44b21df005/

Log:	Kill most of the fragile keepalive_until_here() logic. Replace it
	with a context manager API, declared on the W_CData objects
	themselves.

diff --git a/pypy/module/_cffi_backend/cbuffer.py b/pypy/module/_cffi_backend/cbuffer.py
--- a/pypy/module/_cffi_backend/cbuffer.py
+++ b/pypy/module/_cffi_backend/cbuffer.py
@@ -81,4 +81,5 @@
     if size < 0:
         raise oefmt(space.w_TypeError,
                     "don't know the size pointed to by '%s'", ctype.name)
-    return space.wrap(MiniBuffer(LLBuffer(w_cdata._cdata, size), w_cdata))
+    ptr = w_cdata.unsafe_escaping_ptr()    # w_cdata kept alive by MiniBuffer()
+    return space.wrap(MiniBuffer(LLBuffer(ptr, size), w_cdata))
diff --git a/pypy/module/_cffi_backend/ccallback.py b/pypy/module/_cffi_backend/ccallback.py
--- a/pypy/module/_cffi_backend/ccallback.py
+++ b/pypy/module/_cffi_backend/ccallback.py
@@ -48,9 +48,12 @@
             raise oefmt(space.w_NotImplementedError,
                         "%s: callback with unsupported argument or "
                         "return type or with '...'", self.getfunctype().name)
-        res = clibffi.c_ffi_prep_closure(self.get_closure(), cif_descr.cif,
-                                         invoke_callback,
-                                         rffi.cast(rffi.VOIDP, self.unique_id))
+        with self as ptr:
+            closure_ptr = rffi.cast(clibffi.FFI_CLOSUREP, ptr)
+            unique_id = rffi.cast(rffi.VOIDP, self.unique_id)
+            res = clibffi.c_ffi_prep_closure(closure_ptr, cif_descr.cif,
+                                             invoke_callback,
+                                             unique_id)
         if rffi.cast(lltype.Signed, res) != clibffi.FFI_OK:
             raise OperationError(space.w_SystemError,
                 space.wrap("libffi failed to build this callback"))
@@ -62,12 +65,9 @@
             from pypy.module.thread.os_thread import setup_threads
             setup_threads(space)
 
-    def get_closure(self):
-        return rffi.cast(clibffi.FFI_CLOSUREP, self._cdata)
-
     #@rgc.must_be_light_finalizer
     def __del__(self):
-        clibffi.closureHeap.free(self.get_closure())
+        clibffi.closureHeap.free(rffi.cast(clibffi.FFI_CLOSUREP, self._ptr))
         if self.ll_error:
             lltype.free(self.ll_error, flavor='raw')
 
@@ -106,7 +106,7 @@
         fresult = self.getfunctype().ctitem
         if fresult.size > 0:
             misc._raw_memcopy(self.ll_error, ll_res, fresult.size)
-            keepalive_until_here(self)
+            keepalive_until_here(self)     # to keep self.ll_error alive
 
 
 global_callback_mapping = rweakref.RWeakValueDictionary(int, W_CDataCallback)
diff --git a/pypy/module/_cffi_backend/cdataobj.py b/pypy/module/_cffi_backend/cdataobj.py
--- a/pypy/module/_cffi_backend/cdataobj.py
+++ b/pypy/module/_cffi_backend/cdataobj.py
@@ -14,21 +14,37 @@
 
 
 class W_CData(W_Root):
-    _attrs_ = ['space', '_cdata', 'ctype', '_lifeline_']
-    _immutable_fields_ = ['_cdata', 'ctype']
-    _cdata = lltype.nullptr(rffi.CCHARP.TO)
+    _attrs_ = ['space', '_ptr', 'ctype', '_lifeline_']
+    _immutable_fields_ = ['_ptr', 'ctype']
+    _ptr = lltype.nullptr(rffi.CCHARP.TO)
 
-    def __init__(self, space, cdata, ctype):
+    def __init__(self, space, ptr, ctype):
         from pypy.module._cffi_backend import ctypeobj
-        assert lltype.typeOf(cdata) == rffi.CCHARP
+        assert lltype.typeOf(ptr) == rffi.CCHARP
         assert isinstance(ctype, ctypeobj.W_CType)
         self.space = space
-        self._cdata = cdata    # don't forget keepalive_until_here!
+        self._ptr = ptr    # don't access directly!  use "with cdata as ptr:"
         self.ctype = ctype
 
+    def __enter__(self):
+        """Use 'with cdata as ptr:' to access the raw memory.  It will
+        stay alive at least until the end of the 'with' block.
+        """
+        return self._ptr
+
+    def __exit__(self, *args):
+        keepalive_until_here(self)
+
+    def unsafe_escaping_ptr(self):
+        """Generally unsafe: escape the pointer to raw memory.
+        If 'self' is a subclass that frees the pointer in a destructor,
+        it may be freed under your feet at any time.
+        """
+        return self._ptr
+
     def _repr_extra(self):
-        extra = self.ctype.extra_repr(self._cdata)
-        keepalive_until_here(self)
+        with self as ptr:
+            extra = self.ctype.extra_repr(ptr)
         return extra
 
     def _repr_extra_owning(self):
@@ -54,11 +70,13 @@
             self.ctype.name, extra1, extra2))
 
     def nonzero(self):
-        return self.space.wrap(bool(self._cdata))
+        with self as ptr:
+            nonzero = bool(ptr)
+        return self.space.wrap(nonzero)
 
     def int(self, space):
-        w_result = self.ctype.cast_to_int(self._cdata)
-        keepalive_until_here(self)
+        with self as ptr:
+            w_result = self.ctype.cast_to_int(ptr)
         return w_result
 
     def long(self, space):
@@ -69,8 +87,8 @@
         return w_result
 
     def float(self):
-        w_result = self.ctype.float(self._cdata)
-        keepalive_until_here(self)
+        with self as ptr:
+            w_result = self.ctype.float(ptr)
         return w_result
 
     def len(self):
@@ -88,20 +106,19 @@
         def _cmp(self, w_other):
             from pypy.module._cffi_backend.ctypeprim import W_CTypePrimitive
             space = self.space
-            cdata1 = self._cdata
-            if isinstance(w_other, W_CData):
-                cdata2 = w_other._cdata
-            else:
+            if not isinstance(w_other, W_CData):
                 return space.w_NotImplemented
 
-            if requires_ordering:
-                if (isinstance(self.ctype, W_CTypePrimitive) or
-                    isinstance(w_other.ctype, W_CTypePrimitive)):
-                    raise OperationError(space.w_TypeError,
-                       space.wrap("cannot do comparison on a primitive cdata"))
-                cdata1 = rffi.cast(lltype.Unsigned, cdata1)
-                cdata2 = rffi.cast(lltype.Unsigned, cdata2)
-            return space.newbool(op(cdata1, cdata2))
+            with self as ptr1, w_other as ptr2:
+                if requires_ordering:
+                    if (isinstance(self.ctype, W_CTypePrimitive) or
+                        isinstance(w_other.ctype, W_CTypePrimitive)):
+                        raise OperationError(space.w_TypeError, space.wrap(
+                            "cannot do comparison on a primitive cdata"))
+                    ptr1 = rffi.cast(lltype.Unsigned, ptr1)
+                    ptr2 = rffi.cast(lltype.Unsigned, ptr2)
+                result = op(ptr1, ptr2)
+            return space.newbool(result)
         #
         return func_with_new_name(_cmp, name)
 
@@ -113,7 +130,8 @@
     ge = _make_comparison('ge')
 
     def hash(self):
-        h = rffi.cast(lltype.Signed, self._cdata)
+        ptr = self.unsafe_escaping_ptr()
+        h = rffi.cast(lltype.Signed, ptr)
         # To hash pointers in dictionaries.  Assumes that h shows some
         # alignment (to 4, 8, maybe 16 bytes), so we use the following
         # formula to avoid the trailing bits being always 0.
@@ -128,26 +146,27 @@
             i = space.getindex_w(w_index, space.w_IndexError)
             ctype = self.ctype._check_subscript_index(self, i)
             w_o = self._do_getitem(ctype, i)
-        keepalive_until_here(self)
         return w_o
 
     def _do_getitem(self, ctype, i):
         ctitem = ctype.ctitem
-        return ctitem.convert_to_object(
-            rffi.ptradd(self._cdata, i * ctitem.size))
+        with self as ptr:
+            return ctitem.convert_to_object(
+                rffi.ptradd(ptr, i * ctitem.size))
 
     def setitem(self, w_index, w_value):
         space = self.space
         if space.isinstance_w(w_index, space.w_slice):
-            self._do_setslice(w_index, w_value)
+            with self as ptr:
+                self._do_setslice(w_index, w_value, ptr)
         else:
             i = space.getindex_w(w_index, space.w_IndexError)
             ctype = self.ctype._check_subscript_index(self, i)
             ctitem = ctype.ctitem
-            ctitem.convert_from_object(
-                rffi.ptradd(self._cdata, i * ctitem.size),
-                w_value)
-        keepalive_until_here(self)
+            with self as ptr:
+                ctitem.convert_from_object(
+                    rffi.ptradd(ptr, i * ctitem.size),
+                    w_value)
 
     def _do_getslicearg(self, w_slice):
         from pypy.module._cffi_backend.ctypeptr import W_CTypePointer
@@ -188,14 +207,15 @@
             ctarray = newtype.new_array_type(space, ctptr, space.w_None)
             ctptr.cache_array_type = ctarray
         #
-        p = rffi.ptradd(self._cdata, start * ctarray.ctitem.size)
-        return W_CDataSliced(space, p, ctarray, length)
+        ptr = self.unsafe_escaping_ptr()
+        ptr = rffi.ptradd(ptr, start * ctarray.ctitem.size)
+        return W_CDataSliced(space, ptr, ctarray, length)
 
-    def _do_setslice(self, w_slice, w_value):
+    def _do_setslice(self, w_slice, w_value, ptr):
         ctptr, start, length = self._do_getslicearg(w_slice)
         ctitem = ctptr.ctitem
         ctitemsize = ctitem.size
-        cdata = rffi.ptradd(self._cdata, start * ctitemsize)
+        target = rffi.ptradd(ptr, start * ctitemsize)
         #
         if isinstance(w_value, W_CData):
             from pypy.module._cffi_backend import ctypearray
@@ -204,9 +224,8 @@
                 ctv.ctitem is ctitem and
                 w_value.get_array_length() == length):
                 # fast path: copying from exactly the correct type
-                s = w_value._cdata
-                rffi.c_memcpy(cdata, s, ctitemsize * length)
-                keepalive_until_here(w_value)
+                with w_value as source:
+                    rffi.c_memcpy(target, source, ctitemsize * length)
                 return
         #
         # A fast path for <char[]>[0:N] = "somestring".
@@ -221,7 +240,7 @@
                 raise oefmt(space.w_ValueError,
                             "need a string of length %d, got %d",
                             length, len(value))
-            copy_string_to_raw(llstr(value), cdata, 0, length)
+            copy_string_to_raw(llstr(value), target, 0, length)
             return
         #
         w_iter = space.iter(w_value)
@@ -233,8 +252,8 @@
                     raise
                 raise oefmt(space.w_ValueError,
                             "need %d values to unpack, got %d", length, i)
-            ctitem.convert_from_object(cdata, w_item)
-            cdata = rffi.ptradd(cdata, ctitemsize)
+            ctitem.convert_from_object(target, w_item)
+            target = rffi.ptradd(target, ctitemsize)
         try:
             space.next(w_iter)
         except OperationError, e:
@@ -247,7 +266,8 @@
     def _add_or_sub(self, w_other, sign):
         space = self.space
         i = sign * space.getindex_w(w_other, space.w_OverflowError)
-        return self.ctype.add(self._cdata, i)
+        ptr = self.unsafe_escaping_ptr()
+        return self.ctype.add(ptr, i)
 
     def add(self, w_other):
         return self._add_or_sub(w_other, +1)
@@ -268,9 +288,11 @@
                             self.ctype.name, ct.name)
             #
             itemsize = ct.ctitem.size
-            if itemsize <= 0: itemsize = 1
-            diff = (rffi.cast(lltype.Signed, self._cdata) -
-                    rffi.cast(lltype.Signed, w_other._cdata)) // itemsize
+            if itemsize <= 0:
+                itemsize = 1
+            with self as ptr1, w_other as ptr2:
+                diff = (rffi.cast(lltype.Signed, ptr1) -
+                        rffi.cast(lltype.Signed, ptr2)) // itemsize
             return space.wrap(diff)
         #
         return self._add_or_sub(w_other, -1)
@@ -279,17 +301,19 @@
         return self.ctype.getcfield(self.space.str_w(w_attr))
 
     def getattr(self, w_attr):
-        w_res = self.getcfield(w_attr).read(self._cdata)
-        keepalive_until_here(self)
+        cfield = self.getcfield(w_attr)
+        with self as ptr:
+            w_res = cfield.read(ptr)
         return w_res
 
     def setattr(self, w_attr, w_value):
-        self.getcfield(w_attr).write(self._cdata, w_value)
-        keepalive_until_here(self)
+        cfield = self.getcfield(w_attr)
+        with self as ptr:
+            cfield.write(ptr, w_value)
 
     def call(self, args_w):
-        w_result = self.ctype.call(self._cdata, args_w)
-        keepalive_until_here(self)
+        with self as ptr:
+            w_result = self.ctype.call(ptr, args_w)
         return w_result
 
     def iter(self):
@@ -311,21 +335,21 @@
 
     @specialize.argtype(1)
     def write_raw_signed_data(self, source):
-        misc.write_raw_signed_data(self._cdata, source, self.ctype.size)
-        keepalive_until_here(self)
+        with self as ptr:
+            misc.write_raw_signed_data(ptr, source, self.ctype.size)
 
     @specialize.argtype(1)
     def write_raw_unsigned_data(self, source):
-        misc.write_raw_unsigned_data(self._cdata, source, self.ctype.size)
-        keepalive_until_here(self)
+        with self as ptr:
+            misc.write_raw_unsigned_data(ptr, source, self.ctype.size)
 
     def write_raw_float_data(self, source):
-        misc.write_raw_float_data(self._cdata, source, self.ctype.size)
-        keepalive_until_here(self)
+        with self as ptr:
+            misc.write_raw_float_data(ptr, source, self.ctype.size)
 
     def convert_to_object(self):
-        w_obj = self.ctype.convert_to_object(self._cdata)
-        keepalive_until_here(self)
+        with self as ptr:
+            w_obj = self.ctype.convert_to_object(ptr)
         return w_obj
 
     def get_array_length(self):
@@ -353,7 +377,7 @@
 
     @rgc.must_be_light_finalizer
     def __del__(self):
-        lltype.free(self._cdata, flavor='raw')
+        lltype.free(self._ptr, flavor='raw')
 
 
 class W_CDataNewOwning(W_CDataMem):
diff --git a/pypy/module/_cffi_backend/ctypearray.py b/pypy/module/_cffi_backend/ctypearray.py
--- a/pypy/module/_cffi_backend/ctypearray.py
+++ b/pypy/module/_cffi_backend/ctypearray.py
@@ -8,7 +8,6 @@
 from pypy.interpreter.typedef import TypeDef
 
 from rpython.rtyper.lltypesystem import rffi
-from rpython.rlib.objectmodel import keepalive_until_here
 from rpython.rlib.rarithmetic import ovfcheck
 
 from pypy.module._cffi_backend import cdataobj
@@ -49,8 +48,8 @@
             cdata = cdataobj.W_CDataNewOwning(space, datasize, self)
         #
         if not space.is_w(w_init, space.w_None):
-            self.convert_from_object(cdata._cdata, w_init)
-            keepalive_until_here(cdata)
+            with cdata as ptr:
+                self.convert_from_object(ptr, w_init)
         return cdata
 
     def _check_subscript_index(self, w_cdata, i):
@@ -119,8 +118,8 @@
         self.ctitem = ctitem
         self.cdata = cdata
         length = cdata.get_array_length()
-        self._next = cdata._cdata
-        self._stop = rffi.ptradd(cdata._cdata, length * ctitem.size)
+        self._next = cdata.unsafe_escaping_ptr()
+        self._stop = rffi.ptradd(self._next, length * ctitem.size)
 
     def iter_w(self):
         return self.space.wrap(self)
diff --git a/pypy/module/_cffi_backend/ctypeenum.py b/pypy/module/_cffi_backend/ctypeenum.py
--- a/pypy/module/_cffi_backend/ctypeenum.py
+++ b/pypy/module/_cffi_backend/ctypeenum.py
@@ -2,8 +2,6 @@
 Enums.
 """
 
-from rpython.rlib.objectmodel import keepalive_until_here
-
 from pypy.module._cffi_backend import misc
 from pypy.module._cffi_backend.ctypeprim import (W_CTypePrimitiveSigned,
     W_CTypePrimitiveUnsigned)
@@ -47,8 +45,8 @@
             return '%s: %s' % (value, s)
 
     def string(self, cdataobj, maxlen):
-        value = self._get_value(cdataobj._cdata)
-        keepalive_until_here(cdataobj)
+        with cdataobj as ptr:
+            value = self._get_value(ptr)
         try:
             s = self.enumvalues2erators[value]
         except KeyError:
diff --git a/pypy/module/_cffi_backend/ctypeobj.py b/pypy/module/_cffi_backend/ctypeobj.py
--- a/pypy/module/_cffi_backend/ctypeobj.py
+++ b/pypy/module/_cffi_backend/ctypeobj.py
@@ -177,8 +177,8 @@
         raise oefmt(space.w_AttributeError,
                     "cdata '%s' has no attribute '%s'", self.name, attr)
 
-    def copy_and_convert_to_object(self, cdata):
-        return self.convert_to_object(cdata)
+    def copy_and_convert_to_object(self, source):
+        return self.convert_to_object(source)
 
     # __________ app-level attributes __________
     def dir(self):
diff --git a/pypy/module/_cffi_backend/ctypeprim.py b/pypy/module/_cffi_backend/ctypeprim.py
--- a/pypy/module/_cffi_backend/ctypeprim.py
+++ b/pypy/module/_cffi_backend/ctypeprim.py
@@ -5,7 +5,6 @@
 import sys
 
 from rpython.rlib.rarithmetic import r_uint, r_ulonglong, intmask
-from rpython.rlib.objectmodel import keepalive_until_here
 from rpython.rlib import jit
 from rpython.rtyper.lltypesystem import lltype, rffi
 
@@ -53,7 +52,8 @@
         space = self.space
         if (isinstance(w_ob, cdataobj.W_CData) and
                isinstance(w_ob.ctype, ctypeptr.W_CTypePtrOrArray)):
-            value = rffi.cast(lltype.Signed, w_ob._cdata)
+            ptr = w_ob.unsafe_escaping_ptr()
+            value = rffi.cast(lltype.Signed, ptr)
             value = self._cast_result(value)
         elif space.isinstance_w(w_ob, space.w_str):
             value = self.cast_str(w_ob)
@@ -81,8 +81,8 @@
 
     def string(self, cdataobj, maxlen):
         if self.size == 1:
-            s = cdataobj._cdata[0]
-            keepalive_until_here(cdataobj)
+            with cdataobj as ptr:
+                s = ptr[0]
             return self.space.wrap(s)
         return W_CType.string(self, cdataobj, maxlen)
 
@@ -116,7 +116,8 @@
                 return s[0]
         if (isinstance(w_ob, cdataobj.W_CData) and
                isinstance(w_ob.ctype, W_CTypePrimitiveChar)):
-            return w_ob._cdata[0]
+            with w_ob as ptr:
+                return ptr[0]
         raise self._convert_error("string of length 1", w_ob)
 
     def convert_from_object(self, cdata, w_ob):
@@ -137,8 +138,8 @@
         return self.space.wrap(s)
 
     def string(self, cdataobj, maxlen):
-        w_res = self.convert_to_object(cdataobj._cdata)
-        keepalive_until_here(cdataobj)
+        with cdataobj as ptr:
+            w_res = self.convert_to_object(ptr)
         return w_res
 
     def _convert_to_unichar(self, w_ob):
@@ -149,7 +150,8 @@
                 return s[0]
         if (isinstance(w_ob, cdataobj.W_CData) and
                isinstance(w_ob.ctype, W_CTypePrimitiveUniChar)):
-            return rffi.cast(rffi.CWCHARP, w_ob._cdata)[0]
+            with w_ob as ptr:
+                return rffi.cast(rffi.CWCHARP, ptr)[0]
         raise self._convert_error("unicode string of length 1", w_ob)
 
     def convert_from_object(self, cdata, w_ob):
@@ -219,13 +221,15 @@
         if self.size == rffi.sizeof(rffi.LONG):
             from rpython.rlib.rrawarray import populate_list_from_raw_array
             res = []
-            buf = rffi.cast(rffi.LONGP, w_cdata._cdata)
             length = w_cdata.get_array_length()
-            populate_list_from_raw_array(res, buf, length)
+            with w_cdata as ptr:
+                buf = rffi.cast(rffi.LONGP, ptr)
+                populate_list_from_raw_array(res, buf, length)
             return res
         elif self.value_smaller_than_long:
             res = [0] * w_cdata.get_array_length()
-            misc.unpack_list_from_raw_array(res, w_cdata._cdata, self.size)
+            with w_cdata as ptr:
+                misc.unpack_list_from_raw_array(res, ptr, self.size)
             return res
         return None
 
@@ -308,8 +312,8 @@
     def unpack_list_of_int_items(self, w_cdata):
         if self.value_fits_long:
             res = [0] * w_cdata.get_array_length()
-            misc.unpack_unsigned_list_from_raw_array(res, w_cdata._cdata,
-                                                     self.size)
+            with w_cdata as ptr:
+                misc.unpack_unsigned_list_from_raw_array(res, ptr, self.size)
             return res
         return None
 
@@ -363,8 +367,8 @@
         if not isinstance(self, W_CTypePrimitiveLongDouble):
             w_cdata.write_raw_float_data(value)
         else:
-            self._to_longdouble_and_write(value, w_cdata._cdata)
-            keepalive_until_here(w_cdata)
+            with w_cdata as ptr:
+                self._to_longdouble_and_write(value, ptr)
         return w_cdata
 
     def cast_to_int(self, cdata):
@@ -387,13 +391,15 @@
         if self.size == rffi.sizeof(rffi.DOUBLE):
             from rpython.rlib.rrawarray import populate_list_from_raw_array
             res = []
-            buf = rffi.cast(rffi.DOUBLEP, w_cdata._cdata)
             length = w_cdata.get_array_length()
-            populate_list_from_raw_array(res, buf, length)
+            with w_cdata as ptr:
+                buf = rffi.cast(rffi.DOUBLEP, ptr)
+                populate_list_from_raw_array(res, buf, length)
             return res
         elif self.size == rffi.sizeof(rffi.FLOAT):
             res = [0.0] * w_cdata.get_array_length()
-            misc.unpack_cfloat_list_from_raw_array(res, w_cdata._cdata)
+            with w_cdata as ptr:
+                misc.unpack_cfloat_list_from_raw_array(res, ptr)
             return res
         return None
 
@@ -423,8 +429,8 @@
     def cast(self, w_ob):
         if (isinstance(w_ob, cdataobj.W_CData) and
                 isinstance(w_ob.ctype, W_CTypePrimitiveLongDouble)):
-            w_cdata = self.convert_to_object(w_ob._cdata)
-            keepalive_until_here(w_ob)
+            with w_ob as ptr:
+                w_cdata = self.convert_to_object(ptr)
             return w_cdata
         else:
             return W_CTypePrimitiveFloat.cast(self, w_ob)
@@ -451,16 +457,16 @@
 
     def convert_to_object(self, cdata):
         w_cdata = cdataobj.W_CDataMem(self.space, self.size, self)
-        self._copy_longdouble(cdata, w_cdata._cdata)
-        keepalive_until_here(w_cdata)
+        with w_cdata as ptr:
+            self._copy_longdouble(cdata, ptr)
         return w_cdata
 
     def convert_from_object(self, cdata, w_ob):
         space = self.space
         if (isinstance(w_ob, cdataobj.W_CData) and
                 isinstance(w_ob.ctype, W_CTypePrimitiveLongDouble)):
-            self._copy_longdouble(w_ob._cdata, cdata)
-            keepalive_until_here(w_ob)
+            with w_ob as ptr:
+                self._copy_longdouble(ptr, cdata)
         else:
             value = space.float_w(space.float(w_ob))
             self._to_longdouble_and_write(value, cdata)
diff --git a/pypy/module/_cffi_backend/ctypeptr.py b/pypy/module/_cffi_backend/ctypeptr.py
--- a/pypy/module/_cffi_backend/ctypeptr.py
+++ b/pypy/module/_cffi_backend/ctypeptr.py
@@ -3,7 +3,6 @@
 """
 
 from rpython.rlib import rposix
-from rpython.rlib.objectmodel import keepalive_until_here
 from rpython.rlib.rarithmetic import ovfcheck
 from rpython.rtyper.annlowlevel import llstr, llunicode
 from rpython.rtyper.lltypesystem import lltype, rffi
@@ -49,7 +48,7 @@
         space = self.space
         if (isinstance(w_ob, cdataobj.W_CData) and
                 isinstance(w_ob.ctype, W_CTypePtrOrArray)):
-            value = w_ob._cdata
+            value = w_ob.unsafe_escaping_ptr()
         else:
             value = misc.as_unsigned_long(space, w_ob, strict=False)
             value = rffi.cast(rffi.CCHARP, value)
@@ -108,34 +107,33 @@
     def string(self, cdataobj, maxlen):
         space = self.space
         if isinstance(self.ctitem, ctypeprim.W_CTypePrimitive):
-            cdata = cdataobj._cdata
-            if not cdata:
-                raise oefmt(space.w_RuntimeError, "cannot use string() on %s",
-                            space.str_w(cdataobj.repr()))
-            #
-            from pypy.module._cffi_backend import ctypearray
-            length = maxlen
-            if length < 0 and isinstance(self, ctypearray.W_CTypeArray):
-                length = cdataobj.get_array_length()
-            #
-            # pointer to a primitive type of size 1: builds and returns a str
-            if self.ctitem.size == rffi.sizeof(lltype.Char):
-                if length < 0:
-                    s = rffi.charp2str(cdata)
-                else:
-                    s = rffi.charp2strn(cdata, length)
-                keepalive_until_here(cdataobj)
-                return space.wrap(s)
-            #
-            # pointer to a wchar_t: builds and returns a unicode
-            if self.is_unichar_ptr_or_array():
-                cdata = rffi.cast(rffi.CWCHARP, cdata)
-                if length < 0:
-                    u = rffi.wcharp2unicode(cdata)
-                else:
-                    u = rffi.wcharp2unicoden(cdata, length)
-                keepalive_until_here(cdataobj)
-                return space.wrap(u)
+            with cdataobj as ptr:
+                if not ptr:
+                    raise oefmt(space.w_RuntimeError,
+                                "cannot use string() on %s",
+                                space.str_w(cdataobj.repr()))
+                #
+                from pypy.module._cffi_backend import ctypearray
+                length = maxlen
+                if length < 0 and isinstance(self, ctypearray.W_CTypeArray):
+                    length = cdataobj.get_array_length()
+                #
+                # pointer to a primitive type of size 1: builds and returns a str
+                if self.ctitem.size == rffi.sizeof(lltype.Char):
+                    if length < 0:
+                        s = rffi.charp2str(ptr)
+                    else:
+                        s = rffi.charp2strn(ptr, length)
+                    return space.wrap(s)
+                #
+                # pointer to a wchar_t: builds and returns a unicode
+                if self.is_unichar_ptr_or_array():
+                    cdata = rffi.cast(rffi.CWCHARP, ptr)
+                    if length < 0:
+                        u = rffi.wcharp2unicode(cdata)
+                    else:
+                        u = rffi.wcharp2unicoden(cdata, length)
+                    return space.wrap(u)
         #
         return W_CType.string(self, cdataobj, maxlen)
 
@@ -162,7 +160,7 @@
             if not (self.can_cast_anything or other.can_cast_anything):
                 raise self._convert_error("compatible pointer", w_ob)
 
-        rffi.cast(rffi.CCHARPP, cdata)[0] = w_ob._cdata
+        rffi.cast(rffi.CCHARPP, cdata)[0] = w_ob.unsafe_escaping_ptr()
 
     def _alignof(self):
         from pypy.module._cffi_backend import newtype
@@ -206,8 +204,8 @@
                     lltype.nullptr(rffi.CCHARP.TO), w_init, datasize)
             #
             cdatastruct = cdataobj.W_CDataNewOwning(space, datasize, ctitem)
-            cdata = cdataobj.W_CDataPtrToStructOrUnion(space,
-                                                       cdatastruct._cdata,
+            ptr = cdatastruct.unsafe_escaping_ptr()
+            cdata = cdataobj.W_CDataPtrToStructOrUnion(space, ptr,
                                                        self, cdatastruct)
         else:
             if self.is_char_or_unichar_ptr_or_array():
@@ -215,8 +213,8 @@
             cdata = cdataobj.W_CDataNewOwning(space, datasize, self)
         #
         if not space.is_w(w_init, space.w_None):
-            ctitem.convert_from_object(cdata._cdata, w_init)
-            keepalive_until_here(cdata)
+            with cdata as ptr:
+                ctitem.convert_from_object(ptr, w_init)
         return cdata
 
     def _check_subscript_index(self, w_cdata, i):
@@ -332,8 +330,9 @@
         ctype2 = cdata.ctype
         if (isinstance(ctype2, W_CTypeStructOrUnion) or
                 isinstance(ctype2, W_CTypePtrOrArray)):
-            ptrdata = rffi.ptradd(cdata._cdata, offset)
-            return cdataobj.W_CData(space, ptrdata, self)
+            ptr = cdata.unsafe_escaping_ptr()
+            ptr = rffi.ptradd(ptr, offset)
+            return cdataobj.W_CData(space, ptr, self)
         else:
             raise OperationError(space.w_TypeError,
                     space.wrap("expected a cdata struct/union/array/pointer"
diff --git a/pypy/module/_cffi_backend/ctypestruct.py b/pypy/module/_cffi_backend/ctypestruct.py
--- a/pypy/module/_cffi_backend/ctypestruct.py
+++ b/pypy/module/_cffi_backend/ctypestruct.py
@@ -7,7 +7,6 @@
 from pypy.interpreter.typedef import TypeDef, interp_attrproperty
 
 from rpython.rlib import jit
-from rpython.rlib.objectmodel import keepalive_until_here
 from rpython.rlib.rarithmetic import r_uint, r_ulonglong, r_longlong, intmask
 from rpython.rlib.rarithmetic import ovfcheck
 from rpython.rtyper.lltypesystem import lltype, rffi
@@ -57,12 +56,12 @@
         self.check_complete()
         return cdataobj.W_CData(space, cdata, self)
 
-    def copy_and_convert_to_object(self, cdata):
+    def copy_and_convert_to_object(self, source):
         space = self.space
         self.check_complete()
         ob = cdataobj.W_CDataNewOwning(space, self.size, self)
-        misc._raw_memcopy(cdata, ob._cdata, self.size)
-        keepalive_until_here(ob)
+        with ob as target:
+            misc._raw_memcopy(source, target, self.size)
         return ob
 
     def typeoffsetof_field(self, fieldname, following):
@@ -80,8 +79,8 @@
     def _copy_from_same(self, cdata, w_ob):
         if isinstance(w_ob, cdataobj.W_CData):
             if w_ob.ctype is self and self.size >= 0:
-                misc._raw_memcopy(w_ob._cdata, cdata, self.size)
-                keepalive_until_here(w_ob)
+                with w_ob as ptr:
+                    misc._raw_memcopy(ptr, cdata, self.size)
                 return True
         return False
 
diff --git a/pypy/module/_cffi_backend/ctypevoid.py b/pypy/module/_cffi_backend/ctypevoid.py
--- a/pypy/module/_cffi_backend/ctypevoid.py
+++ b/pypy/module/_cffi_backend/ctypevoid.py
@@ -13,5 +13,5 @@
     def __init__(self, space):
         W_CType.__init__(self, space, -1, "void", len("void"))
 
-    def copy_and_convert_to_object(self, cdata):
+    def copy_and_convert_to_object(self, source):
         return self.space.w_None
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
@@ -34,8 +34,9 @@
         raise oefmt(space.w_TypeError,
                     "expected a 'cdata' object with a 'void *' out of "
                     "new_handle(), got '%s'", ctype.name)
-    index = rffi.cast(lltype.Signed, w_cdata._cdata)
-    original_cdataobj = get(space).fetch_handle(index - 1)
+    with w_cdata as ptr:
+        index = rffi.cast(lltype.Signed, ptr)
+        original_cdataobj = get(space).fetch_handle(index - 1)
     #
     if isinstance(original_cdataobj, cdataobj.W_CDataHandle):
         return original_cdataobj.w_keepalive
diff --git a/pypy/module/_cffi_backend/misc.py b/pypy/module/_cffi_backend/misc.py
--- a/pypy/module/_cffi_backend/misc.py
+++ b/pypy/module/_cffi_backend/misc.py
@@ -3,7 +3,7 @@
 from pypy.interpreter.error import OperationError
 
 from rpython.rlib import jit
-from rpython.rlib.objectmodel import keepalive_until_here, specialize
+from rpython.rlib.objectmodel import specialize
 from rpython.rlib.rarithmetic import r_uint, r_ulonglong
 from rpython.rlib.unroll import unrolling_iterable
 from rpython.rtyper.lltypesystem import lltype, llmemory, rffi
@@ -272,11 +272,11 @@
     from pypy.module._cffi_backend.ctypeprim import W_CTypePrimitiveLongDouble
     is_cdata = isinstance(w_ob, W_CData)
     if is_cdata and isinstance(w_ob.ctype, W_CTypePrimitiveFloat):
-        if isinstance(w_ob.ctype, W_CTypePrimitiveLongDouble):
-            result = is_nonnull_longdouble(w_ob._cdata)
-        else:
-            result = is_nonnull_float(w_ob._cdata, w_ob.ctype.size)
-        keepalive_until_here(w_ob)
+        with w_ob as ptr:
+            if isinstance(w_ob.ctype, W_CTypePrimitiveLongDouble):
+                result = is_nonnull_longdouble(ptr)
+            else:
+                result = is_nonnull_float(ptr, w_ob.ctype.size)
         return result
     #
     if not is_cdata and space.lookup(w_ob, '__float__') is not None:


More information about the pypy-commit mailing list