[pypy-commit] pypy fast-newarray: merge default

fijal noreply at buildbot.pypy.org
Mon Apr 15 17:52:10 CEST 2013


Author: Maciej Fijalkowski <fijall at gmail.com>
Branch: fast-newarray
Changeset: r63373:5c9cbab255ac
Date: 2013-04-15 17:51 +0200
http://bitbucket.org/pypy/pypy/changeset/5c9cbab255ac/

Log:	merge default

diff too long, truncating to 2000 out of 2634 lines

diff --git a/lib_pypy/_pypy_interact.py b/lib_pypy/_pypy_interact.py
--- a/lib_pypy/_pypy_interact.py
+++ b/lib_pypy/_pypy_interact.py
@@ -44,7 +44,7 @@
     import code
     if mainmodule is None:
         import __main__ as mainmodule
-    console = code.InteractiveConsole(mainmodule.__dict__)
+    console = code.InteractiveConsole(mainmodule.__dict__, filename='<stdin>')
     # some parts of code.py are copied here because it seems to be impossible
     # to start an interactive console without printing at least one line
     # of banner
diff --git a/lib_pypy/pyrepl/python_reader.py b/lib_pypy/pyrepl/python_reader.py
--- a/lib_pypy/pyrepl/python_reader.py
+++ b/lib_pypy/pyrepl/python_reader.py
@@ -171,11 +171,11 @@
 
     def execute(self, text):
         try:
-            # ooh, look at the hack:            
+            # ooh, look at the hack:
             code = self.compile("# coding:utf8\n"+text.encode('utf-8'),
-                                '<input>', 'single')
+                                '<stdin>', 'single')
         except (OverflowError, SyntaxError, ValueError):
-            self.showsyntaxerror("<input>")
+            self.showsyntaxerror('<stdin>')
         else:
             self.runcode(code)
             if sys.stdout and not sys.stdout.closed:
diff --git a/lib_pypy/pyrepl/simple_interact.py b/lib_pypy/pyrepl/simple_interact.py
--- a/lib_pypy/pyrepl/simple_interact.py
+++ b/lib_pypy/pyrepl/simple_interact.py
@@ -37,13 +37,13 @@
     import code
     if mainmodule is None:
         import __main__ as mainmodule
-    console = code.InteractiveConsole(mainmodule.__dict__)
+    console = code.InteractiveConsole(mainmodule.__dict__, filename='<stdin>')
 
     def more_lines(unicodetext):
         # ooh, look at the hack:
         src = "#coding:utf-8\n"+unicodetext.encode('utf-8')
         try:
-            code = console.compile(src, '<input>', 'single')
+            code = console.compile(src, '<stdin>', 'single')
         except (OverflowError, SyntaxError, ValueError):
             return False
         else:
diff --git a/pypy/doc/index.rst b/pypy/doc/index.rst
--- a/pypy/doc/index.rst
+++ b/pypy/doc/index.rst
@@ -31,6 +31,7 @@
 .. _`Starting with RPython`: getting-started-dev.html
 .. _`how to contribute`: how-to-contribute.html
 .. _`PyPy website`: http://pypy.org
+.. _`LICENSE`: https://bitbucket.org/pypy/pypy/src/default/LICENSE
 
 Index of various topics:
 ========================
@@ -66,11 +67,9 @@
   * `Sandboxing Python code`_
   * `Garbage collection environment variables`_
 
-Status_ of the project.
-
 .. _`Differences between PyPy and CPython`: cpython_differences.html
 .. _`What PyPy can do for your objects`: objspace-proxies.html
-.. _`Continulets and greenlets_`: stackless.html
+.. _`Continulets and greenlets`: stackless.html
 .. _`JIT Generation in PyPy`: jit/index.html
 .. _`JIT hooks`: jit-hooks.html
 .. _`Sandboxing Python code`: sandbox.html
diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst
--- a/pypy/doc/whatsnew-head.rst
+++ b/pypy/doc/whatsnew-head.rst
@@ -50,6 +50,9 @@
 JIT optimizations which makes cffi calls even faster, by removing the need to
 allocate a temporary buffer where to store the arguments.
 
+.. branch: improve-docs-2
+Improve documents and straighten out links
+
 .. branches we don't care about
 .. branch: autoreds
 .. branch: reflex-support
diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py
--- a/pypy/interpreter/pyopcode.py
+++ b/pypy/interpreter/pyopcode.py
@@ -255,19 +255,7 @@
                                              "code=%d, name=%s" %
                                              (self.last_instr, opcode,
                                               methodname))
-                try:
-                    res = meth(oparg, next_instr)
-                except Exception:
-                    if 0:
-                        import dis, sys
-                        print "*** %s at offset %d (%s)" % (sys.exc_info()[0],
-                                                            self.last_instr,
-                                                            methodname)
-                        try:
-                            dis.dis(co_code)
-                        except:
-                            pass
-                    raise
+                res = meth(oparg, next_instr)
                 if res is not None:
                     next_instr = res
 
diff --git a/pypy/module/__pypy__/test/test_signal.py b/pypy/module/__pypy__/test/test_signal.py
--- a/pypy/module/__pypy__/test/test_signal.py
+++ b/pypy/module/__pypy__/test/test_signal.py
@@ -47,8 +47,9 @@
             try:
                 done = []
                 interrupted = []
+                print 'starting',i
                 thread.start_new_thread(subthread, ())
-                for i in range(10):
+                for j in range(10):
                     if len(done): break
                     print '.'
                     time.sleep(0.1)
diff --git a/pypy/module/_io/interp_bytesio.py b/pypy/module/_io/interp_bytesio.py
--- a/pypy/module/_io/interp_bytesio.py
+++ b/pypy/module/_io/interp_bytesio.py
@@ -2,37 +2,26 @@
     TypeDef, generic_new_descr, GetSetProperty)
 from pypy.interpreter.gateway import interp2app, unwrap_spec
 from pypy.interpreter.error import OperationError, operationerrfmt
+from rpython.rlib.rStringIO import RStringIO
 from rpython.rlib.rarithmetic import r_longlong
 from pypy.module._io.interp_bufferedio import W_BufferedIOBase
 from pypy.module._io.interp_iobase import convert_size
 import sys
 
-def buffer2string(buffer, start, end):
-    from rpython.rlib.rstring import StringBuilder
-    builder = StringBuilder(end - start)
-    for i in range(start, end):
-        builder.append(buffer[i])
-    return builder.build()
 
-class W_BytesIO(W_BufferedIOBase):
+class W_BytesIO(RStringIO, W_BufferedIOBase):
     def __init__(self, space):
         W_BufferedIOBase.__init__(self, space)
-        self.pos = 0
-        self.string_size = 0
-        self.buf = None
+        self.init()
 
     def descr_init(self, space, w_initial_bytes=None):
-        # In case __init__ is called multiple times
-        self.buf = []
-        self.string_size = 0
-        self.pos = 0
-
+        self.init()
         if not space.is_none(w_initial_bytes):
             self.write_w(space, w_initial_bytes)
-            self.pos = 0
+            self.seek(0)
 
     def _check_closed(self, space, message=None):
-        if self.buf is None:
+        if self.is_closed():
             if message is None:
                 message = "I/O operation on closed file"
             raise OperationError(space.w_ValueError, space.wrap(message))
@@ -40,36 +29,12 @@
     def read_w(self, space, w_size=None):
         self._check_closed(space)
         size = convert_size(space, w_size)
-
-        # adjust invalid sizes
-        available = self.string_size - self.pos
-        if not 0 <= size <= available:
-            size = available
-            if size < 0:
-                size = 0
-
-        output = buffer2string(self.buf, self.pos, self.pos + size)
-        self.pos += size
-        return space.wrap(output)
+        return space.wrap(self.read(size))
 
     def readline_w(self, space, w_limit=None):
         self._check_closed(space)
         limit = convert_size(space, w_limit)
-
-        cur_pos = self.pos
-        if limit < 0:
-            end_pos = self.string_size
-        else:
-            end_pos = min(cur_pos + limit, self.string_size)
-        while cur_pos != end_pos:
-            if self.buf[cur_pos] == '\n':
-                cur_pos += 1
-                break
-            cur_pos += 1
-
-        output = buffer2string(self.buf, self.pos, cur_pos)
-        self.pos = cur_pos
-        return space.wrap(output)
+        return space.wrap(self.readline(limit))
 
     def read1_w(self, space, w_size):
         return self.read_w(space, w_size)
@@ -79,56 +44,28 @@
         rwbuffer = space.rwbuffer_w(w_buffer)
         size = rwbuffer.getlength()
 
-        if self.pos + size > self.string_size:
-            size = self.string_size - self.pos
-
-        output = buffer2string(self.buf, self.pos, self.pos + size)
-        length = len(output)
+        output = self.read(size)
         rwbuffer.setslice(0, output)
-        self.pos += length
-        return space.wrap(length)
+        return space.wrap(len(output))
 
     def write_w(self, space, w_data):
         self._check_closed(space)
         if space.isinstance_w(w_data, space.w_unicode):
             raise OperationError(space.w_TypeError, space.wrap(
                 "bytes string of buffer expected"))
-        buf = space.buffer_w(w_data)
-        length = buf.getlength()
+        buf = space.bufferstr_w(w_data)
+        length = len(buf)
         if length <= 0:
-            return
-
-        if self.pos + length > len(self.buf):
-            self.buf.extend(['\0'] * (self.pos + length - len(self.buf)))
-
-        if self.pos > self.string_size:
-            # In case of overseek, pad with null bytes the buffer region
-            # between the end of stream and the current position.
-            #
-            # 0   lo      string_size                           hi
-            # |   |<---used--->|<----------available----------->|
-            # |   |            <--to pad-->|<---to write--->    |
-            # 0   buf                   position
-            for i in range(self.string_size, self.pos):
-                self.buf[i] = '\0'
-
-        # Copy the data to the internal buffer, overwriting some of the
-        # existing data if self->pos < self->string_size.
-        for i in range(length):
-            self.buf[self.pos + i] = buf.getitem(i)
-        self.pos += length
-
-        # Set the new length of the internal string if it has changed
-        if self.string_size < self.pos:
-            self.string_size = self.pos
-
+            return space.wrap(0)
+        self.write(buf)
         return space.wrap(length)
 
     def truncate_w(self, space, w_size=None):
         self._check_closed(space)
 
+        pos = self.tell()
         if space.is_none(w_size):
-            size = self.pos
+            size = pos
         else:
             size = space.r_longlong_w(w_size)
 
@@ -136,19 +73,20 @@
             raise OperationError(space.w_ValueError, space.wrap(
                 "negative size value"))
 
