[pypy-commit] pypy object-dtype2: merge default into branch

mattip noreply at buildbot.pypy.org
Fri Mar 6 16:02:51 CET 2015


Author: mattip <matti.picus at gmail.com>
Branch: object-dtype2
Changeset: r76253:cb72282b1ea6
Date: 2015-03-06 09:28 +0200
http://bitbucket.org/pypy/pypy/changeset/cb72282b1ea6/

Log:	merge default into branch

diff too long, truncating to 2000 out of 3202 lines

diff --git a/lib_pypy/cffi.egg-info b/lib_pypy/cffi.egg-info
--- a/lib_pypy/cffi.egg-info
+++ b/lib_pypy/cffi.egg-info
@@ -1,6 +1,6 @@
 Metadata-Version: 1.0
 Name: cffi
-Version: 0.8.6+
+Version: 0.9.0
 Summary: Foreign Function Interface for Python calling C code.
 Home-page: http://cffi.readthedocs.org
 Author: Armin Rigo, Maciej Fijalkowski
diff --git a/lib_pypy/cffi/__init__.py b/lib_pypy/cffi/__init__.py
--- a/lib_pypy/cffi/__init__.py
+++ b/lib_pypy/cffi/__init__.py
@@ -4,8 +4,8 @@
 from .api import FFI, CDefError, FFIError
 from .ffiplatform import VerificationError, VerificationMissing
 
-__version__ = "0.8.6+"
-__version_info__ = (0, 8, 6, "plus")
+__version__ = "0.9.0"
+__version_info__ = (0, 9, 0)
 
 # The verifier module file names are based on the CRC32 of a string that
 # contains the following version number.  It may be older than __version__
diff --git a/lib_pypy/pyrepl/readline.py b/lib_pypy/pyrepl/readline.py
--- a/lib_pypy/pyrepl/readline.py
+++ b/lib_pypy/pyrepl/readline.py
@@ -73,7 +73,6 @@
     assume_immutable_completions = False
     use_brackets = False
     sort_in_column = True
-    tab_insert_spaces_if_stem_is_empty = False
 
     def error(self, msg="none"):
         pass    # don't show error messages by default
@@ -87,7 +86,7 @@
         return ''.join(b[p+1:self.pos])
 
     def get_completions(self, stem):
-        if len(stem) == 0 and self.tab_insert_spaces_if_stem_is_empty:
+        if len(stem) == 0 and self.more_lines is not None:
             b = self.buffer
             p = self.pos
             while p > 0 and b[p - 1] != '\n':
@@ -141,12 +140,16 @@
 
     def collect_keymap(self):
         return super(ReadlineAlikeReader, self).collect_keymap() + (
-            (r'\n', 'maybe-accept'),)
+            (r'\n', 'maybe-accept'),
+            (r'\<backspace>', 'backspace-dedent'),
+            )
 
     def __init__(self, console):
         super(ReadlineAlikeReader, self).__init__(console)
         self.commands['maybe_accept'] = maybe_accept
         self.commands['maybe-accept'] = maybe_accept
+        self.commands['backspace_dedent'] = backspace_dedent
+        self.commands['backspace-dedent'] = backspace_dedent
 
     def after_command(self, cmd):
         super(ReadlineAlikeReader, self).after_command(cmd)
@@ -164,6 +167,28 @@
                 if self.pos > len(self.buffer):
                     self.pos = len(self.buffer)
 
+def _get_this_line_indent(buffer, pos):
+    indent = 0
+    while pos > 0 and buffer[pos - 1] in " \t":
+        indent += 1
+        pos -= 1
+    if pos > 0 and buffer[pos - 1] == "\n":
+        return indent
+    return 0
+
+def _get_previous_line_indent(buffer, pos):
+    prevlinestart = pos
+    while prevlinestart > 0 and buffer[prevlinestart - 1] != "\n":
+        prevlinestart -= 1
+    prevlinetext = prevlinestart
+    while prevlinetext < pos and buffer[prevlinetext] in " \t":
+        prevlinetext += 1
+    if prevlinetext == pos:
+        indent = None
+    else:
+        indent = prevlinetext - prevlinestart
+    return prevlinestart, indent
+
 class maybe_accept(commands.Command):
     def do(self):
         r = self.reader
@@ -172,13 +197,39 @@
         # if there are already several lines and the cursor
         # is not on the last one, always insert a new \n.
         text = r.get_unicode()
-        if "\n" in r.buffer[r.pos:]:
+        if ("\n" in r.buffer[r.pos:] or
+            (r.more_lines is not None and r.more_lines(text))):
+            #
+            # auto-indent the next line like the previous line
+            prevlinestart, indent = _get_previous_line_indent(r.buffer, r.pos)
             r.insert("\n")
-        elif r.more_lines is not None and r.more_lines(text):
-            r.insert("\n")
+            if indent:
+                for i in range(prevlinestart, prevlinestart + indent):
+                    r.insert(r.buffer[i])
         else:
             self.finish = 1
 
+class backspace_dedent(commands.Command):
+    def do(self):
+        r = self.reader
+        b = r.buffer
+        if r.pos > 0:
+            repeat = 1
+            if b[r.pos - 1] != "\n":
+                indent = _get_this_line_indent(b, r.pos)
+                if indent > 0:
+                    ls = r.pos - indent
+                    while ls > 0:
+                        ls, pi = _get_previous_line_indent(b, ls - 1)
+                        if pi is not None and pi < indent:
+                            repeat = indent - pi
+                            break
+            r.pos -= repeat
+            del b[r.pos:r.pos + repeat]
+            r.dirty = 1
+        else:
+            self.reader.error("can't backspace at start")
+
 # ____________________________________________________________
 
 class _ReadlineWrapper(object):