-        if size < self.string_size:
-            self.string_size = size
-            del self.buf[size:]
-
+        self.truncate(size)
+        if size == pos:
+            self.seek(0, 2)
+        else:
+            self.seek(pos)
         return space.wrap(size)
 
     def getvalue_w(self, space):
         self._check_closed(space)
-        return space.wrap(buffer2string(self.buf, 0, self.string_size))
+        return space.wrap(self.getvalue())
 
     def tell_w(self, space):
         self._check_closed(space)
-        return space.wrap(self.pos)
+        return space.wrap(self.tell())
 
     @unwrap_spec(pos=r_longlong, whence=int)
     def seek_w(self, space, pos, whence=0):
@@ -159,24 +97,19 @@
                 raise OperationError(space.w_ValueError, space.wrap(
                     "negative seek value"))
         elif whence == 1:
-            if pos > sys.maxint - self.pos:
+            if pos > sys.maxint - self.tell():
                 raise OperationError(space.w_OverflowError, space.wrap(
                     "new position too large"))
-            pos += self.pos
         elif whence == 2:
-            if pos > sys.maxint - self.string_size:
+            if pos > sys.maxint - self.getsize():
                 raise OperationError(space.w_OverflowError, space.wrap(
                     "new position too large"))
-            pos += self.string_size
         else:
             raise operationerrfmt(space.w_ValueError,
                 "whence must be between 0 and 2, not %d", whence)
 
-        if pos >= 0:
-            self.pos = pos
-        else:
-            self.pos = 0
-        return space.wrap(self.pos)
+        self.seek(pos, whence)
+        return space.wrap(self.tell())
 
     def readable_w(self, space):
         return space.w_True
@@ -188,17 +121,16 @@
         return space.w_True
 
     def close_w(self, space):
-        self.buf = None
+        self.close()
 
     def closed_get_w(self, space):
-        return space.wrap(self.buf is None)
+        return space.wrap(self.is_closed())
 
     def getstate_w(self, space):
         self._check_closed(space)
-        w_content = space.wrap(buffer2string(self.buf, 0, self.string_size))
         return space.newtuple([
-            w_content,
-            space.wrap(self.pos),
+            space.wrap(self.getvalue()),
+            space.wrap(self.tell()),
             self.getdict(space)])
 
     def setstate_w(self, space, w_state):
@@ -211,13 +143,13 @@
                 space.type(w_state).getname(space)
             )
         w_content, w_pos, w_dict = space.unpackiterable(w_state, 3)
+        self.truncate(0)
+        self.write_w(space, w_content)
         pos = space.int_w(w_pos)
-        self.buf = []
-        self.write_w(space, w_content)
         if pos < 0:
             raise OperationError(space.w_ValueError, space.wrap(
                 "position value cannot be negative"))
-        self.pos = pos
+        self.seek(pos)
         if not space.is_w(w_dict, space.w_None):
             space.call_method(self.getdict(space), "update", w_dict)
 
diff --git a/pypy/module/_io/interp_stringio.py b/pypy/module/_io/interp_stringio.py
--- a/pypy/module/_io/interp_stringio.py
+++ b/pypy/module/_io/interp_stringio.py
@@ -169,9 +169,9 @@
         self.pos = end
         return space.wrap(u''.join(self.buf[start:end]))
 
-    @unwrap_spec(limit=int)
-    def readline_w(self, space, limit=-1):
+    def readline_w(self, space, w_limit=None):
         self._check_closed(space)
+        limit = convert_size(space, w_limit)
 
         if self.pos >= len(self.buf):
             return space.wrap(u"")
diff --git a/pypy/module/_io/test/test_bytesio.py b/pypy/module/_io/test/test_bytesio.py
--- a/pypy/module/_io/test/test_bytesio.py
+++ b/pypy/module/_io/test/test_bytesio.py
@@ -4,6 +4,15 @@
     def test_init(self):
         import _io
         raises(TypeError, _io.BytesIO, u"12345")
+        buf = "1234567890"
+        b = _io.BytesIO(buf)
+        assert b.getvalue() == buf
+        b = _io.BytesIO(None)
+        assert b.getvalue() == ""
+        b.__init__(buf * 2)
+        assert b.getvalue() == buf * 2
+        b.__init__(buf)
+        assert b.getvalue() == buf
 
     def test_init_kwargs(self):
         import _io
@@ -24,6 +33,7 @@
     def test_write(self):
         import _io
         f = _io.BytesIO()
+        assert f.write("") == 0
         assert f.write("hello") == 5
         import gc; gc.collect()
         assert f.getvalue() == "hello"
@@ -47,10 +57,17 @@
 
     def test_truncate(self):
         import _io
-        f = _io.BytesIO("hello")
+        f = _io.BytesIO()
+        f.write("hello")
+        assert f.truncate(0) == 0
+        assert f.tell() == 5
+        f.seek(0)
+        f.write("hello")
         f.seek(3)
         assert f.truncate() == 3
         assert f.getvalue() == "hel"
+        assert f.truncate(2) == 2
+        assert f.tell() == 3
 
     def test_setstate(self):
         # state is (content, position, __dict__)
@@ -73,7 +90,13 @@
         import _io
 
         b = _io.BytesIO("hello")
+        a1 = bytearray('t')
+        a2 = bytearray('testing')
+        assert b.readinto(a1) == 1
+        assert b.readinto(a2) == 4
         b.close()
+        assert a1 == "h"
+        assert a2 == "elloing"
         raises(ValueError, b.readinto, bytearray("hello"))
 
     def test_readline(self):
diff --git a/pypy/module/_io/test/test_stringio.py b/pypy/module/_io/test/test_stringio.py
--- a/pypy/module/_io/test/test_stringio.py
+++ b/pypy/module/_io/test/test_stringio.py
@@ -32,7 +32,7 @@
         raises(ValueError, sio.read, 1)
         raises(ValueError, sio.write, u"text")
 
-    def testRead(self):
+    def test_read(self):
         import io
         buf = u"1234567890"
         sio = io.StringIO(buf)
@@ -42,6 +42,13 @@
         assert buf[5:] == sio.read(900)
         assert u"" == sio.read()
 
+    def test_readline(self):
+        import io
+        sio = io.StringIO(u'123\n456')
+        assert sio.readline(2) == '12'
+        assert sio.readline(None) == '3\n'
+        assert sio.readline() == '456'
+
     def test_seek(self):
         import io
 
diff --git a/pypy/module/_io/test/test_ztranslation.py b/pypy/module/_io/test/test_ztranslation.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_io/test/test_ztranslation.py
@@ -0,0 +1,4 @@
+from pypy.objspace.fake.checkmodule import checkmodule
+
+def test_checkmodule():
+    checkmodule('_io')
diff --git a/pypy/module/_minimal_curses/__init__.py b/pypy/module/_minimal_curses/__init__.py
--- a/pypy/module/_minimal_curses/__init__.py
+++ b/pypy/module/_minimal_curses/__init__.py
@@ -2,10 +2,12 @@
     import _curses
 except ImportError:
     try:
-        import _minimal_curses as _curses   # when running on top of pypy-c
+        # when running on top of pypy before it had _curses, settle for minimal
+        # we prefer _curses so any constants added make it into _minimal_curses
+        import _minimal_curses as _curses
     except ImportError:
         import py
-        py.test.skip("no _curses or _minimal_curses module") #no _curses at all
+        py.test.skip("no _curses or _minimal_curses module")  # no _curses at all
 
 from pypy.interpreter.mixedmodule import MixedModule
 from pypy.module._minimal_curses import fficurses  # for side effects
diff --git a/pypy/module/cStringIO/interp_stringio.py b/pypy/module/cStringIO/interp_stringio.py
--- a/pypy/module/cStringIO/interp_stringio.py
+++ b/pypy/module/cStringIO/interp_stringio.py
@@ -146,7 +146,7 @@
 
 class W_OutputType(RStringIO, W_InputOutputType):
     def __init__(self, space):
-        RStringIO.__init__(self)
+        self.init()
         self.space = space
 
     def descr_truncate(self, w_size=None):
@@ -159,6 +159,7 @@
         if size < 0:
             raise OperationError(space.w_IOError, space.wrap("negative size"))
         self.truncate(size)
+        self.seek(0, 2)
 
     @unwrap_spec(buffer='bufferstr')
     def descr_write(self, buffer):
diff --git a/pypy/module/cStringIO/test/test_interp_stringio.py b/pypy/module/cStringIO/test/test_interp_stringio.py
--- a/pypy/module/cStringIO/test/test_interp_stringio.py
+++ b/pypy/module/cStringIO/test/test_interp_stringio.py
@@ -142,8 +142,11 @@
         f.write(' world')
         f.truncate(30)
         assert f.getvalue() == '\x00' * 20 + 'hello worl'
+        assert f.tell() == 30
+        f.seek(0)
         f.truncate(25)
         assert f.getvalue() == '\x00' * 20 + 'hello'
+        assert f.tell() == 25
         f.write('baz')
         f.write('egg')
         f.truncate(3)
diff --git a/pypy/module/cpyext/test/test_cpyext.py b/pypy/module/cpyext/test/test_cpyext.py
--- a/pypy/module/cpyext/test/test_cpyext.py
+++ b/pypy/module/cpyext/test/test_cpyext.py
@@ -1,6 +1,6 @@
 import sys
 import weakref
-import os.path
+import os
 
 import py
 
@@ -19,6 +19,21 @@
 from rpython.tool.identity_dict import identity_dict
 from rpython.tool import leakfinder
 
+def setup_module(module):
+    if os.name == 'nt':
+        # Do not open dreaded dialog box on segfault
+        import ctypes
+        SEM_NOGPFAULTERRORBOX = 0x0002 # From MSDN
+        old_err_mode = ctypes.windll.kernel32.GetErrorMode()
+        new_err_mode = old_err_mode | SEM_NOGPFAULTERRORBOX
+        ctypes.windll.kernel32.SetErrorMode(new_err_mode)
+        module.old_err_mode = old_err_mode
+
+def teardown_module(module):
+    if os.name == 'nt':
+        import ctypes
+        ctypes.windll.kernel32.SetErrorMode(module.old_err_mode)
+
 @api.cpython_api([], api.PyObject)
 def PyPy_Crash1(space):
     1/0
diff --git a/pypy/module/micronumpy/interp_dtype.py b/pypy/module/micronumpy/interp_dtype.py
--- a/pypy/module/micronumpy/interp_dtype.py
+++ b/pypy/module/micronumpy/interp_dtype.py
@@ -282,7 +282,10 @@
             return dtype
         if w_dtype is dtype.w_box_type:
             return dtype
-    raise OperationError(space.w_TypeError, space.wrap("data type %r not understood" % w_dtype))
+    typename = space.type(w_dtype).getname(space)
+    raise OperationError(space.w_TypeError, space.wrap(
+                             "data type not understood (value of type " +
+                             "%s not expected here)" % typename))
 
 W_Dtype.typedef = TypeDef("dtype",
     __module__ = "numpypy",
diff --git a/pypy/module/micronumpy/test/test_dtypes.py b/pypy/module/micronumpy/test/test_dtypes.py
--- a/pypy/module/micronumpy/test/test_dtypes.py
+++ b/pypy/module/micronumpy/test/test_dtypes.py
@@ -32,7 +32,8 @@
 
         assert dtype(None) is dtype(float)
 
-        raises(TypeError, dtype, 1042)
+        exc = raises(TypeError, dtype, (1, 2))
+        assert 'data type not understood' in str(exc.value)
         raises(KeyError, 'dtype(int)["asdasd"]')
 
     def test_dtype_eq(self):
diff --git a/pypy/module/thread/os_thread.py b/pypy/module/thread/os_thread.py
--- a/pypy/module/thread/os_thread.py
+++ b/pypy/module/thread/os_thread.py
@@ -132,7 +132,7 @@
             if not e.match(space, space.w_SystemExit):
                 ident = rthread.get_ident()
                 where = 'thread %d started by ' % ident
-                e.write_unraisable(space, where, w_callable)
+                e.write_unraisable(space, where, w_callable, with_traceback=True)
             e.clear(space)
         # clean up space.threadlocals to remove the ExecutionContext
         # entry corresponding to the current thread
diff --git a/pypy/module/thread/test/test_thread.py b/pypy/module/thread/test/test_thread.py
--- a/pypy/module/thread/test/test_thread.py
+++ b/pypy/module/thread/test/test_thread.py
@@ -129,10 +129,10 @@
             sys.stderr = StringIO.StringIO()
             thread.start_new_thread(fn3, ())
             self.waitfor(lambda: "ValueError" in sys.stderr.getvalue())
-            result = sys.stderr.getvalue()
-            assert "ValueError" in result
-            assert "hello world" in result
-            assert len(result.splitlines()) == 1
+            result = sys.stderr.getvalue().splitlines()
+            #assert result[0].startswith("Unhandled exception in thread ")
+            assert result[1].startswith("Traceback ")
+            assert result[-1] == "ValueError: hello world"
         finally:
             sys.stderr = prev
 
diff --git a/pypy/objspace/fake/objspace.py b/pypy/objspace/fake/objspace.py
--- a/pypy/objspace/fake/objspace.py
+++ b/pypy/objspace/fake/objspace.py
@@ -58,6 +58,10 @@
 class W_MyType(W_MyObject):
     def __init__(self):
         self.mro_w = [w_some_obj(), w_some_obj()]
+        self.dict_w = {'__str__': w_some_obj()}
+
+    def get_module(self):
+        return w_some_obj()
 
 def w_some_obj():
     if NonConstant(False):
@@ -318,7 +322,7 @@
                  ObjSpace.ExceptionTable +
                  ['int', 'str', 'float', 'long', 'tuple', 'list',
                   'dict', 'unicode', 'complex', 'slice', 'bool',
-                  'basestring', 'object']):
+                  'basestring', 'object', 'bytearray']):
         setattr(FakeObjSpace, 'w_' + name, w_some_obj())
     FakeObjSpace.w_type = w_some_type()
     #
diff --git a/pypy/objspace/std/test/test_listobject.py b/pypy/objspace/std/test/test_listobject.py
--- a/pypy/objspace/std/test/test_listobject.py
+++ b/pypy/objspace/std/test/test_listobject.py
@@ -1109,7 +1109,7 @@
                 self.i = i
             def __eq__(self, other):
                 if self.i == 9:
-                    del l[i - 1]
+                    del l[self.i - 1]
                     return True
                 else:
                     return False
diff --git a/rpython/jit/backend/arm/assembler.py b/rpython/jit/backend/arm/assembler.py
--- a/rpython/jit/backend/arm/assembler.py
+++ b/rpython/jit/backend/arm/assembler.py
@@ -74,29 +74,6 @@
     def setup_failure_recovery(self):
         self.failure_recovery_code = [0, 0, 0, 0]
 
-    @staticmethod
-    def _release_gil_shadowstack():
-        before = rffi.aroundstate.before
-        if before:
-            before()
-
-    @staticmethod
-    def _reacquire_gil_shadowstack():
-        after = rffi.aroundstate.after
-        if after:
-            after()
-
-    _NOARG_FUNC = lltype.Ptr(lltype.FuncType([], lltype.Void))
-
-    def _build_release_gil(self, gcrootmap):
-        assert gcrootmap.is_shadow_stack
-        releasegil_func = llhelper(self._NOARG_FUNC,
-                                   self._release_gil_shadowstack)
-        reacqgil_func = llhelper(self._NOARG_FUNC,
-                                 self._reacquire_gil_shadowstack)
-        self.releasegil_addr = rffi.cast(lltype.Signed, releasegil_func)
-        self.reacqgil_addr = rffi.cast(lltype.Signed, reacqgil_func)
-
     def _build_propagate_exception_path(self):
         if not self.cpu.propagate_exception_descr:
             return      # not supported (for tests, or non-translated)
@@ -537,7 +514,7 @@
         clt.allgcrefs = []
         clt.frame_info.clear() # for now
 
-        if False and log:
+        if log:
             operations = self._inject_debugging_code(looptoken, operations,
                                                      'e', looptoken.number)
 
@@ -787,13 +764,13 @@
 
         # restore registers
         self._pop_all_regs_from_jitframe(mc, [], self.cpu.supports_floats)
-        mc.POP([r.ip.value, r.pc.value]) # return
+        mc.POP([r.ip.value, r.pc.value])  # return
         self._frame_realloc_slowpath = mc.materialize(self.cpu.asmmemmgr, [])
 
     def _load_shadowstack_top(self, mc, reg, gcrootmap):
         rst = gcrootmap.get_root_stack_top_addr()
         mc.gen_load_int(reg.value, rst)
-        mc.gen_load_int(reg.value, reg.value)
+        self.load_reg(mc, reg, reg)
         return rst
 
     def fixup_target_tokens(self, rawstart):
diff --git a/rpython/jit/backend/arm/opassembler.py b/rpython/jit/backend/arm/opassembler.py
--- a/rpython/jit/backend/arm/opassembler.py
+++ b/rpython/jit/backend/arm/opassembler.py
@@ -352,7 +352,8 @@
 
     def _emit_call(self, adr, arglocs, fcond=c.AL, resloc=None,
                                             result_info=(-1, -1),
-                                            can_collect=1):
+                                            can_collect=1,
+                                            reload_frame=False):
         if self.cpu.hf_abi:
             stack_args, adr = self._setup_call_hf(adr, arglocs, fcond,
                                             resloc, result_info)
@@ -365,7 +366,6 @@
             gcmap = self._regalloc.get_gcmap([r.r0], noregs=noregs)
             self.push_gcmap(self.mc, gcmap, store=True)
         #the actual call
-        #self.mc.BKPT()
         if adr.is_imm():
             self.mc.BL(adr.value)
         elif adr.is_stack():
@@ -388,6 +388,8 @@
         if can_collect:
             self._reload_frame_if_necessary(self.mc, can_collect=can_collect)
             self.pop_gcmap(self.mc)
+        elif reload_frame:
+            self._reload_frame_if_necessary(self.mc)
         return fcond
 
     def _restore_sp(self, stack_args, fcond):
@@ -630,7 +632,9 @@
         # argument the address of the structure we are writing into
         # (the first argument to COND_CALL_GC_WB).
         helper_num = card_marking
-        if self._regalloc is not None and self._regalloc.vfprm.reg_bindings:
+        if is_frame:
+            helper_num = 4
+        elif self._regalloc is not None and self._regalloc.vfprm.reg_bindings:
             helper_num += 2
         if self.wb_slowpath[helper_num] == 0:    # tests only
             assert not we_are_translated()
@@ -1264,7 +1268,11 @@
         resloc = arglocs[0]
 
         if gcrootmap:
-            self.call_release_gil(gcrootmap, arglocs, fcond)
+            noregs = self.cpu.gc_ll_descr.is_shadow_stack()
+            assert noregs
+            gcmap = self._regalloc.get_gcmap([r.r0], noregs=noregs)
+            self.push_gcmap(self.mc, gcmap, store=True)
+            self.call_release_gil(gcrootmap, arglocs, regalloc, fcond)
         # do the call
         self._store_force_index(guard_op)
         #
@@ -1273,42 +1281,40 @@
         signed = descr.is_result_signed()
         #
         self._emit_call(adr, callargs, fcond,
-                                    resloc, (size, signed))
+                                    resloc, (size, signed),
+                                    can_collect=0)
         # then reopen the stack
         if gcrootmap:
-            self.call_reacquire_gil(gcrootmap, resloc, fcond)
+            self.call_reacquire_gil(gcrootmap, resloc, regalloc, fcond)
 
         self._emit_guard_may_force(guard_op, arglocs[numargs+1:], numargs)
         return fcond
 
-    def call_release_gil(self, gcrootmap, save_registers, fcond):
-        # First, we need to save away the registers listed in
-        # 'save_registers' that are not callee-save.
+    def call_release_gil(self, gcrootmap, save_registers, regalloc, fcond):
+        # Save caller saved registers and do the call
         # NOTE: We assume that  the floating point registers won't be modified.
-        regs_to_save = []
-        for reg in self._regalloc.rm.save_around_call_regs:
-            if reg in save_registers:
-                regs_to_save.append(reg)
         assert gcrootmap.is_shadow_stack
-        with saved_registers(self.mc, regs_to_save):
-            self._emit_call(imm(self.releasegil_addr), [], fcond)
+        with saved_registers(self.mc, regalloc.rm.save_around_call_regs):
+            self._emit_call(imm(self.releasegil_addr), [],
+                                        fcond, can_collect=False)
 
-    def call_reacquire_gil(self, gcrootmap, save_loc, fcond):
-        # save the previous result into the stack temporarily.
+    def call_reacquire_gil(self, gcrootmap, save_loc, regalloc, fcond):
+        # save the previous result into the stack temporarily, in case it is in
+        # a caller saved register.
         # NOTE: like with call_release_gil(), we assume that we don't need to
         # save vfp regs in this case. Besides the result location
         regs_to_save = []
         vfp_regs_to_save = []
-        if save_loc.is_reg():
+        if save_loc and save_loc in regalloc.rm.save_around_call_regs:
             regs_to_save.append(save_loc)