@@ -212,15 +263,14 @@
         boolean value is true.
         """
         reader = self.get_reader()
-        saved = reader.more_lines, reader.tab_insert_spaces_if_stem_is_empty
+        saved = reader.more_lines
         try:
             reader.more_lines = more_lines
             reader.ps1 = reader.ps2 = ps1
             reader.ps3 = reader.ps4 = ps2
-            reader.tab_insert_spaces_if_stem_is_empty = True
             return reader.readline(returns_unicode=returns_unicode)
         finally:
-            reader.more_lines, reader.tab_insert_spaces_if_stem_is_empty = saved
+            reader.more_lines = saved
 
     def parse_and_bind(self, string):
         pass  # XXX we don't support parsing GNU-readline-style init files
diff --git a/pypy/doc/jit-hooks.rst b/pypy/doc/jit-hooks.rst
--- a/pypy/doc/jit-hooks.rst
+++ b/pypy/doc/jit-hooks.rst
@@ -39,3 +39,30 @@
     Reason is a string, the meaning of other arguments is the same
     as attributes on JitLoopInfo object
 
+.. function:: enable_debug()
+
+    Start recording debugging counters for ``get_stats_snapshot``
+
+.. function:: disable_debug()
+
+    Stop recording debugging counters for ``get_stats_snapshot``
+
+.. function:: get_stats_snapshot()
+
+    Get the jit status in the specific moment in time. Note that this
+    is eager - the attribute access is not lazy, if you need new stats
+    you need to call this function again. You might want to call
+    ``enable_debug`` to get more information. It returns an instance
+    of ``JitInfoSnapshot``
+
+.. class:: JitInfoSnapshot
+
+    A class describing current snapshot. Usable attributes:
+
+    * ``counters`` - internal JIT integer counters
+
+    * ``counter_times`` - internal JIT float counters, notably time spent
+      TRACING and in the JIT BACKEND
+
+    * ``loop_run_times`` - counters for number of times loops are run, only
+      works when ``enable_debug`` is called.
diff --git a/pypy/interpreter/app_main.py b/pypy/interpreter/app_main.py
--- a/pypy/interpreter/app_main.py
+++ b/pypy/interpreter/app_main.py
@@ -517,6 +517,10 @@
     elif not sys.stdout.isatty():
         set_fully_buffered_io()
 
+    if we_are_translated():
+        import __pypy__
+        __pypy__.save_module_content_for_future_reload(sys)
+
     mainmodule = type(sys)('__main__')
     sys.modules['__main__'] = mainmodule
 
diff --git a/pypy/interpreter/mixedmodule.py b/pypy/interpreter/mixedmodule.py
--- a/pypy/interpreter/mixedmodule.py
+++ b/pypy/interpreter/mixedmodule.py
@@ -55,7 +55,10 @@
         if self.w_initialdict is None:
             Module.init(self, space)
             if not self.lazy and self.w_initialdict is None:
-                self.w_initialdict = space.call_method(self.w_dict, 'items')
+                self.save_module_content_for_future_reload()
+
+    def save_module_content_for_future_reload(self):
+        self.w_initialdict = self.space.call_method(self.w_dict, 'items')
 
 
     def get_applevel_name(cls):
@@ -119,7 +122,7 @@
                 w_value = self.get(name)
                 space.setitem(self.w_dict, space.new_interned_str(name), w_value)
             self.lazy = False
-            self.w_initialdict = space.call_method(self.w_dict, 'items')
+            self.save_module_content_for_future_reload()
         return self.w_dict
 
     def _cleanup_(self):
diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py
--- a/pypy/module/__pypy__/__init__.py
+++ b/pypy/module/__pypy__/__init__.py
@@ -82,6 +82,8 @@
         'strategy'                  : 'interp_magic.strategy',  # dict,set,list
         'set_debug'                 : 'interp_magic.set_debug',
         'locals_to_fast'            : 'interp_magic.locals_to_fast',
+        'save_module_content_for_future_reload':
+                          'interp_magic.save_module_content_for_future_reload',
     }
     if sys.platform == 'win32':
         interpleveldefs['get_console_cp'] = 'interp_magic.get_console_cp'
diff --git a/pypy/module/__pypy__/interp_magic.py b/pypy/module/__pypy__/interp_magic.py
--- a/pypy/module/__pypy__/interp_magic.py
+++ b/pypy/module/__pypy__/interp_magic.py
@@ -1,6 +1,7 @@
 from pypy.interpreter.error import OperationError, wrap_oserror
 from pypy.interpreter.gateway import unwrap_spec
 from pypy.interpreter.pyframe import PyFrame
+from pypy.interpreter.mixedmodule import MixedModule
 from rpython.rlib.objectmodel import we_are_translated
 from pypy.objspace.std.dictmultiobject import W_DictMultiObject
 from pypy.objspace.std.listobject import W_ListObject
@@ -130,3 +131,7 @@
 def locals_to_fast(space, w_frame):
     assert isinstance(w_frame, PyFrame)
     w_frame.locals2fast()
+
+ at unwrap_spec(w_module=MixedModule)
+def save_module_content_for_future_reload(space, w_module):
+    w_module.save_module_content_for_future_reload()
diff --git a/pypy/module/__pypy__/test/test_magic.py b/pypy/module/__pypy__/test/test_magic.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/__pypy__/test/test_magic.py
@@ -0,0 +1,15 @@
+
+class AppTestMagic:
+    spaceconfig = dict(usemodules=['__pypy__'])
+
+    def test_save_module_content_for_future_reload(self):
+        import sys, __pypy__
+        d = sys.dont_write_bytecode
+        sys.dont_write_bytecode = "hello world"
+        __pypy__.save_module_content_for_future_reload(sys)
+        sys.dont_write_bytecode = d
+        reload(sys)
+        assert sys.dont_write_bytecode == "hello world"
+        #
+        sys.dont_write_bytecode = d
+        __pypy__.save_module_content_for_future_reload(sys)
diff --git a/pypy/module/_cffi_backend/__init__.py b/pypy/module/_cffi_backend/__init__.py
--- a/pypy/module/_cffi_backend/__init__.py
+++ b/pypy/module/_cffi_backend/__init__.py
@@ -8,7 +8,7 @@
     appleveldefs = {
         }
     interpleveldefs = {
-        '__version__': 'space.wrap("0.8.6+")',
+        '__version__': 'space.wrap("0.9.0")',
 
         'load_library': 'libraryobj.load_library',
 
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:
diff --git a/pypy/module/_cffi_backend/test/_backend_test_c.py b/pypy/module/_cffi_backend/test/_backend_test_c.py
--- a/pypy/module/_cffi_backend/test/_backend_test_c.py
+++ b/pypy/module/_cffi_backend/test/_backend_test_c.py
@@ -3249,4 +3249,4 @@
 
 def test_version():
     # this test is here mostly for PyPy
-    assert __version__ == "0.8.6+"
+    assert __version__ == "0.9.0"
diff --git a/pypy/module/array/interp_array.py b/pypy/module/array/interp_array.py
--- a/pypy/module/array/interp_array.py
+++ b/pypy/module/array/interp_array.py
@@ -1,4 +1,4 @@
-from rpython.rlib import jit
+from rpython.rlib import jit, rgc
 from rpython.rlib.buffer import Buffer
 from rpython.rlib.objectmodel import keepalive_until_here
 from rpython.rlib.rarithmetic import ovfcheck, widen
@@ -698,11 +698,9 @@
                                          self.space.wrap(msg))
             return result
 
+        @rgc.must_be_light_finalizer
         def __del__(self):
-            # note that we don't call clear_all_weakrefs here because
-            # an array with freed buffer is ok to see - it's just empty with 0
-            # length
-            self.setlen(0)
+            lltype.free(self.buffer, flavor='raw')
 
         def setlen(self, size, zero=False, overallocate=True):
             if size > 0:
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
@@ -259,7 +259,8 @@
         if not objectmodel.we_are_translated():
             leakfinder.remember_free(c_call.ctype.cif_descr._obj0)
         state.capi_calls[name] = c_call
-    return c_call.ctype.rcall(c_call._cdata, args)
+    with c_call as ptr:
+        return c_call.ctype.rcall(ptr, args)
 
 def _cdata_to_cobject(space, w_cdata):
     return rffi.cast(C_OBJECT, space.uint_w(w_cdata))
@@ -271,8 +272,9 @@
     return rffi.cast(rffi.LONG, space.int_w(w_cdata))
 
 def _cdata_to_ptr(space, w_cdata): # TODO: this is both a hack and dreadfully slow
-    return rffi.cast(rffi.VOIDP,
-        space.interp_w(cdataobj.W_CData, w_cdata, can_be_None=False)._cdata)
+    w_cdata = space.interp_w(cdataobj.W_CData, w_cdata, can_be_None=False)
+    ptr = w_cdata.unsafe_escaping_ptr()
+    return rffi.cast(rffi.VOIDP, ptr)
 
 def c_load_dictionary(name):
     return libffi.CDLL(name)
diff --git a/pypy/module/micronumpy/base.py b/pypy/module/micronumpy/base.py
--- a/pypy/module/micronumpy/base.py
+++ b/pypy/module/micronumpy/base.py
@@ -48,7 +48,7 @@
     @staticmethod
     def from_shape_and_storage(space, shape, storage, dtype, storage_bytes=-1,
                                order='C', owning=False, w_subtype=None,
-                               w_base=None, writable=True, strides=None):
+                               w_base=None, writable=True, strides=None, start=0):
         from pypy.module.micronumpy import concrete
         from pypy.module.micronumpy.strides import (calc_strides,
                                                     calc_backstrides)
@@ -77,8 +77,9 @@
                 raise OperationError(space.w_ValueError,
                         space.wrap("Cannot have owning=True when specifying a buffer"))
             if writable:
-                impl = concrete.ConcreteArrayWithBase(shape, dtype, order, strides,
-                                                      backstrides, storage, w_base)
+                impl = concrete.ConcreteArrayWithBase(shape, dtype, order,
+                                    strides, backstrides, storage, w_base,
+                                    start=start)
             else:
                 impl = concrete.ConcreteNonWritableArrayWithBase(shape, dtype, order,
                                                                  strides, backstrides,
@@ -130,6 +131,9 @@
     def get_order(self):
         return self.implementation.order
 
+    def get_start(self):
+        return self.implementation.start
+
     def ndims(self):
         return len(self.get_shape())
     ndims._always_inline_ = True
diff --git a/pypy/module/micronumpy/concrete.py b/pypy/module/micronumpy/concrete.py
--- a/pypy/module/micronumpy/concrete.py
+++ b/pypy/module/micronumpy/concrete.py
@@ -12,6 +12,7 @@
 from pypy.module.micronumpy.strides import (Chunk, Chunks, NewAxisChunk,
     RecordChunk, calc_strides, calc_new_strides, shape_agreement,
     calculate_broadcast_strides, calc_backstrides)
+from rpython.rlib.objectmodel import keepalive_until_here
 
 
 class BaseConcreteArray(object):
@@ -312,12 +313,15 @@
         l_w = [w_res.descr_getitem(space, space.wrap(d)) for d in range(nd)]
         return space.newtuple(l_w)
 
-    def get_storage_as_int(self, space):
-        return rffi.cast(lltype.Signed, self.storage) + self.start
-
-    def get_storage(self):
+    ##def get_storage(self):
+    ##    return self.storage
+    ## use a safer context manager
+    def __enter__(self):
         return self.storage
 
+    def __exit__(self, typ, value, traceback):
+        keepalive_until_here(self)
+        
     def get_buffer(self, space, readonly):
         return ArrayBuffer(self, readonly)
 
@@ -331,7 +335,7 @@
 
 
 class ConcreteArrayNotOwning(BaseConcreteArray):
-    def __init__(self, shape, dtype, order, strides, backstrides, storage):
+    def __init__(self, shape, dtype, order, strides, backstrides, storage, start=0):
         make_sure_not_resized(shape)
         make_sure_not_resized(strides)
         make_sure_not_resized(backstrides)
@@ -342,6 +346,7 @@
         self.strides = strides
         self.backstrides = backstrides
         self.storage = storage
+        self.start = start
 
     def fill(self, space, box):
         self.dtype.itemtype.fill(self.storage, self.dtype.elsize,
@@ -350,7 +355,7 @@
     def set_shape(self, space, orig_array, new_shape):
         strides, backstrides = calc_strides(new_shape, self.dtype,
                                                     self.order)
-        return SliceArray(0, strides, backstrides, new_shape, self,
+        return SliceArray(self.start, strides, backstrides, new_shape, self,
                           orig_array)
 
     def set_dtype(self, space, dtype):
@@ -384,9 +389,10 @@
 
 
 class ConcreteArrayWithBase(ConcreteArrayNotOwning):
-    def __init__(self, shape, dtype, order, strides, backstrides, storage, orig_base):
+    def __init__(self, shape, dtype, order, strides, backstrides, storage,
+                 orig_base, start=0):
         ConcreteArrayNotOwning.__init__(self, shape, dtype, order,
-                                        strides, backstrides, storage)
+                                        strides, backstrides, storage, start)
         self.orig_base = orig_base
 
     def base(self):
diff --git a/pypy/module/micronumpy/ctors.py b/pypy/module/micronumpy/ctors.py
--- a/pypy/module/micronumpy/ctors.py
+++ b/pypy/module/micronumpy/ctors.py
@@ -99,10 +99,12 @@
             for i in range(w_object.get_size()):
                 elems_w[i] = w_object.implementation.getitem(i * elsize)
         else:
-            sz = support.product(w_object.get_shape()) * dtype.elsize
-            return W_NDimArray.from_shape_and_storage(space,
-                w_object.get_shape(),w_object.implementation.storage,
-                dtype, storage_bytes=sz, w_base=w_object)
+            imp = w_object.implementation
+            with imp as storage:
+                sz = support.product(w_object.get_shape()) * dtype.elsize
+                return W_NDimArray.from_shape_and_storage(space,
+                    w_object.get_shape(), storage, dtype, storage_bytes=sz, 
+                    w_base=w_object, start=imp.start)
     else:
         # not an array
         shape, elems_w = strides.find_shape_and_elems(space, w_object, dtype)
diff --git a/pypy/module/micronumpy/loop.py b/pypy/module/micronumpy/loop.py
--- a/pypy/module/micronumpy/loop.py
+++ b/pypy/module/micronumpy/loop.py
@@ -604,14 +604,15 @@
     iter, state = arr.create_iter()
     w_res_str = W_NDimArray.from_shape(space, [1], arr.get_dtype(), order='C')
     itemsize = arr.get_dtype().elsize
-    res_str_casted = rffi.cast(rffi.CArrayPtr(lltype.Char),
-                               w_res_str.implementation.get_storage_as_int(space))
-    while not iter.done(state):
-        w_res_str.implementation.setitem(0, iter.getitem(state))
-        for i in range(itemsize):
-            builder.append(res_str_casted[i])
-        state = iter.next(state)
-    return builder.build()
+    with w_res_str.implementation as storage:
+        res_str_casted = rffi.cast(rffi.CArrayPtr(lltype.Char),
+                               support.get_storage_as_int(storage))
+        while not iter.done(state):
+            w_res_str.implementation.setitem(0, iter.getitem(state))
+            for i in range(itemsize):
+                builder.append(res_str_casted[i])
+            state = iter.next(state)
+        return builder.build()
 
 getitem_int_driver = jit.JitDriver(name = 'numpy_getitem_int',
                                    greens = ['shapelen', 'indexlen',
diff --git a/pypy/module/micronumpy/ndarray.py b/pypy/module/micronumpy/ndarray.py
--- a/pypy/module/micronumpy/ndarray.py
+++ b/pypy/module/micronumpy/ndarray.py
@@ -532,20 +532,25 @@
             self.get_dtype(), storage_bytes=sz, w_base=self)
 
     def descr_array_iface(self, space):
-        addr = self.implementation.get_storage_as_int(space)
-        # will explode if it can't
-        w_d = space.newdict()
-        space.setitem_str(w_d, 'data',
-                          space.newtuple([space.wrap(addr), space.w_False]))
-        space.setitem_str(w_d, 'shape', self.descr_get_shape(space))
-        space.setitem_str(w_d, 'typestr', self.get_dtype().descr_get_str(space))
-        if self.implementation.order == 'C':
-            # Array is contiguous, no strides in the interface.
-            strides = space.w_None
-        else:
-            strides = self.descr_get_strides(space)
-        space.setitem_str(w_d, 'strides', strides)
-        return w_d
+        '''
+        Note: arr.__array__.data[0] is a pointer so arr must be kept alive
+              while it is in use
+        '''
+        with self.implementation as storage:
+            addr = support.get_storage_as_int(storage, self.get_start())
+            # will explode if it can't
+            w_d = space.newdict()
+            space.setitem_str(w_d, 'data',
+                              space.newtuple([space.wrap(addr), space.w_False]))
+            space.setitem_str(w_d, 'shape', self.descr_get_shape(space))
+            space.setitem_str(w_d, 'typestr', self.get_dtype().descr_get_str(space))
+            if self.implementation.order == 'C':
+                # Array is contiguous, no strides in the interface.
+                strides = space.w_None
+            else:
+                strides = self.descr_get_strides(space)
+            space.setitem_str(w_d, 'strides', strides)
+            return w_d
 
     w_pypy_data = None
 
@@ -1165,7 +1170,8 @@
                 builder.append(box.raw_str())
                 state = iter.next(state)
         else:
-            builder.append_charpsize(self.implementation.get_storage(),
+            with self.implementation as storage:
+                builder.append_charpsize(storage,
                                      self.implementation.get_storage_size())
 
         state = space.newtuple([
diff --git a/pypy/module/micronumpy/selection.py b/pypy/module/micronumpy/selection.py
--- a/pypy/module/micronumpy/selection.py
+++ b/pypy/module/micronumpy/selection.py
@@ -33,14 +33,14 @@
             self.values = values
             self.indexes = indexes
 
-        def getitem(self, item):
+        def getitem(self, idx):
             if count < 2:
-                v = raw_storage_getitem(TP, self.values, item * self.stride_size
+                v = raw_storage_getitem(TP, self.values, idx * self.stride_size
                                     + self.start)
             else:
                 v = []
                 for i in range(count):
-                    _v = raw_storage_getitem(TP, self.values, item * self.stride_size
+                    _v = raw_storage_getitem(TP, self.values, idx * self.stride_size
                                     + self.start + step * i)
                     v.append(_v)
             if comp_type == 'int':
@@ -52,7 +52,7 @@
             else:
                 raise NotImplementedError('cannot reach')
             return (v, raw_storage_getitem(lltype.Signed, self.indexes,
-                                           item * self.index_stride_size +
+                                           idx * self.index_stride_size +
                                            self.index_start))
 
         def setitem(self, idx, item):
@@ -134,37 +134,37 @@
         # create array of indexes
         dtype = descriptor.get_dtype_cache(space).w_longdtype
         index_arr = W_NDimArray.from_shape(space, arr.get_shape(), dtype)
-        storage = index_arr.implementation.get_storage()
-        if len(arr.get_shape()) == 1:
-            for i in range(arr.get_size()):
-                raw_storage_setitem(storage, i * INT_SIZE, i)
-            r = Repr(INT_SIZE, itemsize, arr.get_size(), arr.get_storage(),
-                     storage, 0, arr.start)
-            ArgSort(r).sort()
-        else:
-            shape = arr.get_shape()
-            if axis < 0:
-                axis = len(shape) + axis
-            if axis < 0 or axis >= len(shape):
-                raise oefmt(space.w_IndexError, "Wrong axis %d", axis)
-            arr_iter = AllButAxisIter(arr, axis)
-            arr_state = arr_iter.reset()
-            index_impl = index_arr.implementation
-            index_iter = AllButAxisIter(index_impl, axis)
-            index_state = index_iter.reset()
-            stride_size = arr.strides[axis]
-            index_stride_size = index_impl.strides[axis]
-            axis_size = arr.shape[axis]
-            while not arr_iter.done(arr_state):
-                for i in range(axis_size):
-                    raw_storage_setitem(storage, i * index_stride_size +
-                                        index_state.offset, i)
-                r = Repr(index_stride_size, stride_size, axis_size,
-                         arr.get_storage(), storage, index_state.offset, arr_state.offset)
+        with index_arr.implementation as storage, arr as arr_storage:
+            if len(arr.get_shape()) == 1:
+                for i in range(arr.get_size()):
+                    raw_storage_setitem(storage, i * INT_SIZE, i)
+                r = Repr(INT_SIZE, itemsize, arr.get_size(), arr_storage,
+                         storage, 0, arr.start)
                 ArgSort(r).sort()
-                arr_state = arr_iter.next(arr_state)
-                index_state = index_iter.next(index_state)
-        return index_arr
+            else:
+                shape = arr.get_shape()
+                if axis < 0:
+                    axis = len(shape) + axis
+                if axis < 0 or axis >= len(shape):
+                    raise oefmt(space.w_IndexError, "Wrong axis %d", axis)
+                arr_iter = AllButAxisIter(arr, axis)
+                arr_state = arr_iter.reset()
+                index_impl = index_arr.implementation
+                index_iter = AllButAxisIter(index_impl, axis)
+                index_state = index_iter.reset()
+                stride_size = arr.strides[axis]
+                index_stride_size = index_impl.strides[axis]
+                axis_size = arr.shape[axis]
+                while not arr_iter.done(arr_state):
+                    for i in range(axis_size):
+                        raw_storage_setitem(storage, i * index_stride_size +
+                                            index_state.offset, i)
+                    r = Repr(index_stride_size, stride_size, axis_size,
+                         arr_storage, storage, index_state.offset, arr_state.offset)
+                    ArgSort(r).sort()
+                    arr_state = arr_iter.next(arr_state)
+                    index_state = index_iter.next(index_state)
+            return index_arr
 
     return argsort
 
@@ -282,25 +282,25 @@
             axis = -1
         else:
             axis = space.int_w(w_axis)
-        # create array of indexes
-        if len(arr.get_shape()) == 1:
-            r = Repr(itemsize, arr.get_size(), arr.get_storage(),
-                     arr.start)
-            ArgSort(r).sort()
-        else:
-            shape = arr.get_shape()
-            if axis < 0:
-                axis = len(shape) + axis
-            if axis < 0 or axis >= len(shape):
-                raise oefmt(space.w_IndexError, "Wrong axis %d", axis)
-            arr_iter = AllButAxisIter(arr, axis)
-            arr_state = arr_iter.reset()
-            stride_size = arr.strides[axis]
-            axis_size = arr.shape[axis]
-            while not arr_iter.done(arr_state):
-                r = Repr(stride_size, axis_size, arr.get_storage(), arr_state.offset)
+        with arr as storage:
+            if len(arr.get_shape()) == 1:
+                r = Repr(itemsize, arr.get_size(), storage,
+                         arr.start)
                 ArgSort(r).sort()
-                arr_state = arr_iter.next(arr_state)
+            else:
+                shape = arr.get_shape()
+                if axis < 0:
+                    axis = len(shape) + axis
+                if axis < 0 or axis >= len(shape):
+                    raise oefmt(space.w_IndexError, "Wrong axis %d", axis)
+                arr_iter = AllButAxisIter(arr, axis)
+                arr_state = arr_iter.reset()
+                stride_size = arr.strides[axis]
+                axis_size = arr.shape[axis]
+                while not arr_iter.done(arr_state):
+                    r = Repr(stride_size, axis_size, storage, arr_state.offset)
+                    ArgSort(r).sort()
+                    arr_state = arr_iter.next(arr_state)
 
     return sort
 
diff --git a/pypy/module/micronumpy/support.py b/pypy/module/micronumpy/support.py
--- a/pypy/module/micronumpy/support.py
+++ b/pypy/module/micronumpy/support.py
@@ -1,6 +1,7 @@
 from pypy.interpreter.error import OperationError, oefmt
 from rpython.rlib import jit
 from rpython.rlib.rarithmetic import ovfcheck
+from rpython.rtyper.lltypesystem import rffi, lltype
 
 
 def issequence_w(space, w_obj):
@@ -147,3 +148,7 @@
     if cur_core_dim == 0:
         ufunc.core_enabled = False
     return 0 # for historical reasons, any failures will raise
+
+def get_storage_as_int(storage, start=0):
+        return rffi.cast(lltype.Signed, storage) + start
+
diff --git a/pypy/module/micronumpy/test/test_subtype.py b/pypy/module/micronumpy/test/test_subtype.py
--- a/pypy/module/micronumpy/test/test_subtype.py
+++ b/pypy/module/micronumpy/test/test_subtype.py
@@ -2,7 +2,7 @@
 
 
 class AppTestSupport(BaseNumpyAppTest):
-    spaceconfig = dict(usemodules=["micronumpy", "struct", "binascii"])
+    spaceconfig = dict(usemodules=["micronumpy", "struct", "binascii", "mmap"])
 
     def setup_class(cls):
         BaseNumpyAppTest.setup_class.im_func(cls)
@@ -476,3 +476,120 @@
         a = self.SubType(array([[1, 2], [3, 4]]))
         b = array(a, subok=False)
         assert type(b) is ndarray
+    
+    def test_numpypy_mmap(self):
+        # issue #21 on pypy/numpy 
+        from numpy import array, ndarray, arange, dtype as dtypedescr
+        import mmap
+        import os.path
+        from tempfile import mkdtemp
+        import os.path as path
+        valid_filemodes = ["r", "c", "r+", "w+"]
+        writeable_filemodes = ["r+", "w+"]
+        mode_equivalents = {
+            "readonly":"r",
+            "copyonwrite":"c",
+            "readwrite":"r+",
+            "write":"w+"
+            }
+
+        class memmap(ndarray):
+            def __new__(subtype, filename, dtype='uint8', mode='r+', offset=0, shape=None, order='C'):
+                # Import here to minimize 'import numpy' overhead
+                try:
+                    mode = mode_equivalents[mode]
+                except KeyError:
+                    if mode not in valid_filemodes:
+                        raise ValueError("mode must be one of %s" %
+                                         (valid_filemodes + list(mode_equivalents.keys())))
+
+                if hasattr(filename, 'read'):
+                    fid = filename
+                    own_file = False
+                else:
+                    fid = open(filename, (mode == 'c' and 'r' or mode)+'b')
+                    own_file = True
+
+                if (mode == 'w+') and shape is None:
+                    raise ValueError("shape must be given")
+
+                fid.seek(0, 2)
+                flen = fid.tell()
+                descr = dtypedescr(dtype)
+                _dbytes = descr.itemsize
+
+                if shape is None:
+                    bytes = flen - offset
+                    if (bytes % _dbytes):
+                        fid.close()
+                        raise ValueError("Size of available data is not a "
+                                "multiple of the data-type size.")
+                    size = bytes // _dbytes
+                    shape = (size,)
+                else:
+                    if not isinstance(shape, tuple):
+                        shape = (shape,)
+                    size = 1
+                    for k in shape:
+                        size *= k
+
+                bytes = long(offset + size*_dbytes)
+
+                if mode == 'w+' or (mode == 'r+' and flen < bytes):
+                    fid.seek(bytes - 1, 0)
+                    fid.write('\0')
+                    fid.flush()
+
+                if mode == 'c':
+                    acc = mmap.ACCESS_COPY
+                elif mode == 'r':
+                    acc = mmap.ACCESS_READ
+                else:
+                    acc = mmap.ACCESS_WRITE
+
+                start = offset - offset % mmap.ALLOCATIONGRANULARITY
+                bytes -= start
+                offset -= start
+                mm = mmap.mmap(fid.fileno(), bytes, access=acc, offset=start)
+
+                self = ndarray.__new__(subtype, shape, dtype=descr, buffer=mm,
+                    offset=offset, order=order)
+                self._mmap = mm
+                self.offset = offset
+                self.mode = mode
+
+                if isinstance(filename, basestring):
+                    self.filename = os.path.abspath(filename)
+                # py3 returns int for TemporaryFile().name
+                elif (hasattr(filename, "name") and
+                      isinstance(filename.name, basestring)):
+                    self.filename = os.path.abspath(filename.name)
+                # same as memmap copies (e.g. memmap + 1)
+                else:
+                    self.filename = None
+
+                if own_file:
+                    fid.close()
+
+                return self
+
+            def flush(self):
+                if self.base is not None and hasattr(self.base, 'flush'):
+                    self.base.flush() 
+
+        def asarray(obj, itemsize=None, order=None):
+            return array(obj, itemsize, copy=False, order=order)
+
+        filename = path.join(mkdtemp(), 'newfile.dat')
+        data = arange(10*10*36).reshape(10, 10, 36)
+        fp = memmap(filename, dtype='float32', mode='w+', shape=data.shape)
+        vals = [   242,    507,    255,    505,    315,    316,    308,    506,
+          309,    255,    211,    505,    315,    316,    308,    506,
+          309,    255,    255,    711,    194,    232,    711,    711,
+          709,    710,    709,    710,    882,    897,    711,    245,
+          711,    711,    168,    245]
+        fp[:] = data
+        fp[5:6][:,4] = vals
+        a = asarray(fp[5:6][:,4])
+        assert (a == vals).all()
+
diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py
--- a/pypy/module/micronumpy/test/test_zjit.py
+++ b/pypy/module/micronumpy/test/test_zjit.py
@@ -238,15 +238,15 @@
             'getfield_gc': 5,
             'getfield_gc_pure': 51,
             'guard_class': 3,
-            'guard_false': 13,
+            'guard_false': 12,
             'guard_nonnull': 11,
             'guard_nonnull_class': 3,
             'guard_not_invalidated': 2,
             'guard_true': 10,
-            'guard_value': 5,
+            'guard_value': 6,
             'int_add': 13,
             'int_ge': 4,
-            'int_is_true': 4,
+            'int_is_true': 3,
             'int_is_zero': 4,
             'int_le': 2,
             'int_lt': 3,
@@ -616,15 +616,15 @@
             'getfield_gc': 6,
             'getfield_gc_pure': 63,
             'guard_class': 5,
-            'guard_false': 20,
+            'guard_false': 19,
             'guard_nonnull': 6,
             'guard_nonnull_class': 1,
             'guard_not_invalidated': 3,
             'guard_true': 16,
-            'guard_value': 2,
+            'guard_value': 3,
             'int_add': 24,
             'int_ge': 4,
-            'int_is_true': 6,
+            'int_is_true': 5,
             'int_is_zero': 4,
             'int_le': 5,
             'int_lt': 7,
diff --git a/pypy/module/micronumpy/types.py b/pypy/module/micronumpy/types.py
--- a/pypy/module/micronumpy/types.py
+++ b/pypy/module/micronumpy/types.py
@@ -185,13 +185,16 @@
         raw_storage_setitem_unaligned(storage, i + offset, value)
 
     def read(self, arr, i, offset, dtype=None):
-        return self.box(self._read(arr.storage, i, offset))
+        with arr as storage:
+            return self.box(self._read(storage, i, offset))
 
     def read_bool(self, arr, i, offset):
-        return bool(self.for_computation(self._read(arr.storage, i, offset)))
+        with arr as storage:
+            return bool(self.for_computation(self._read(storage, i, offset)))
 
     def store(self, arr, i, offset, box):
-        self._write(arr.storage, i, offset, self.unbox(box))
+        with arr as storage:
+            self._write(storage, i, offset, self.unbox(box))
 
     def fill(self, storage, width, box, start, stop, offset):
         value = self.unbox(box)
@@ -1085,8 +1088,9 @@
         return bool(real) or bool(imag)
 
     def read_bool(self, arr, i, offset):
-        v = self.for_computation(self._read(arr.storage, i, offset))
-        return bool(v[0]) or bool(v[1])
+        with arr as storage:
+            v = self.for_computation(self._read(storage, i, offset))
+            return bool(v[0]) or bool(v[1])
 
     def get_element_size(self):
         return 2 * rffi.sizeof(self.T)
@@ -1137,8 +1141,9 @@
         return real, imag
 
     def read(self, arr, i, offset, dtype=None):
-        real, imag = self._read(arr.storage, i, offset)
-        return self.box_complex(real, imag)
+        with arr as storage:
+            real, imag = self._read(storage, i, offset)
+            return self.box_complex(real, imag)
 
     def _write(self, storage, i, offset, value):
         real, imag = value
@@ -1149,7 +1154,8 @@
         raw_storage_setitem_unaligned(storage, i + offset + rffi.sizeof(self.T), imag)
 
     def store(self, arr, i, offset, box):
-        self._write(arr.storage, i, offset, self.unbox(box))
+        with arr as storage:
+            self._write(storage, i, offset, self.unbox(box))
 
     def fill(self, storage, width, box, start, stop, offset):
         value = self.unbox(box)
@@ -1722,13 +1728,14 @@
         assert isinstance(item, boxes.W_FlexibleBox)
         i = item.ofs
         end = i + item.dtype.elsize
-        while i < end:
-            assert isinstance(item.arr.storage[i], str)
-            if item.arr.storage[i] == '\x00':
-                break
-            builder.append(item.arr.storage[i])
-            i += 1
-        return builder.build()
+        with item.arr as storage:
+            while i < end:
+                assert isinstance(storage[i], str)
+                if storage[i] == '\x00':
+                    break
+                builder.append(storage[i])
+                i += 1
+            return builder.build()
 
 def str_unary_op(func):
     specialize.argtype(1)(func)
@@ -1758,23 +1765,26 @@
             w_item = space.wrap('')
         arg = space.str_w(space.str(w_item))
         arr = VoidBoxStorage(dtype.elsize, dtype)
-        j = min(len(arg), dtype.elsize)
-        for i in range(j):
-            arr.storage[i] = arg[i]
-        for j in range(j, dtype.elsize):
-            arr.storage[j] = '\x00'
-        return boxes.W_StringBox(arr,  0, arr.dtype)
+        with arr as storage:
+            j = min(len(arg), dtype.elsize)
+            for i in range(j):
+                storage[i] = arg[i]
+            for j in range(j, dtype.elsize):
+                storage[j] = '\x00'
+            return boxes.W_StringBox(arr,  0, arr.dtype)
 
     def store(self, arr, i, offset, box):
         assert isinstance(box, boxes.W_StringBox)
         size = min(arr.dtype.elsize - offset, box.arr.size - box.ofs)
-        return self._store(arr.storage, i, offset, box, size)
+        with arr as storage:
+            return self._store(storage, i, offset, box, size)
 
     @jit.unroll_safe
     def _store(self, storage, i, offset, box, size):
         assert isinstance(box, boxes.W_StringBox)
-        for k in range(size):
-            storage[k + offset + i] = box.arr.storage[k + box.ofs]
+        with box.arr as box_storage:
+            for k in range(size):
+                storage[k + offset + i] = box_storage[k + box.ofs]
 
     def read(self, arr, i, offset, dtype=None):
         if dtype is None:
@@ -1891,8 +1901,9 @@
         assert i == 0
         assert isinstance(box, boxes.W_VoidBox)
         assert box.dtype is box.arr.dtype
-        for k in range(box.arr.dtype.elsize):
-            arr.storage[k + ofs] = box.arr.storage[k + box.ofs]
+        with arr as arr_storage, box.arr as box_storage:
+            for k in range(box.arr.dtype.elsize):
+                arr_storage[k + ofs] = box_storage[k + box.ofs]
 
     def readarray(self, arr, i, offset, dtype=None):
         from pypy.module.micronumpy.base import W_NDimArray
@@ -1982,12 +1993,14 @@
 
     def store(self, arr, i, ofs, box):
         assert isinstance(box, boxes.W_VoidBox)
-        self._store(arr.storage, i, ofs, box, box.dtype.elsize)
+        with arr as storage:
+            self._store(storage, i, ofs, box, box.dtype.elsize)
 
     @jit.unroll_safe
     def _store(self, storage, i, ofs, box, size):
-        for k in range(size):
-            storage[k + i + ofs] = box.arr.storage[k + box.ofs]
+        with box.arr as box_storage:
+            for k in range(size):
+                storage[k + i + ofs] = box_storage[k + box.ofs]
 
     def fill(self, storage, width, box, start, stop, offset):
         assert isinstance(box, boxes.W_VoidBox)
@@ -2033,9 +2046,10 @@
         s1 = v1.dtype.elsize
         s2 = v2.dtype.elsize
         assert s1 == s2
-        for i in range(s1):
-            if v1.arr.storage[v1.ofs + i] != v2.arr.storage[v2.ofs + i]:
-                return False
+        with v1.arr as v1_storage, v2.arr as v2_storage:
+            for i in range(s1):
+                if v1_storage[v1.ofs + i] != v2_storage[v2.ofs + i]:
+                    return False
         return True
 
     def ne(self, v1, v2):
diff --git a/pypy/module/micronumpy/ufuncs.py b/pypy/module/micronumpy/ufuncs.py
--- a/pypy/module/micronumpy/ufuncs.py
+++ b/pypy/module/micronumpy/ufuncs.py
@@ -13,11 +13,12 @@
 from pypy.module.micronumpy.ctors import numpify
 from pypy.module.micronumpy.nditer import W_NDIter, coalesce_iter
 from pypy.module.micronumpy.strides import shape_agreement
-from pypy.module.micronumpy.support import _parse_signature, product
+from pypy.module.micronumpy.support import _parse_signature, product, get_storage_as_int
 from rpython.rlib.rawstorage import (raw_storage_setitem, free_raw_storage,
              alloc_raw_storage)
 from rpython.rtyper.lltypesystem import rffi, lltype
 from rpython.rlib.rarithmetic import LONG_BIT, _get_bitsize
+from rpython.rlib.objectmodel import keepalive_until_here
 
 
 def done_if_true(dtype, val):
@@ -98,7 +99,9 @@
         if out is not None and not isinstance(out, W_NDimArray):
             raise OperationError(space.w_TypeError, space.wrap(
                                             'output must be an array'))
-        return self.call(space, args_w, sig, casting, extobj)
+        retval = self.call(space, args_w, sig, casting, extobj)
+        keepalive_until_here(args_w)
+        return retval
 
     def descr_accumulate(self, space, w_obj, w_axis=None, w_dtype=None, w_out=None):
         if space.is_none(w_axis):
@@ -806,11 +809,12 @@
             assert isinstance(curarg, W_NDimArray)
             if len(arg_shapes[i]) != curarg.ndims():
                 # reshape
+                
                 sz = product(curarg.get_shape()) * curarg.get_dtype().elsize
-                inargs[i] = W_NDimArray.from_shape_and_storage(
-                    space, arg_shapes[i], curarg.implementation.storage,
-                    curarg.get_dtype(), storage_bytes=sz, w_base=curarg)
-                pass
+                with curarg.implementation as storage:
+                    inargs[i] = W_NDimArray.from_shape_and_storage(
+                        space, arg_shapes[i], storage,
+                        curarg.get_dtype(), storage_bytes=sz, w_base=curarg)
             need_to_cast.append(curarg.get_dtype() != dtypes[i])
         for i in range(len(outargs)):
             j = self.nin + i
@@ -821,9 +825,10 @@
             elif len(arg_shapes[i]) != curarg.ndims():
                 # reshape
                 sz = product(curarg.get_shape()) * curarg.get_dtype().elsize
-                outargs[i] = W_NDimArray.from_shape_and_storage(
-                    space, arg_shapes[i], curarg.implementation.storage,
-                    curarg.get_dtype(), storage_bytes=sz, w_base=curarg)
+                with curarg.implementation as storage:
+                    outargs[i] = W_NDimArray.from_shape_and_storage(
+                        space, arg_shapes[i], storage,
+                        curarg.get_dtype(), storage_bytes=sz, w_base=curarg)
                 curarg = outargs[i]
             assert isinstance(curarg, W_NDimArray)
             need_to_cast.append(curarg.get_dtype() != dtypes[j])
@@ -1414,8 +1419,9 @@
                     raise OperationError(space.w_NotImplementedError,
                          space.wrap("cannot mix ndarray and %r (arg %d) in call to ufunc" % (
                                     arg_i, i)))
-                raw_storage_setitem(dataps, CCHARP_SIZE * i,
-                        rffi.cast(rffi.CCHARP, arg_i.implementation.get_storage_as_int(space)))
+                with arg_i.implementation as storage:
+                    addr = get_storage_as_int(storage, arg_i.get_start())
+                    raw_storage_setitem(dataps, CCHARP_SIZE * i, rffi.cast(rffi.CCHARP, addr))
                 #This assumes we iterate over the whole array (it should be a view...)
                 raw_storage_setitem(self.dims, LONG_SIZE * i, rffi.cast(rffi.LONG, arg_i.get_size()))
                 raw_storage_setitem(self.steps, LONG_SIZE * i, rffi.cast(rffi.LONG, arg_i.get_dtype().elsize))
@@ -1423,8 +1429,9 @@
             for i in range(len(args_w)):
                 arg_i = args_w[i]
                 assert isinstance(arg_i, W_NDimArray)
-                raw_storage_setitem(dataps, CCHARP_SIZE * i,
-                        rffi.cast(rffi.CCHARP, arg_i.implementation.get_storage_as_int(space)))
+                with arg_i.implementation as storage:
+                    addr = get_storage_as_int(storage, arg_i.get_start())
+                raw_storage_setitem(dataps, CCHARP_SIZE * i, rffi.cast(rffi.CCHARP, addr))
         try:
             arg1 = rffi.cast(rffi.CArrayPtr(rffi.CCHARP), dataps)
             arg2 = rffi.cast(npy_intpp, self.dims)
@@ -1432,6 +1439,7 @@
             self.func(arg1, arg2, arg3, self.data)
         finally:
             free_raw_storage(dataps, track_allocation=False)
+        keepalive_until_here(args_w)
 
     def set_dims_and_steps(self, space, dims, steps):
         if not isinstance(dims, list) or not isinstance(steps, list):
diff --git a/pypy/module/mmap/interp_mmap.py b/pypy/module/mmap/interp_mmap.py
--- a/pypy/module/mmap/interp_mmap.py
+++ b/pypy/module/mmap/interp_mmap.py
@@ -22,6 +22,10 @@
         self.check_valid()
         return MMapBuffer(self.space, self.mmap, True)
 
+    def writebuf_w(self, space):
+        self.check_writeable()
+        return MMapBuffer(self.space, self.mmap, False)
+
     def close(self):
         self.mmap.close()
 
diff --git a/pypy/module/pypyjit/test_pypy_c/test_ffi.py b/pypy/module/pypyjit/test_pypy_c/test_ffi.py
--- a/pypy/module/pypyjit/test_pypy_c/test_ffi.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_ffi.py
@@ -341,7 +341,7 @@
         raw_store(i119, 0, i160, descr=<ArrayS 2>)
         raw_store(i119, 2, i160, descr=<ArrayS 2>)
         raw_store(i119, 4, i160, descr=<ArrayS 2>)
-        setfield_gc(p167, i119, descr=<FieldU pypy.module._cffi_backend.cdataobj.W_CData.inst__cdata .+>)
+        setfield_gc(p167, i119, descr=<FieldU pypy.module._cffi_backend.cdataobj.W_CData.inst__ptr .+>)
         i123 = arraylen_gc(p67, descr=<ArrayP .>)
         jump(..., descr=...)
         """)