-        if save_loc.is_vfp_reg():
+            regs_to_save.append(r.ip)  # for alingment
+        elif save_loc and save_loc in regalloc.vfprm.save_around_call_regs:
             vfp_regs_to_save.append(save_loc)
+        assert gcrootmap.is_shadow_stack
         # call the reopenstack() function (also reacquiring the GIL)
-        if len(regs_to_save) % 2 != 1:
-            regs_to_save.append(r.ip)  # for alingment
-        assert gcrootmap.is_shadow_stack
         with saved_registers(self.mc, regs_to_save, vfp_regs_to_save):
-            self._emit_call(imm(self.reacqgil_addr), [], fcond)
+            self._emit_call(imm(self.reacqgil_addr), [], fcond,
+                    can_collect=False, reload_frame=True)
 
     def _store_force_index(self, guard_op):
         faildescr = guard_op.getdescr()
diff --git a/rpython/jit/backend/arm/regalloc.py b/rpython/jit/backend/arm/regalloc.py
--- a/rpython/jit/backend/arm/regalloc.py
+++ b/rpython/jit/backend/arm/regalloc.py
@@ -554,10 +554,9 @@
         return self._prepare_call(op)
 
     def _prepare_call(self, op, force_store=[], save_all_regs=False):
-        args = []
-        args.append(None)
+        args = [None] * (op.numargs() + 1)
         for i in range(op.numargs()):
-            args.append(self.loc(op.getarg(i)))
+            args[i + 1] = self.loc(op.getarg(i))
         # spill variables that need to be saved around calls
         self.vfprm.before_call(save_all_regs=save_all_regs)
         if not save_all_regs:
diff --git a/rpython/jit/backend/arm/test/test_zrpy_gc.py b/rpython/jit/backend/arm/test/test_zrpy_gc.py
--- a/rpython/jit/backend/arm/test/test_zrpy_gc.py
+++ b/rpython/jit/backend/arm/test/test_zrpy_gc.py
@@ -1,4 +1,8 @@
 from rpython.jit.backend.arm.test.support import skip_unless_run_slow_tests
 skip_unless_run_slow_tests()
 
-from rpython.jit.backend.llsupport.test.zrpy_gc_test import TestShadowStack
+from rpython.jit.backend.llsupport.test.zrpy_gc_test import CompileFrameworkTests
+
+
+class TestShadowStack(CompileFrameworkTests):
+    gcrootfinder = "shadowstack"
diff --git a/rpython/jit/backend/arm/test/test_zrpy_gc_boehm.py b/rpython/jit/backend/arm/test/test_zrpy_gc_boehm.py
--- a/rpython/jit/backend/arm/test/test_zrpy_gc_boehm.py
+++ b/rpython/jit/backend/arm/test/test_zrpy_gc_boehm.py
@@ -1,3 +1,3 @@
 from rpython.jit.backend.arm.test.support import skip_unless_run_slow_tests
 skip_unless_run_slow_tests()
-from rpython.jit.backend.llsupport.test.zrpy_gc_boehm_test import test_compile_boehm
+from rpython.jit.backend.llsupport.test.zrpy_gc_boehm_test import compile_boehm_test as test_compile_boehm
diff --git a/rpython/jit/backend/arm/test/test_zrpy_releasegil.py b/rpython/jit/backend/arm/test/test_zrpy_releasegil.py
--- a/rpython/jit/backend/arm/test/test_zrpy_releasegil.py
+++ b/rpython/jit/backend/arm/test/test_zrpy_releasegil.py
@@ -1,4 +1,10 @@
 from rpython.jit.backend.arm.test.support import skip_unless_run_slow_tests
 skip_unless_run_slow_tests()
 
-from rpython.jit.backend.llsupport.test.zrpy_releasegil_test import TestShadowStack
+from rpython.jit.backend.llsupport.test.zrpy_releasegil_test import ReleaseGILTests
+
+
+class TestShadowStack(ReleaseGILTests):
+    gcrootfinder = "shadowstack"
+
+
diff --git a/rpython/jit/backend/llsupport/assembler.py b/rpython/jit/backend/llsupport/assembler.py
--- a/rpython/jit/backend/llsupport/assembler.py
+++ b/rpython/jit/backend/llsupport/assembler.py
@@ -9,7 +9,7 @@
                                 debug_print)
 from rpython.rlib.rarithmetic import r_uint
 from rpython.rlib.objectmodel import specialize, compute_unique_id
-from rpython.rtyper.annlowlevel import cast_instance_to_gcref
+from rpython.rtyper.annlowlevel import cast_instance_to_gcref, llhelper
 from rpython.rtyper.lltypesystem import rffi, lltype
 
 
@@ -283,6 +283,69 @@
                 debug_print(prefix + ':' + str(struct.i))
             debug_stop('jit-backend-counts')
 
+    @staticmethod
+    @rgc.no_collect
+    def _release_gil_asmgcc(css):
+        # similar to trackgcroot.py:pypy_asm_stackwalk, first part
+        from rpython.memory.gctransform import asmgcroot
+        new = rffi.cast(asmgcroot.ASM_FRAMEDATA_HEAD_PTR, css)
+        next = asmgcroot.gcrootanchor.next
+        new.next = next
+        new.prev = asmgcroot.gcrootanchor
+        asmgcroot.gcrootanchor.next = new
+        next.prev = new
+        # and now release the GIL
+        before = rffi.aroundstate.before
+        if before:
+            before()
+
+    @staticmethod
+    @rgc.no_collect
+    def _reacquire_gil_asmgcc(css):
+        # first reacquire the GIL
+        after = rffi.aroundstate.after
+        if after:
+            after()
+        # similar to trackgcroot.py:pypy_asm_stackwalk, second part
+        from rpython.memory.gctransform import asmgcroot
+        old = rffi.cast(asmgcroot.ASM_FRAMEDATA_HEAD_PTR, css)
+        prev = old.prev
+        next = old.next
+        prev.next = next
+        next.prev = prev
+
+    @staticmethod
+    @rgc.no_collect
+    def _release_gil_shadowstack():
+        before = rffi.aroundstate.before
+        if before:
+            before()
+
+    @staticmethod
+    @rgc.no_collect
+    def _reacquire_gil_shadowstack():
+        after = rffi.aroundstate.after
+        if after:
+            after()
+
+    _NOARG_FUNC = lltype.Ptr(lltype.FuncType([], lltype.Void))
+    _CLOSESTACK_FUNC = lltype.Ptr(lltype.FuncType([rffi.LONGP],
+                                                  lltype.Void))
+
+    def _build_release_gil(self, gcrootmap):
+        if gcrootmap.is_shadow_stack:
+            releasegil_func = llhelper(self._NOARG_FUNC,
+                                       self._release_gil_shadowstack)
+            reacqgil_func = llhelper(self._NOARG_FUNC,
+                                     self._reacquire_gil_shadowstack)
+        else:
+            releasegil_func = llhelper(self._CLOSESTACK_FUNC,
+                                       self._release_gil_asmgcc)
+            reacqgil_func = llhelper(self._CLOSESTACK_FUNC,
+                                     self._reacquire_gil_asmgcc)
+        self.releasegil_addr  = self.cpu.cast_ptr_to_int(releasegil_func)
+        self.reacqgil_addr = self.cpu.cast_ptr_to_int(reacqgil_func)
+
 
 
 def debug_bridge(descr_number, rawstart, codeendpos):
diff --git a/rpython/jit/backend/llsupport/test/test_gc_integration.py b/rpython/jit/backend/llsupport/test/test_gc_integration.py
--- a/rpython/jit/backend/llsupport/test/test_gc_integration.py
+++ b/rpython/jit/backend/llsupport/test/test_gc_integration.py
@@ -719,18 +719,24 @@
         # people actually wreck xmm registers
         cpu = self.cpu
         l = []
+        copied_stack = [None]
 
         def before():
+            # put nonsense on the top of shadowstack
+            frame = rffi.cast(JITFRAMEPTR, cpu.gc_ll_descr.gcrootmap.stack[0])
+            assert getmap(frame).count('1') == 7 #
+            copied_stack[0] = cpu.gc_ll_descr.gcrootmap.stack[0]
+            cpu.gc_ll_descr.gcrootmap.stack[0] = 0
             l.append("before")
 
         def after():
+            cpu.gc_ll_descr.gcrootmap.stack[0] = copied_stack[0]
             l.append("after")
 
         invoke_around_extcall(before, after)
 
         def f(frame, x):
             # all the gc pointers are alive p1 -> p7 (but not p0)
-            assert getmap(frame).count('1') == 7 #
             assert x == 1
             return 2
 
diff --git a/rpython/jit/backend/llsupport/test/zrpy_gc_boehm_test.py b/rpython/jit/backend/llsupport/test/zrpy_gc_boehm_test.py
--- a/rpython/jit/backend/llsupport/test/zrpy_gc_boehm_test.py
+++ b/rpython/jit/backend/llsupport/test/zrpy_gc_boehm_test.py
@@ -32,7 +32,7 @@
     g._dont_inline_ = True
     return g
 
-def test_compile_boehm(monkeypatch):
+def compile_boehm_test(monkeypatch):
     fix_annotator_for_vrawbuffer(monkeypatch)
     myjitdriver = JitDriver(greens = [], reds = ['n', 'x'])
     @dont_look_inside
diff --git a/rpython/jit/backend/llsupport/test/zrpy_gc_test.py b/rpython/jit/backend/llsupport/test/zrpy_gc_test.py
--- a/rpython/jit/backend/llsupport/test/zrpy_gc_test.py
+++ b/rpython/jit/backend/llsupport/test/zrpy_gc_test.py
@@ -770,6 +770,3 @@
 
     def test_compile_framework_call_assembler(self):
         self.run('compile_framework_call_assembler')
-
-class TestShadowStack(CompileFrameworkTests):
-    gcrootfinder = "shadowstack"
diff --git a/rpython/jit/backend/llsupport/test/zrpy_releasegil_test.py b/rpython/jit/backend/llsupport/test/zrpy_releasegil_test.py
--- a/rpython/jit/backend/llsupport/test/zrpy_releasegil_test.py
+++ b/rpython/jit/backend/llsupport/test/zrpy_releasegil_test.py
@@ -95,10 +95,3 @@
     def test_close_stack(self):
         self.run('close_stack')
         assert 'call_release_gil' in udir.join('TestCompileFramework.log').read()
-
-
-class TestShadowStack(ReleaseGILTests):
-    gcrootfinder = "shadowstack"
-
-class TestAsmGcc(ReleaseGILTests):
-    gcrootfinder = "asmgcc"
diff --git a/rpython/jit/backend/test/runner_test.py b/rpython/jit/backend/test/runner_test.py
--- a/rpython/jit/backend/test/runner_test.py
+++ b/rpython/jit/backend/test/runner_test.py
@@ -348,7 +348,7 @@
         i0 = BoxInt()
         class UntouchableFailDescr(AbstractFailDescr):
             final_descr = True
-            
+
             def __setattr__(self, name, value):
                 if (name == 'index' or name == '_carry_around_for_tests'
                         or name == '_TYPE' or name == '_cpu'):
@@ -2455,12 +2455,12 @@
         lltype.free(raw, flavor='raw')
 
     def test_call_to_winapi_function(self):
-        from rpython.rlib.clibffi import _WIN32, FUNCFLAG_STDCALL
+        from rpython.rlib.clibffi import _WIN32
         if not _WIN32:
             py.test.skip("Windows test only")
-        from rpython.rlib.libffi import CDLL, types, ArgChain
+        from rpython.rlib.libffi import WinDLL, types, ArgChain
         from rpython.rlib.rwin32 import DWORD
-        libc = CDLL('KERNEL32')
+        libc = WinDLL('KERNEL32')
         c_GetCurrentDir = libc.getpointer('GetCurrentDirectoryA',
                                           [types.ulong, types.pointer],
                                           types.ulong)
@@ -2831,6 +2831,56 @@
         assert self.cpu.get_int_value(deadframe, 0) == 97
         assert not called
 
+    def test_assembler_call_propagate_exc(self):
+        from rpython.jit.backend.llsupport.llmodel import AbstractLLCPU
+        
+        if not isinstance(self.cpu, AbstractLLCPU):
+            py.test.skip("llgraph can't fake exceptions well enough, give up")
+
+        excdescr = BasicFailDescr(666)
+        self.cpu.propagate_exception_descr = excdescr
+        self.cpu.setup_once()    # xxx redo it, because we added
+                                 # propagate_exception
+
+        def assembler_helper(deadframe, virtualizable):
+            assert self.cpu.get_latest_descr(deadframe) is excdescr
+            # let's assume we handled that
+            return 3
+
+        FUNCPTR = lltype.Ptr(lltype.FuncType([llmemory.GCREF,
+                                              llmemory.GCREF],
+                                             lltype.Signed))
+        class FakeJitDriverSD:
+            index_of_virtualizable = -1
+            _assembler_helper_ptr = llhelper(FUNCPTR, assembler_helper)
+            assembler_helper_adr = llmemory.cast_ptr_to_adr(
+                _assembler_helper_ptr)
+
+        ops = '''
+        [i0]
+        p0 = newunicode(i0)
+        finish(p0)'''
+        loop = parse(ops)
+        looptoken = JitCellToken()
+        looptoken.outermost_jitdriver_sd = FakeJitDriverSD()
+        self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
+        ARGS = [lltype.Signed] * 10
+        RES = lltype.Signed
+        FakeJitDriverSD.portal_calldescr = self.cpu.calldescrof(
+            lltype.Ptr(lltype.FuncType(ARGS, RES)), ARGS, RES,
+            EffectInfo.MOST_GENERAL)
+        ops = '''
+        [i0]
+        i11 = call_assembler(i0, descr=looptoken)
+        guard_not_forced()[]
+        finish(i11)
+        '''
+        loop = parse(ops, namespace=locals())
+        othertoken = JitCellToken()
+        self.cpu.compile_loop(loop.inputargs, loop.operations, othertoken)
+        deadframe = self.cpu.execute_token(othertoken, sys.maxint - 1)
+        assert self.cpu.get_int_value(deadframe, 0) == 3
+
     def test_assembler_call_float(self):
         if not self.cpu.supports_floats:
             py.test.skip("requires floats")
@@ -3341,7 +3391,7 @@
         excdescr = BasicFailDescr(666)
         self.cpu.propagate_exception_descr = excdescr
         self.cpu.setup_once()    # xxx redo it, because we added
-                                 # propagate_exception_v
+                                 # propagate_exception
         i0 = BoxInt()
         p0 = BoxPtr()
         operations = [
@@ -3375,7 +3425,7 @@
         calldescr = self.cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, effectinfo)
         testcases = [(4.0, 2.0), (6.25, 2.5)]
         for arg, expected in testcases:
-            res = self.execute_operation(rop.CALL, 
+            res = self.execute_operation(rop.CALL,
                         [funcbox, boxfloat(arg)],
                          'float', descr=calldescr)
             assert res.getfloat() == expected
@@ -3731,7 +3781,7 @@
         # memory
         assert values[0] == 0
 
-    def test_compile_bridge_while_running(self):        
+    def test_compile_bridge_while_running(self):
         def func():
             bridge = parse("""
             [i1, i2, px]
@@ -3778,9 +3828,9 @@
         func2_ptr = llhelper(FPTR2, func2)
         calldescr2 = cpu.calldescrof(FUNC2, FUNC2.ARGS, FUNC2.RESULT,
                                     EffectInfo.MOST_GENERAL)
-        
+
         faildescr = BasicFailDescr(0)
-        
+
         looptoken = JitCellToken()
         loop = parse("""
         [i0, i1, i2]
@@ -3796,7 +3846,7 @@
 
         if not isinstance(self.cpu, AbstractLLCPU):
             py.test.skip("pointless test on non-asm")
-            
+
         frame = lltype.cast_opaque_ptr(jitframe.JITFRAMEPTR, frame)
         assert len(frame.jf_frame) == frame.jf_frame_info.jfi_frame_depth
         ref = self.cpu.get_ref_value(frame, 9)
@@ -3858,7 +3908,7 @@
                         'calldescr': calldescr,
                         'faildescr': faildescr,
                         'finaldescr2': BasicFinalDescr(1)})
-        
+
         self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
         frame = self.cpu.execute_token(looptoken, 1, 2, 3)
         descr = self.cpu.get_latest_descr(frame)
diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py
--- a/rpython/jit/backend/x86/assembler.py
+++ b/rpython/jit/backend/x86/assembler.py
@@ -371,69 +371,6 @@
         else:
             self.wb_slowpath[withcards + 2 * withfloats] = rawstart
 