diff --git a/pypy/module/sys/test/test_sysmodule.py b/pypy/module/sys/test/test_sysmodule.py
--- a/pypy/module/sys/test/test_sysmodule.py
+++ b/pypy/module/sys/test/test_sysmodule.py
@@ -521,9 +521,11 @@
 
     def test_reload_doesnt_override_sys_executable(self):
         import sys
-        sys.executable = 'from_test_sysmodule'
+        if not hasattr(sys, 'executable'):    # if not translated
+            sys.executable = 'from_test_sysmodule'
+        previous = sys.executable
         reload(sys)
-        assert sys.executable == 'from_test_sysmodule'
+        assert sys.executable == previous
 
     def test_settrace(self):
         import sys
diff --git a/rpython/annotator/annrpython.py b/rpython/annotator/annrpython.py
--- a/rpython/annotator/annrpython.py
+++ b/rpython/annotator/annrpython.py
@@ -6,8 +6,8 @@
 from rpython.tool.pairtype import pair
 from rpython.tool.error import (format_blocked_annotation_error,
                              gather_error, source_lines)
-from rpython.flowspace.model import (Variable, Constant, FunctionGraph,
-                                      c_last_exception, checkgraph)
+from rpython.flowspace.model import (
+    Variable, Constant, FunctionGraph, checkgraph)
 from rpython.translator import simplify, transform
 from rpython.annotator import model as annmodel, signature
 from rpython.annotator.argument import simple_args
@@ -407,8 +407,7 @@
                     self.bookkeeper.leave()
 
         except BlockedInference as e:
-            if (e.op is block.operations[-1] and
-                block.exitswitch == c_last_exception):
+            if e.op is block.raising_op:
                 # this is the case where the last operation of the block will
                 # always raise an exception which is immediately caught by
                 # an exception handler.  We then only follow the exceptional
@@ -450,8 +449,8 @@
 
         # filter out those exceptions which cannot
         # occour for this specific, typed operation.
-        if block.exitswitch == c_last_exception:
-            op = block.operations[-1]
+        if block.canraise:
+            op = block.raising_op


More information about the pypy-commit mailing list