-    @staticmethod
-    @rgc.no_collect
-    def _release_gil_asmgcc(css):
-        # similar to trackgcroot.py:pypy_asm_stackwalk, first part
-        from rpython.memory.gctransform import asmgcroot
-        new = rffi.cast(asmgcroot.ASM_FRAMEDATA_HEAD_PTR, css)
-        next = asmgcroot.gcrootanchor.next
-        new.next = next
-        new.prev = asmgcroot.gcrootanchor
-        asmgcroot.gcrootanchor.next = new
-        next.prev = new
-        # and now release the GIL
-        before = rffi.aroundstate.before
-        if before:
-            before()
-
-    @staticmethod
-    @rgc.no_collect
-    def _reacquire_gil_asmgcc(css):
-        # first reacquire the GIL
-        after = rffi.aroundstate.after
-        if after:
-            after()
-        # similar to trackgcroot.py:pypy_asm_stackwalk, second part
-        from rpython.memory.gctransform import asmgcroot
-        old = rffi.cast(asmgcroot.ASM_FRAMEDATA_HEAD_PTR, css)
-        prev = old.prev
-        next = old.next
-        prev.next = next
-        next.prev = prev
-
-    @staticmethod
-    @rgc.no_collect
-    def _release_gil_shadowstack():
-        before = rffi.aroundstate.before
-        if before:
-            before()
-
-    @staticmethod
-    @rgc.no_collect
-    def _reacquire_gil_shadowstack():
-        after = rffi.aroundstate.after
-        if after:
-            after()
-
-    _NOARG_FUNC = lltype.Ptr(lltype.FuncType([], lltype.Void))
-    _CLOSESTACK_FUNC = lltype.Ptr(lltype.FuncType([rffi.LONGP],
-                                                  lltype.Void))
-
-    def _build_release_gil(self, gcrootmap):
-        if gcrootmap.is_shadow_stack:
-            releasegil_func = llhelper(self._NOARG_FUNC,
-                                       self._release_gil_shadowstack)
-            reacqgil_func = llhelper(self._NOARG_FUNC,
-                                     self._reacquire_gil_shadowstack)
-        else:
-            releasegil_func = llhelper(self._CLOSESTACK_FUNC,
-                                       self._release_gil_asmgcc)
-            reacqgil_func = llhelper(self._CLOSESTACK_FUNC,
-                                     self._reacquire_gil_asmgcc)
-        self.releasegil_addr  = self.cpu.cast_ptr_to_int(releasegil_func)
-        self.reacqgil_addr = self.cpu.cast_ptr_to_int(reacqgil_func)
-
     def assemble_loop(self, loopname, inputargs, operations, looptoken, log):
         '''adds the following attributes to looptoken:
                _ll_function_addr    (address of the generated func, as an int)
@@ -1041,12 +978,13 @@
 
     def _emit_call(self, x, arglocs, start=0, tmp=eax,
                    argtypes=None, callconv=FFI_DEFAULT_ABI, can_collect=1,
-                   stack_max=PASS_ON_MY_FRAME):
+                   stack_max=PASS_ON_MY_FRAME, reload_frame=False):
         if can_collect == 1 and not self._is_asmgcc():
             can_collect = 2    # don't bother with jf_extra_stack_depth
         if IS_X86_64:
             return self._emit_call_64(x, arglocs, start, argtypes,
-                                      can_collect, stack_max)
+                                      can_collect, stack_max,
+                                      reload_frame=reload_frame)
         stack_depth = 0
         n = len(arglocs)
         for i in range(start, n):
@@ -1096,6 +1034,8 @@
                 ofs = self.cpu.get_ofs_of_frame_field('jf_extra_stack_depth')
                 self.mc.MOV_bi(ofs, 0)
             self.pop_gcmap(self.mc)
+        elif reload_frame:
+            self._reload_frame_if_necessary(self.mc)
         #
 
     def _fix_stdcall(self, callconv, p):
@@ -1106,7 +1046,7 @@
         self.mc.SUB_ri(esp.value, p)
 
     def _emit_call_64(self, x, arglocs, start, argtypes,
-                      can_collect, stack_max):
+                      can_collect, stack_max, reload_frame=False):
         src_locs = []
         dst_locs = []
         xmm_src_locs = []
@@ -1196,6 +1136,8 @@
             if align and can_collect == 1:
                 ofs = self.cpu.get_ofs_of_frame_field('jf_extra_stack_depth')
                 self.mc.MOV_bi(ofs, 0)
+        elif reload_frame:
+            self._reload_frame_if_necessary(self.mc)
         if align:
             self.mc.ADD_ri(esp.value, align * WORD)
         if can_collect:
@@ -1988,6 +1930,9 @@
         self.pending_guard_tokens.append(guard_token)
 
     def genop_call(self, op, arglocs, resloc):
+        return self._genop_call(op, arglocs, resloc)
+
+    def _genop_call(self, op, arglocs, resloc, is_call_release_gil=False):
         from rpython.jit.backend.llsupport.descr import CallDescr
 
         sizeloc = arglocs[0]
@@ -2005,11 +1950,14 @@
         assert isinstance(descr, CallDescr)
 
         stack_max = PASS_ON_MY_FRAME
-        if self._is_asmgcc() and op.getopnum() == rop.CALL_RELEASE_GIL:
-            from rpython.memory.gctransform import asmgcroot
-            stack_max -= asmgcroot.JIT_USE_WORDS
-            can_collect = 3    # asmgcc only: don't write jf_extra_stack_depth,
-                               # and reload ebp from the css
+        if is_call_release_gil:
+            if self._is_asmgcc():
+                from rpython.memory.gctransform import asmgcroot
+                stack_max -= asmgcroot.JIT_USE_WORDS
+                can_collect = 3    # asmgcc only: don't write jf_extra_stack_depth,
+                                   # and reload ebp from the css
+            else:
+                can_collect = 0
         else:
             can_collect = 1
 
@@ -2074,13 +2022,16 @@
 
     def genop_guard_call_release_gil(self, op, guard_op, guard_token,
                                      arglocs, result_loc):
+        self._store_force_index(guard_op)
         # first, close the stack in the sense of the asmgcc GC root tracker
         gcrootmap = self.cpu.gc_ll_descr.gcrootmap
         if gcrootmap:
+            noregs = self.cpu.gc_ll_descr.is_shadow_stack()
+            gcmap = self._regalloc.get_gcmap([eax], noregs=noregs)
+            self.push_gcmap(self.mc, gcmap, store=True)
             self.call_release_gil(gcrootmap, arglocs)
         # do the call
-        self._store_force_index(guard_op)
-        self.genop_call(op, arglocs, result_loc)
+        self._genop_call(op, arglocs, result_loc, is_call_release_gil=True)
         # then reopen the stack
         if gcrootmap:
             self.call_reacquire_gil(gcrootmap, result_loc)
@@ -2139,7 +2090,8 @@
                 reg = edi
             self.mc.LEA_rs(reg.value, css)
             args = [reg]
-        self._emit_call(imm(self.reacqgil_addr), args, can_collect=False)
+        self._emit_call(imm(self.reacqgil_addr), args, can_collect=False,
+                        reload_frame=True)
         # restore the result from the stack
         if isinstance(save_loc, RegLoc) and not save_loc.is_xmm:
             self.mc.MOV_rs(save_loc.value, WORD)
diff --git a/rpython/jit/backend/x86/test/test_zrpy_gc.py b/rpython/jit/backend/x86/test/test_zrpy_gc.py
--- a/rpython/jit/backend/x86/test/test_zrpy_gc.py
+++ b/rpython/jit/backend/x86/test/test_zrpy_gc.py
@@ -1,1 +1,5 @@
-from rpython.jit.backend.llsupport.test.zrpy_gc_test import TestShadowStack
+from rpython.jit.backend.llsupport.test.zrpy_gc_test import CompileFrameworkTests
+
+
+class TestShadowStack(CompileFrameworkTests):
+    gcrootfinder = "shadowstack"
diff --git a/rpython/jit/backend/x86/test/test_zrpy_gc_boehm.py b/rpython/jit/backend/x86/test/test_zrpy_gc_boehm.py
--- a/rpython/jit/backend/x86/test/test_zrpy_gc_boehm.py
+++ b/rpython/jit/backend/x86/test/test_zrpy_gc_boehm.py
@@ -1,1 +1,1 @@
-from rpython.jit.backend.llsupport.test.zrpy_gc_boehm_test import test_compile_boehm
+from rpython.jit.backend.llsupport.test.zrpy_gc_boehm_test import compile_boehm_test as test_compile_boehm
diff --git a/rpython/jit/backend/x86/test/test_zrpy_releasegil.py b/rpython/jit/backend/x86/test/test_zrpy_releasegil.py
--- a/rpython/jit/backend/x86/test/test_zrpy_releasegil.py
+++ b/rpython/jit/backend/x86/test/test_zrpy_releasegil.py
@@ -1,1 +1,9 @@
-from rpython.jit.backend.llsupport.test.zrpy_releasegil_test import TestShadowStack, TestAsmGcc
+from rpython.jit.backend.llsupport.test.zrpy_releasegil_test import ReleaseGILTests
+
+
+class TestShadowStack(ReleaseGILTests):
+    gcrootfinder = "shadowstack"
+
+
+class TestAsmGcc(ReleaseGILTests):
+    gcrootfinder = "asmgcc"
diff --git a/rpython/jit/codewriter/jtransform.py b/rpython/jit/codewriter/jtransform.py
--- a/rpython/jit/codewriter/jtransform.py
+++ b/rpython/jit/codewriter/jtransform.py
@@ -1755,11 +1755,15 @@
         return SpaceOperation('libffi_save_result_%s' % kind, op.args[1:], None)
 
     def rewrite_op_jit_force_virtual(self, op):
-        return self._do_builtin_call(op)
+        op0 = SpaceOperation('-live-', [], None)
+        op1 = self._do_builtin_call(op)
+        if isinstance(op1, list):
+            return [op0] + op1
+        else:
+            return [op0, op1]
 
     def rewrite_op_jit_is_virtual(self, op):
-        raise Exception, (
-            "'vref.virtual' should not be used from jit-visible code")
+        raise Exception("'vref.virtual' should not be used from jit-visible code")
 
     def rewrite_op_jit_force_virtualizable(self, op):
         # this one is for virtualizables
diff --git a/rpython/jit/codewriter/test/test_flatten.py b/rpython/jit/codewriter/test/test_flatten.py
--- a/rpython/jit/codewriter/test/test_flatten.py
+++ b/rpython/jit/codewriter/test/test_flatten.py
@@ -689,6 +689,7 @@
         self.encoding_test(f, [], """
             new_with_vtable <Descr> -> %r0
             virtual_ref %r0 -> %r1
+            -live-
             residual_call_r_r $<* fn jit_force_virtual>, R[%r1], <Descr> -> %r2
             ref_return %r2
         """, transform=True, cc=FakeCallControlWithVRefInfo())
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py
@@ -1747,9 +1747,9 @@
         ops = """
         [i1]
         i2 = call('malloc', 10, descr=raw_malloc_descr)
-        setarrayitem_raw(i2, 0, i1, descr=rawarraydescr)
-        setarrayitem_raw(i2, 2, 456, descr=rawarraydescr)
-        setarrayitem_raw(i2, 1, 123, descr=rawarraydescr)
+        setarrayitem_raw(i2, 0, i1, descr=rawarraydescr_char)
+        setarrayitem_raw(i2, 2, 456, descr=rawarraydescr_char)
+        setarrayitem_raw(i2, 1, 123, descr=rawarraydescr_char)
         label('foo') # we expect the buffer to be forced *after* the label
         escape(i2)
         call('free', i2, descr=raw_free_descr)
@@ -1759,11 +1759,11 @@
         [i1]
         label('foo')
         i2 = call('malloc', 10, descr=raw_malloc_descr)
-        setarrayitem_raw(i2, 0, i1, descr=rawarraydescr)
-        i3 = int_add(i2, 8)
-        setarrayitem_raw(i3, 0, 123, descr=rawarraydescr)
-        i4 = int_add(i2, 16)
-        setarrayitem_raw(i4, 0, 456, descr=rawarraydescr)
+        setarrayitem_raw(i2, 0, i1, descr=rawarraydescr_char)
+        i3 = int_add(i2, 1)
+        setarrayitem_raw(i3, 0, 123, descr=rawarraydescr_char)
+        i4 = int_add(i2, 2)
+        setarrayitem_raw(i4, 0, 456, descr=rawarraydescr_char)
         escape(i2)
         call('free', i2, descr=raw_free_descr)
         jump(i1)
diff --git a/rpython/jit/metainterp/pyjitpl.py b/rpython/jit/metainterp/pyjitpl.py
--- a/rpython/jit/metainterp/pyjitpl.py
+++ b/rpython/jit/metainterp/pyjitpl.py
@@ -1,25 +1,27 @@
-import py, sys
+import sys
+
+import py
+
+from rpython.jit.codewriter import heaptracker
+from rpython.jit.codewriter.effectinfo import EffectInfo
+from rpython.jit.codewriter.jitcode import JitCode, SwitchDictDescr
+from rpython.jit.metainterp import history, compile, resume, executor
+from rpython.jit.metainterp.heapcache import HeapCache
+from rpython.jit.metainterp.history import (Const, ConstInt, ConstPtr,
+    ConstFloat, Box, TargetToken)
+from rpython.jit.metainterp.jitexc import JitException, get_llexception
+from rpython.jit.metainterp.jitprof import EmptyProfiler
+from rpython.jit.metainterp.logger import Logger
+from rpython.jit.metainterp.optimizeopt.util import args_dict_box
+from rpython.jit.metainterp.resoperation import rop
+from rpython.rlib import nonconst, rstack
+from rpython.rlib.debug import debug_start, debug_stop, debug_print, make_sure_not_resized
+from rpython.rlib.jit import Counters
+from rpython.rlib.objectmodel import we_are_translated, specialize
+from rpython.rlib.unroll import unrolling_iterable
 from rpython.rtyper.lltypesystem import lltype, rclass
-from rpython.rlib.objectmodel import we_are_translated
-from rpython.rlib.unroll import unrolling_iterable
-from rpython.rlib.debug import debug_start, debug_stop, debug_print
-from rpython.rlib.debug import make_sure_not_resized
-from rpython.rlib import nonconst, rstack
 
-from rpython.jit.metainterp import history, compile, resume
-from rpython.jit.metainterp.history import Const, ConstInt, ConstPtr, ConstFloat
-from rpython.jit.metainterp.history import Box, TargetToken
-from rpython.jit.metainterp.resoperation import rop
-from rpython.jit.metainterp import executor
-from rpython.jit.metainterp.logger import Logger
-from rpython.jit.metainterp.jitprof import EmptyProfiler
-from rpython.rlib.jit import Counters
-from rpython.jit.metainterp.jitexc import JitException, get_llexception
-from rpython.jit.metainterp.heapcache import HeapCache
-from rpython.rlib.objectmodel import specialize
-from rpython.jit.codewriter.jitcode import JitCode, SwitchDictDescr
-from rpython.jit.codewriter import heaptracker
-from rpython.jit.metainterp.optimizeopt.util import args_dict_box
+
 
 # ____________________________________________________________
 
@@ -831,15 +833,17 @@
     opimpl_inline_call_irf_f = _opimpl_inline_call3
     opimpl_inline_call_irf_v = _opimpl_inline_call3
 
-    @arguments("box", "boxes", "descr")
-    def _opimpl_residual_call1(self, funcbox, argboxes, calldescr):
-        return self.do_residual_or_indirect_call(funcbox, argboxes, calldescr)
-    @arguments("box", "boxes2", "descr")
-    def _opimpl_residual_call2(self, funcbox, argboxes, calldescr):
-        return self.do_residual_or_indirect_call(funcbox, argboxes, calldescr)
-    @arguments("box", "boxes3", "descr")
-    def _opimpl_residual_call3(self, funcbox, argboxes, calldescr):
-        return self.do_residual_or_indirect_call(funcbox, argboxes, calldescr)
+    @arguments("box", "boxes", "descr", "orgpc")
+    def _opimpl_residual_call1(self, funcbox, argboxes, calldescr, pc):
+        return self.do_residual_or_indirect_call(funcbox, argboxes, calldescr, pc)
+
+    @arguments("box", "boxes2", "descr", "orgpc")
+    def _opimpl_residual_call2(self, funcbox, argboxes, calldescr, pc):
+        return self.do_residual_or_indirect_call(funcbox, argboxes, calldescr, pc)
+
+    @arguments("box", "boxes3", "descr", "orgpc")
+    def _opimpl_residual_call3(self, funcbox, argboxes, calldescr, pc):
+        return self.do_residual_or_indirect_call(funcbox, argboxes, calldescr, pc)
 
     opimpl_residual_call_r_i = _opimpl_residual_call1
     opimpl_residual_call_r_r = _opimpl_residual_call1
@@ -852,8 +856,8 @@
     opimpl_residual_call_irf_f = _opimpl_residual_call3
     opimpl_residual_call_irf_v = _opimpl_residual_call3
 
-    @arguments("int", "boxes3", "boxes3")
-    def _opimpl_recursive_call(self, jdindex, greenboxes, redboxes):
+    @arguments("int", "boxes3", "boxes3", "orgpc")
+    def _opimpl_recursive_call(self, jdindex, greenboxes, redboxes, pc):
         targetjitdriver_sd = self.metainterp.staticdata.jitdrivers_sd[jdindex]
         allboxes = greenboxes + redboxes
         warmrunnerstate = targetjitdriver_sd.warmstate
@@ -868,15 +872,15 @@
             # that assembler that we call is still correct
             self.verify_green_args(targetjitdriver_sd, greenboxes)
         #
-        return self.do_recursive_call(targetjitdriver_sd, allboxes,
+        return self.do_recursive_call(targetjitdriver_sd, allboxes, pc,
                                       assembler_call)
 
-    def do_recursive_call(self, targetjitdriver_sd, allboxes,
+    def do_recursive_call(self, targetjitdriver_sd, allboxes, pc,
                           assembler_call=False):
         portal_code = targetjitdriver_sd.mainjitcode
         k = targetjitdriver_sd.portal_runner_adr
         funcbox = ConstInt(heaptracker.adr2int(k))
-        return self.do_residual_call(funcbox, allboxes, portal_code.calldescr,
+        return self.do_residual_call(funcbox, allboxes, portal_code.calldescr, pc,
                                      assembler_call=assembler_call,
                                      assembler_call_jd=targetjitdriver_sd)
 
@@ -935,7 +939,7 @@
             return box     # no promotion needed, already a Const
         else:
             constbox = box.constbox()
-            resbox = self.do_residual_call(funcbox, [box, constbox], descr)
+            resbox = self.do_residual_call(funcbox, [box, constbox], descr, orgpc)
             promoted_box = resbox.constbox()
             # This is GUARD_VALUE because GUARD_TRUE assumes the existance
             # of a label when computing resumepc
@@ -1027,7 +1031,7 @@
             except ChangeFrame:
                 pass
             frame = self.metainterp.framestack[-1]
-            frame.do_recursive_call(jitdriver_sd, greenboxes + redboxes,
+            frame.do_recursive_call(jitdriver_sd, greenboxes + redboxes, orgpc,
                                     assembler_call=True)
             raise ChangeFrame
 
@@ -1329,7 +1333,7 @@
             self.metainterp.assert_no_exception()
         return resbox
 
-    def do_residual_call(self, funcbox, argboxes, descr,
+    def do_residual_call(self, funcbox, argboxes, descr, pc,
                          assembler_call=False,
                          assembler_call_jd=None):
         # First build allboxes: it may need some reordering from the
@@ -1369,6 +1373,10 @@
                 effectinfo.check_forces_virtual_or_virtualizable()):
             # residual calls require attention to keep virtualizables in-sync
             self.metainterp.clear_exception()
+            if effectinfo.oopspecindex == EffectInfo.OS_JIT_FORCE_VIRTUAL:
+                resbox = self._do_jit_force_virtual(allboxes, descr, pc)
+                if resbox is not None:
+                    return resbox
             self.metainterp.vable_and_vrefs_before_residual_call()
             resbox = self.metainterp.execute_and_record_varargs(
                 rop.CALL_MAY_FORCE, allboxes, descr=descr)
@@ -1399,7 +1407,27 @@
             pure = effectinfo.check_is_elidable()
             return self.execute_varargs(rop.CALL, allboxes, descr, exc, pure)
 
-    def do_residual_or_indirect_call(self, funcbox, argboxes, calldescr):
+    def _do_jit_force_virtual(self, allboxes, descr, pc):
+        assert len(allboxes) == 2
+        if (self.metainterp.jitdriver_sd.virtualizable_info is None and
+            self.metainterp.jitdriver_sd.greenfield_info is None):
+            # can occur in case of multiple JITs
+            return None
+        vref_box = allboxes[1]
+        standard_box = self.metainterp.virtualizable_boxes[-1]
+        if standard_box is vref_box:
+            return vref_box
+        if self.metainterp.heapcache.is_nonstandard_virtualizable(vref_box):
+            return None
+        eqbox = self.metainterp.execute_and_record(rop.PTR_EQ, None, vref_box, standard_box)
+        eqbox = self.implement_guard_value(eqbox, pc)
+        isstandard = eqbox.getint()
+        if isstandard:
+            return standard_box
+        else:
+            return None
+
+    def do_residual_or_indirect_call(self, funcbox, argboxes, calldescr, pc):
         """The 'residual_call' operation is emitted in two cases:
         when we have to generate a residual CALL operation, but also
         to handle an indirect_call that may need to be inlined."""
@@ -1411,7 +1439,7 @@
                 # we should follow calls to this graph
                 return self.metainterp.perform_call(jitcode, argboxes)
         # but we should not follow calls to that graph
-        return self.do_residual_call(funcbox, argboxes, calldescr)
+        return self.do_residual_call(funcbox, argboxes, calldescr, pc)
 
 # ____________________________________________________________
 
diff --git a/rpython/jit/metainterp/test/test_virtualizable.py b/rpython/jit/metainterp/test/test_virtualizable.py
--- a/rpython/jit/metainterp/test/test_virtualizable.py
+++ b/rpython/jit/metainterp/test/test_virtualizable.py
@@ -1,20 +1,22 @@
 import py
+
+from rpython.jit.codewriter import heaptracker
+from rpython.jit.codewriter.policy import StopAtXPolicy
+from rpython.jit.metainterp.optimizeopt.test.test_util import LLtypeMixin
+from rpython.jit.metainterp.test.support import LLJitMixin, OOJitMixin
+from rpython.jit.metainterp.warmspot import get_translator
+from rpython.rlib.jit import JitDriver, hint, dont_look_inside, promote, virtual_ref
+from rpython.rlib.rarithmetic import intmask
+from rpython.rtyper.annlowlevel import hlstr
 from rpython.rtyper.extregistry import ExtRegistryEntry
 from rpython.rtyper.lltypesystem import lltype, lloperation, rclass, llmemory
-from rpython.rtyper.annlowlevel import llhelper
-from rpython.rtyper.rclass import IR_IMMUTABLE, IR_IMMUTABLE_ARRAY
-from rpython.jit.codewriter.policy import StopAtXPolicy
-from rpython.jit.codewriter import heaptracker
-from rpython.rlib.jit import JitDriver, hint, dont_look_inside, promote
-from rpython.rlib.rarithmetic import intmask
-from rpython.jit.metainterp.test.support import LLJitMixin, OOJitMixin
-from rpython.rtyper.rclass import FieldListAccessor
-from rpython.jit.metainterp.warmspot import get_stats, get_translator
-from rpython.jit.metainterp import history
-from rpython.jit.metainterp.optimizeopt.test.test_util import LLtypeMixin
+from rpython.rtyper.rclass import IR_IMMUTABLE, IR_IMMUTABLE_ARRAY, FieldListAccessor
+
 
 def promote_virtualizable(*args):
     pass
+
+
 class Entry(ExtRegistryEntry):
     "Annotation and rtyping of LLOp instances, which are callable."
     _about_ = promote_virtualizable
@@ -46,7 +48,7 @@
         ('inst_node', lltype.Ptr(LLtypeMixin.NODE)),
         hints = {'virtualizable2_accessor': FieldListAccessor()})
     XY._hints['virtualizable2_accessor'].initialize(
-        XY, {'inst_x' : IR_IMMUTABLE, 'inst_node' : IR_IMMUTABLE})
+        XY, {'inst_x': IR_IMMUTABLE, 'inst_node': IR_IMMUTABLE})
 
     xy_vtable = lltype.malloc(rclass.OBJECT_VTABLE, immortal=True)
     heaptracker.set_testing_vtable_for_gcstruct(XY, xy_vtable, 'XY')
@@ -73,7 +75,7 @@
                 x = xy.inst_x
                 xy.inst_x = x + 1
                 n -= 1
-            promote_virtualizable(xy, 'inst_x')                
+            promote_virtualizable(xy, 'inst_x')
             return xy.inst_x
         res = self.meta_interp(f, [20])
         assert res == 30
@@ -97,7 +99,7 @@
                     x = xy.inst_x
                     xy.inst_x = x + 10
                 n -= 1
-            promote_virtualizable(xy, 'inst_x')                
+            promote_virtualizable(xy, 'inst_x')
             return xy.inst_x
         assert f(5) == 185
         res = self.meta_interp(f, [5])
@@ -118,10 +120,10 @@
                 x = xy.inst_x
                 if n <= 10:
                     x += 1000
-                promote_virtualizable(xy, 'inst_x')                    
+                promote_virtualizable(xy, 'inst_x')
                 xy.inst_x = x + 1
                 n -= 1
-            promote_virtualizable(xy, 'inst_x')                
+            promote_virtualizable(xy, 'inst_x')
             return xy.inst_x
         res = self.meta_interp(f, [18])
         assert res == 10118
@@ -164,7 +166,7 @@
                 xy.inst_x = x + 1
                 m = (m+1) & 3     # the loop gets unrolled 4 times
                 n -= 1
-            promote_virtualizable(xy, 'inst_x')                
+            promote_virtualizable(xy, 'inst_x')
             return xy.inst_x
         def f(n):
             res = 0
@@ -194,7 +196,7 @@
                 promote_virtualizable(xy, 'inst_x')
                 xy.inst_x = value + 100      # virtualized away
                 n -= 1
-            promote_virtualizable(xy, 'inst_x')                
+            promote_virtualizable(xy, 'inst_x')
             return xy.inst_x
         res = self.meta_interp(f, [20])
         assert res == 134
@@ -212,8 +214,8 @@
         ('inst_l2', lltype.Ptr(lltype.GcArray(lltype.Signed))),
         hints = {'virtualizable2_accessor': FieldListAccessor()})
     XY2._hints['virtualizable2_accessor'].initialize(
-        XY2, {'inst_x' : IR_IMMUTABLE,
-              'inst_l1' : IR_IMMUTABLE_ARRAY, 'inst_l2' : IR_IMMUTABLE_ARRAY})
+        XY2, {'inst_x': IR_IMMUTABLE,
+              'inst_l1': IR_IMMUTABLE_ARRAY, 'inst_l2': IR_IMMUTABLE_ARRAY})
 
     xy2_vtable = lltype.malloc(rclass.OBJECT_VTABLE, immortal=True)
     heaptracker.set_testing_vtable_for_gcstruct(XY2, xy2_vtable, 'XY2')
@@ -241,11 +243,11 @@
             while n > 0:
                 myjitdriver.can_enter_jit(xy2=xy2, n=n)
                 myjitdriver.jit_merge_point(xy2=xy2, n=n)
-                promote_virtualizable(xy2, 'inst_l1')                
+                promote_virtualizable(xy2, 'inst_l1')
                 promote_virtualizable(xy2, 'inst_l2')
                 xy2.inst_l1[2] += xy2.inst_l2[0]
                 n -= 1
-            promote_virtualizable(xy2, 'inst_l1')                
+            promote_virtualizable(xy2, 'inst_l1')
             return xy2.inst_l1[2]
         res = self.meta_interp(f, [16])
         assert res == 3001 + 16 * 80
@@ -292,7 +294,7 @@
                 myjitdriver.can_enter_jit(xy2=xy2, n=n)
                 myjitdriver.jit_merge_point(xy2=xy2, n=n)
                 promote_virtualizable(xy2, 'inst_l1')
-                promote_virtualizable(xy2, 'inst_l2')                
+                promote_virtualizable(xy2, 'inst_l2')
                 xy2.inst_l1[1] += len(xy2.inst_l2)
                 n -= 1
         def f(n):
@@ -373,7 +375,7 @@
                 promote_virtualizable(xy2, 'inst_l2')
                 xy2.inst_l2[0] = value + 100      # virtualized away
                 n -= 1
-            promote_virtualizable(xy2, 'inst_l2')                
+            promote_virtualizable(xy2, 'inst_l2')
             return xy2.inst_l2[0]
         expected = f(20)
         res = self.meta_interp(f, [20], enable_opts='')
@@ -406,8 +408,8 @@
                 myjitdriver.can_enter_jit(xy2=xy2, n=n)
                 myjitdriver.jit_merge_point(xy2=xy2, n=n)
                 parent = xy2.parent
-                promote_virtualizable(parent, 'inst_x')                
-                promote_virtualizable(parent, 'inst_l2')                
+                promote_virtualizable(parent, 'inst_x')
+                promote_virtualizable(parent, 'inst_l2')
                 parent.inst_l2[0] += parent.inst_x
                 n -= 1
         def f(n):
@@ -432,8 +434,7 @@
     # ------------------------------
 
 
-class ImplicitVirtualizableTests:
-
+class ImplicitVirtualizableTests(object):
     def test_simple_implicit(self):
         myjitdriver = JitDriver(greens = [], reds = ['frame'],
                                 virtualizables = ['frame'])
@@ -473,9 +474,9 @@
             def __init__(self, l, s):
                 self.l = l
                 self.s = s
-        
+
         def f(n, a):
-            frame = Frame([a,a+1,a+2,a+3], 0)
+            frame = Frame([a, a+1, a+2, a+3], 0)
             x = 0
             while n > 0:
                 myjitdriver.can_enter_jit(frame=frame, n=n, x=x)
@@ -544,7 +545,7 @@
 
         def f(n):
             BaseFrame([])     # hack to force 'x' to be in BaseFrame
-            frame = Frame([1,2,3])
+            frame = Frame([1, 2, 3])
             z = 0
             while n > 0:
                 jitdriver.can_enter_jit(frame=frame, n=n, z=z)
@@ -560,9 +561,10 @@
     def test_external_read(self):
         jitdriver = JitDriver(greens = [], reds = ['frame'],
                               virtualizables = ['frame'])
-        
+
         class Frame(object):
             _virtualizable2_ = ['x', 'y']
+
         class SomewhereElse:
             pass
         somewhere_else = SomewhereElse()
@@ -592,9 +594,10 @@
     def test_external_read_with_exception(self):
         jitdriver = JitDriver(greens = [], reds = ['frame'],
                               virtualizables = ['frame'])
-        
+
         class Frame(object):
             _virtualizable2_ = ['x', 'y']
+
         class SomewhereElse:
             pass
         somewhere_else = SomewhereElse()
@@ -634,6 +637,7 @@
 
         class Frame(object):
             _virtualizable2_ = ['x', 'y']
+
         class SomewhereElse:
             pass
         somewhere_else = SomewhereElse()
@@ -663,9 +667,10 @@
     def test_external_read_sometimes(self):
         jitdriver = JitDriver(greens = [], reds = ['frame'],
                               virtualizables = ['frame'])
-        
+
         class Frame(object):
             _virtualizable2_ = ['x', 'y']
+
         class SomewhereElse:
             pass
         somewhere_else = SomewhereElse()
@@ -699,11 +704,13 @@
     def test_external_read_sometimes_with_virtuals(self):
         jitdriver = JitDriver(greens = [], reds = ['frame'],
                               virtualizables = ['frame'])
-        
+
         class Frame(object):
             _virtualizable2_ = ['x', 'y']
+
         class Y:
             pass
+
         class SomewhereElse:
             pass
         somewhere_else = SomewhereElse()
@@ -742,11 +749,13 @@
     def test_external_read_sometimes_changing_virtuals(self):
         jitdriver = JitDriver(greens = [], reds = ['frame'],
                               virtualizables = ['frame'])
-        
+
         class Frame(object):
             _virtualizable2_ = ['x', 'y']
+
         class Y:
             pass
+
         class SomewhereElse:
             pass
         somewhere_else = SomewhereElse()
@@ -790,11 +799,13 @@
     def test_external_read_sometimes_with_exception(self):
         jitdriver = JitDriver(greens = [], reds = ['frame'],
                               virtualizables = ['frame'])
-        
+
         class Frame(object):
             _virtualizable2_ = ['x', 'y']
+
         class FooBarError(Exception):
             pass
+
         class SomewhereElse:
             pass
         somewhere_else = SomewhereElse()
@@ -832,9 +843,10 @@
     def test_external_read_sometimes_dont_compile_guard(self):
         jitdriver = JitDriver(greens = [], reds = ['frame'],
                               virtualizables = ['frame'])
-        
+
         class Frame(object):
             _virtualizable2_ = ['x', 'y']
+
         class SomewhereElse:
             pass
         somewhere_else = SomewhereElse()
@@ -868,9 +880,10 @@
     def test_external_read_sometimes_recursive(self):
         jitdriver = JitDriver(greens = [], reds = ['rec', 'frame'],
                               virtualizables = ['frame'])
-        
+
         class Frame(object):
             _virtualizable2_ = ['x', 'y']
+
         class SomewhereElse:
             pass
         somewhere_else = SomewhereElse()
@@ -919,9 +932,10 @@
     def test_external_write_sometimes(self):
         jitdriver = JitDriver(greens = [], reds = ['frame'],
                               virtualizables = ['frame'])
-        
+
         class Frame(object):
             _virtualizable2_ = ['x', 'y']
+
         class SomewhereElse:
             pass
         somewhere_else = SomewhereElse()
@@ -955,9 +969,10 @@
     def test_bridge_forces(self):
         jitdriver = JitDriver(greens = [], reds = ['frame'],
                               virtualizables = ['frame'])
-        
+
         class Frame(object):
             _virtualizable2_ = ['x', 'y']
+
         class SomewhereElse:
             pass
         somewhere_else = SomewhereElse()
@@ -988,6 +1003,7 @@
     def test_promote_index_in_virtualizable_list(self):
         jitdriver = JitDriver(greens = [], reds = ['n', 'frame'],
                               virtualizables = ['frame'])
+
         class Frame(object):
             _virtualizable2_ = ['stackpos', 'stack[*]']
 
@@ -1063,8 +1079,8 @@
         assert direct_calls(f_graph) == ['__init__',
                                          'force_virtualizable_if_necessary',
                                          'll_portal_runner']
-        assert direct_calls(portal_graph)==['force_virtualizable_if_necessary',
-                                            'maybe_enter_jit']
+        assert direct_calls(portal_graph) == ['force_virtualizable_if_necessary',
+                                              'maybe_enter_jit']
         assert direct_calls(init_graph) == []
 
     def test_virtual_child_frame(self):
@@ -1262,7 +1278,7 @@
         somewhere_else = SomewhereElse()
 
         def jump_back(frame, fail):
-            myjitdriver.can_enter_jit(frame=frame, fail=fail)            
+            myjitdriver.can_enter_jit(frame=frame, fail=fail)
 
         def f(n, fail):
             frame = Frame(n, 0)
@@ -1315,8 +1331,10 @@
                 f.x -= 1
                 result += indirection(f)
             return result
+
         def indirection(arg):
             return interp(arg)
+
         def run_interp(n):
             f = hint(Frame(n), access_directly=True)
             return interp(f)
@@ -1325,7 +1343,7 @@
         assert res == run_interp(4)
 
     def test_guard_failure_in_inlined_function(self):
-        from rpython.rtyper.annlowlevel import hlstr
+
         class Frame(object):
             _virtualizable2_ = ['n', 'next']
 
@@ -1368,11 +1386,12 @@
                     assert 0
                 pc += 1
             return frame.n
+
         def main(n):
             frame = Frame(n)
             return f("c-l", frame)


More information about the pypy-commit mailing list