Author: mattip <[email protected]>
Branch: ufuncapi
Changeset: r72695:5e27940eacc0
Date: 2014-08-04 23:48 +0300
http://bitbucket.org/pypy/pypy/changeset/5e27940eacc0/

Log:    merge default into branch

diff too long, truncating to 2000 out of 2595 lines

diff --git a/lib-python/2.7/xml/sax/saxutils.py 
b/lib-python/2.7/xml/sax/saxutils.py
--- a/lib-python/2.7/xml/sax/saxutils.py
+++ b/lib-python/2.7/xml/sax/saxutils.py
@@ -98,13 +98,14 @@
         except AttributeError:
             pass
     # wrap a binary writer with TextIOWrapper
-    class UnbufferedTextIOWrapper(io.TextIOWrapper):
-        def write(self, s):
-            super(UnbufferedTextIOWrapper, self).write(s)
-            self.flush()
-    return UnbufferedTextIOWrapper(buffer, encoding=encoding,
+    return _UnbufferedTextIOWrapper(buffer, encoding=encoding,
                                    errors='xmlcharrefreplace',
                                    newline='\n')
+# PyPy: moved this class outside the function above
+class _UnbufferedTextIOWrapper(io.TextIOWrapper):
+    def write(self, s):
+        super(_UnbufferedTextIOWrapper, self).write(s)
+        self.flush()
 
 class XMLGenerator(handler.ContentHandler):
 
diff --git a/lib_pypy/_curses.py b/lib_pypy/_curses.py
--- a/lib_pypy/_curses.py
+++ b/lib_pypy/_curses.py
@@ -309,11 +309,9 @@
 #endif
 
 int _m_ispad(WINDOW *win) {
-#if defined WINDOW_HAS_FLAGS
+    // <curses.h> may not have _flags (and possibly _ISPAD),
+    // but for now let's assume that <ncurses.h> always has it
     return (win->_flags & _ISPAD);
-#else
-    return 0;
-#endif
 }
 
 void _m_getsyx(int *yx) {
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,5 +4,5 @@
 from .api import FFI, CDefError, FFIError
 from .ffiplatform import VerificationError, VerificationMissing
 
-__version__ = "0.8.2"
-__version_info__ = (0, 8, 2)
+__version__ = "0.8.6"
+__version_info__ = (0, 8, 6)
diff --git a/lib_pypy/cffi/api.py b/lib_pypy/cffi/api.py
--- a/lib_pypy/cffi/api.py
+++ b/lib_pypy/cffi/api.py
@@ -55,8 +55,7 @@
             # _cffi_backend.so compiled.
             import _cffi_backend as backend
             from . import __version__
-            assert (backend.__version__ == __version__ or
-                    backend.__version__ == __version__[:3])
+            assert backend.__version__ == __version__
             # (If you insist you can also try to pass the option
             # 'backend=backend_ctypes.CTypesBackend()', but don't
             # rely on it!  It's probably not going to work well.)
diff --git a/lib_pypy/cffi/vengine_gen.py b/lib_pypy/cffi/vengine_gen.py
--- a/lib_pypy/cffi/vengine_gen.py
+++ b/lib_pypy/cffi/vengine_gen.py
@@ -435,14 +435,14 @@
                     enumerator, enumerator, enumvalue))
             prnt('    char buf[64];')
             prnt('    if ((%s) < 0)' % enumerator)
-            prnt('        snprintf(buf, 63, "%%ld", (long)(%s));' % enumerator)
+            prnt('        sprintf(buf, "%%ld", (long)(%s));' % enumerator)
             prnt('    else')
-            prnt('        snprintf(buf, 63, "%%lu", (unsigned long)(%s));' %
+            prnt('        sprintf(buf, "%%lu", (unsigned long)(%s));' %
                  enumerator)
-            prnt('    snprintf(out_error, 255,'
+            prnt('    sprintf(out_error,'
                              ' "%s has the real value %s, not %s",')
             prnt('            "%s", buf, "%d");' % (
-                enumerator, enumvalue))
+                enumerator[:100], enumvalue))
             prnt('    return -1;')
             prnt('  }')
         prnt('  return 0;')
diff --git a/pypy/doc/coding-guide.rst b/pypy/doc/coding-guide.rst
--- a/pypy/doc/coding-guide.rst
+++ b/pypy/doc/coding-guide.rst
@@ -740,7 +740,7 @@
 
 Adding an entry under pypy/module (e.g. mymodule) entails automatic
 creation of a new config option (such as --withmod-mymodule and
---withoutmod-mymodule (the later being the default)) for py.py and
+--withoutmod-mymodule (the latter being the default)) for py.py and
 translate.py.
 
 Testing modules in ``lib_pypy/``
@@ -931,7 +931,7 @@
             assert self.result == 2 ** 6
 
 which executes the code string function with the given arguments at app level.
-Note the use of ``w_result`` in ``setup_class`` but self.result in the test 
+Note the use of ``w_result`` in ``setup_class`` but self.result in the test.
 Here is how to define an app level class  in ``setup_class`` that can be used
 in subsequent tests::
 
diff --git a/pypy/doc/cpython_differences.rst b/pypy/doc/cpython_differences.rst
--- a/pypy/doc/cpython_differences.rst
+++ b/pypy/doc/cpython_differences.rst
@@ -74,9 +74,6 @@
     zipimport
     zlib
 
-  When translated to Java or .NET, the list is smaller; see
-  `pypy/config/pypyoption.py`_ for details.
-
   When translated on Windows, a few Unix-only modules are skipped,
   and the following module is built instead:
 
@@ -328,7 +325,7 @@
 * directly calling the internal magic methods of a few built-in types
   with invalid arguments may have a slightly different result.  For
   example, ``[].__add__(None)`` and ``(2).__add__(None)`` both return
-  ``NotImplemented`` on PyPy; on CPython, only the later does, and the
+  ``NotImplemented`` on PyPy; on CPython, only the latter does, and the
   former raises ``TypeError``.  (Of course, ``[]+None`` and ``2+None``
   both raise ``TypeError`` everywhere.)  This difference is an
   implementation detail that shows up because of internal C-level slots
diff --git a/pypy/doc/faq.rst b/pypy/doc/faq.rst
--- a/pypy/doc/faq.rst
+++ b/pypy/doc/faq.rst
@@ -171,16 +171,21 @@
 You might be interested in our `benchmarking site`_ and our 
 `jit documentation`_.
 
-Note that the JIT has a very high warm-up cost, meaning that the
-programs are slow at the beginning.  If you want to compare the timings
-with CPython, even relatively simple programs need to run *at least* one
-second, preferrably at least a few seconds.  Large, complicated programs
-need even more time to warm-up the JIT.
+`Your tests are not a benchmark`_: tests tend to be slow under PyPy
+because they run exactly once; if they are good tests, they exercise
+various corner cases in your code.  This is a bad case for JIT
+compilers.  Note also that our JIT has a very high warm-up cost, meaning
+that any program is slow at the beginning.  If you want to compare the
+timings with CPython, even relatively simple programs need to run *at
+least* one second, preferrably at least a few seconds.  Large,
+complicated programs need even more time to warm-up the JIT.
 
 .. _`benchmarking site`: http://speed.pypy.org
 
 .. _`jit documentation`: jit/index.html
 
+.. _`your tests are not a benchmark`: 
http://alexgaynor.net/2013/jul/15/your-tests-are-not-benchmark/
+
 ---------------------------------------------------------------
 Couldn't the JIT dump and reload already-compiled machine code?
 ---------------------------------------------------------------
diff --git a/pypy/doc/getting-started-python.rst 
b/pypy/doc/getting-started-python.rst
--- a/pypy/doc/getting-started-python.rst
+++ b/pypy/doc/getting-started-python.rst
@@ -50,6 +50,8 @@
      libz-dev libbz2-dev libncurses-dev libexpat1-dev \
      libssl-dev libgc-dev python-sphinx python-greenlet
 
+   For the optional lzma module on PyPy3 you will also need ``liblzma-dev``.
+
    On a Fedora-16 box these are::
 
      [user@fedora-or-rh-box ~]$ sudo yum install \
@@ -57,6 +59,8 @@
      zlib-devel bzip2-devel ncurses-devel expat-devel \
      openssl-devel gc-devel python-sphinx python-greenlet
 
+   For the optional lzma module on PyPy3 you will also need ``xz-devel``.
+
    On SLES11:
 
      $ sudo zypper install gcc make python-devel pkg-config \
@@ -74,6 +78,7 @@
    * ``pkg-config`` (to help us locate libffi files)
    * ``libz-dev`` (for the optional ``zlib`` module)
    * ``libbz2-dev`` (for the optional ``bz2`` module)
+   * ``liblzma`` (for the optional ``lzma`` module, PyPy3 only)
    * ``libsqlite3-dev`` (for the optional ``sqlite3`` module via cffi)
    * ``libncurses-dev`` (for the optional ``_minimal_curses`` module)
    * ``libexpat1-dev`` (for the optional ``pyexpat`` module)
diff --git a/pypy/doc/index.rst b/pypy/doc/index.rst
--- a/pypy/doc/index.rst
+++ b/pypy/doc/index.rst
@@ -102,7 +102,7 @@
 .. _Python: http://docs.python.org/index.html
 .. _`more...`: architecture.html#mission-statement 
 .. _`PyPy blog`: http://morepypy.blogspot.com/
-.. _`development bug/feature tracker`: https://bugs.pypy.org
+.. _`development bug/feature tracker`: https://bitbucket.org/pypy/pypy/issues
 .. _here: http://www.tismer.com/pypy/irc-logs/pypy/
 .. _`Mercurial commit mailing list`: 
http://mail.python.org/mailman/listinfo/pypy-commit
 .. _`development mailing list`: 
http://mail.python.org/mailman/listinfo/pypy-dev
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
@@ -34,7 +34,7 @@
     aborted due to some reason.
 
     The hook will be invoked with the siagnture:
-    ``hook(jitdriver_name, greenkey, reason)``
+    ``hook(jitdriver_name, greenkey, reason, oplist)``
 
     Reason is a string, the meaning of other arguments is the same
     as attributes on JitLoopInfo object
diff --git a/pypy/doc/stm.rst b/pypy/doc/stm.rst
--- a/pypy/doc/stm.rst
+++ b/pypy/doc/stm.rst
@@ -28,7 +28,8 @@
 Introduction
 ============
 
-``pypy-stm`` is a variant of the regular PyPy interpreter.  With caveats_
+``pypy-stm`` is a variant of the regular PyPy interpreter.  (This
+version supports Python 2.7; see below for `Python 3`_.)  With caveats_
 listed below, it should be in theory within 20%-50% slower than a
 regular PyPy, comparing the JIT version in both cases (but see below!).
 It is called
@@ -137,6 +138,25 @@
 
 
 
+Python 3
+========
+
+In this document I describe "pypy-stm", which is based on PyPy's Python
+2.7 interpreter.  Supporting Python 3 should take about half an
+afternoon of work.  Obviously, what I *don't* mean is that by tomorrow
+you can have a finished and polished "pypy3-stm" product.  General py3k
+work is still missing; and general stm work is also still missing.  But
+they are rather independent from each other, as usual in PyPy.  The
+required afternoon of work will certainly be done one of these days now
+that the internal interfaces seem to stabilize.
+
+The same is true for other languages implemented in the RPython
+framework, although the amount of work to put there might vary, because
+the STM framework within RPython is currently targeting the PyPy
+interpreter and other ones might have slightly different needs.
+
+
+
 User Guide
 ==========
   
@@ -489,8 +509,6 @@
 The last two lines are special; they are an internal marker read by
 ``transactional_memory.print_abort_info()``.
 
-These statistics are not printed out for the main thread, for now.
-
 
 Reference to implementation details
 -----------------------------------
diff --git a/pypy/doc/you-want-to-help.rst b/pypy/doc/you-want-to-help.rst
--- a/pypy/doc/you-want-to-help.rst
+++ b/pypy/doc/you-want-to-help.rst
@@ -15,14 +15,14 @@
 * Because of the above, we are very serious about Test Driven Development.
   It's not only what we believe in, but also that PyPy's architecture is
   working very well with TDD in mind and not so well without it. Often
-  the development means progressing in an unrelated corner, one unittest
+  development means progressing in an unrelated corner, one unittest
   at a time; and then flipping a giant switch, bringing it all together.
   (It generally works out of the box.  If it doesn't, then we didn't
-  write enough unit tests.)  It's worth repeating - PyPy
-  approach is great if you do TDD, not so great otherwise.
+  write enough unit tests.)  It's worth repeating - PyPy's
+  approach is great if you do TDD, and not so great otherwise.
 
 * PyPy uses an entirely different set of tools - most of them included
-  in the PyPy repository. There is no Makefile, nor autoconf. More below
+  in the PyPy repository. There is no Makefile, nor autoconf. More below.
 
 Architecture
 ============
@@ -32,7 +32,7 @@
 * `RPython`_ is the language in which we write interpreters. Not the entire
   PyPy project is written in RPython, only the parts that are compiled in
   the translation process. The interesting point is that RPython has no parser,
-  it's compiled from the live python objects, which make it possible to do
+  it's compiled from the live python objects, which makes it possible to do
   all kinds of metaprogramming during import time. In short, Python is a meta
   programming language for RPython.
 
@@ -40,7 +40,7 @@
 
 .. _`RPython`: coding-guide.html#RPython
 
-* The translation toolchain - this is the part that takes care about 
translating
+* The translation toolchain - this is the part that takes care of translating
   RPython to flow graphs and then to C. There is more in the `architecture`_
   document written about it.
 
@@ -73,7 +73,7 @@
 
 .. _`we have a tracing JIT`: jit/index.html
 
-* Garbage Collectors (GC): as you can notice if you are used to CPython's
+* Garbage Collectors (GC): as you may notice if you are used to CPython's
   C code, there are no ``Py_INCREF/Py_DECREF`` equivalents in RPython code.
   `Garbage collection in PyPy`_ is inserted
   during translation.  Moreover, this is not reference counting; it is a real
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -665,8 +665,11 @@
         else:
             # translated case follows.  self.threadlocals is either from
             # 'pypy.interpreter.miscutils' or 
'pypy.module.thread.threadlocals'.
-            # the result is assumed to be non-null: enter_thread() was called.
-            return self.threadlocals.get_ec()
+            # the result is assumed to be non-null: enter_thread() was called
+            # by space.startup().
+            ec = self.threadlocals.get_ec()
+            assert ec is not None
+            return ec
 
     def _freeze_(self):
         return True
@@ -1498,9 +1501,7 @@
             return buf.as_str()
 
     def str_or_None_w(self, w_obj):
-        if self.is_w(w_obj, self.w_None):
-            return None
-        return self.str_w(w_obj)
+        return None if self.is_none(w_obj) else self.str_w(w_obj)
 
     def str_w(self, w_obj):
         return w_obj.str_w(self)
diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py
--- a/pypy/interpreter/function.py
+++ b/pypy/interpreter/function.py
@@ -616,7 +616,8 @@
     def descr_classmethod_get(self, space, w_obj, w_klass=None):
         if space.is_none(w_klass):
             w_klass = space.type(w_obj)
-        return space.wrap(Method(space, self.w_function, w_klass, 
space.w_None))
+        return space.wrap(Method(space, self.w_function, w_klass,
+                                 space.type(w_klass)))
 
     def descr_classmethod__new__(space, w_subtype, w_function):
         instance = space.allocate_instance(ClassMethod, w_subtype)
diff --git a/pypy/interpreter/pycompiler.py b/pypy/interpreter/pycompiler.py
--- a/pypy/interpreter/pycompiler.py
+++ b/pypy/interpreter/pycompiler.py
@@ -96,7 +96,7 @@
 
     XXX: This class should override the baseclass implementation of
          compile_command() in order to optimize it, especially in case
-         of incomplete inputs (e.g. we shouldn't re-compile from sracth
+         of incomplete inputs (e.g. we shouldn't re-compile from scratch
          the whole source after having only added a new '\n')
     """
     def __init__(self, space, override_version=None):
diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py
--- a/pypy/interpreter/pyopcode.py
+++ b/pypy/interpreter/pyopcode.py
@@ -200,7 +200,7 @@
             elif opcode == opcodedesc.BREAK_LOOP.index:
                 next_instr = self.BREAK_LOOP(oparg, next_instr)
             elif opcode == opcodedesc.CONTINUE_LOOP.index:
-                next_instr = self.CONTINUE_LOOP(oparg, next_instr)
+                return self.CONTINUE_LOOP(oparg, next_instr)
             elif opcode == opcodedesc.FOR_ITER.index:
                 next_instr = self.FOR_ITER(oparg, next_instr)
             elif opcode == opcodedesc.JUMP_FORWARD.index:
diff --git a/pypy/interpreter/test/test_generator.py 
b/pypy/interpreter/test/test_generator.py
--- a/pypy/interpreter/test/test_generator.py
+++ b/pypy/interpreter/test/test_generator.py
@@ -17,7 +17,7 @@
             yield 1
             assert g.gi_running
         g = f()
-        assert g.gi_code is f.func_code
+        assert g.gi_code is f.__code__
         assert g.__name__ == 'f'
         assert g.gi_frame is not None
         assert not g.gi_running
@@ -26,7 +26,7 @@
         raises(StopIteration, g.next)
         assert not g.gi_running
         assert g.gi_frame is None
-        assert g.gi_code is f.func_code
+        assert g.gi_code is f.__code__
         assert g.__name__ == 'f'
 
     def test_generator3(self):
@@ -286,13 +286,13 @@
     w_co = space.appexec([], '''():
         def g(x):
             yield x + 5
-        return g.func_code
+        return g.__code__
     ''')
     assert should_not_inline(w_co) == False
     w_co = space.appexec([], '''():
         def g(x):
             yield x + 5
             yield x + 6
-        return g.func_code
+        return g.__code__
     ''')
     assert should_not_inline(w_co) == True
diff --git a/pypy/interpreter/test/test_typedef.py 
b/pypy/interpreter/test/test_typedef.py
--- a/pypy/interpreter/test/test_typedef.py
+++ b/pypy/interpreter/test/test_typedef.py
@@ -388,6 +388,13 @@
         # differs from .im_class in case the method is
         # defined in some parent class of l's actual class
 
+    def test_classmethod_im_class(self):
+        class Foo(object):
+            @classmethod
+            def bar(cls):
+                pass
+        assert Foo.bar.im_class is type
+
     def test_func_closure(self):
         x = 2
         def f():
diff --git a/pypy/module/__builtin__/app_inspect.py 
b/pypy/module/__builtin__/app_inspect.py
--- a/pypy/module/__builtin__/app_inspect.py
+++ b/pypy/module/__builtin__/app_inspect.py
@@ -7,8 +7,8 @@
 
 from __pypy__ import lookup_special
 
-def _caller_locals(): 
-    return sys._getframe(0).f_locals 
+def _caller_locals():
+    return sys._getframe(0).f_locals
 
 def vars(*obj):
     """Return a dictionary of all the attributes currently bound in obj.  If
@@ -17,12 +17,11 @@
     if len(obj) == 0:
         return _caller_locals()
     elif len(obj) != 1:
-        raise TypeError, "vars() takes at most 1 argument."
-    else:
-        try:
-            return obj[0].__dict__
-        except AttributeError:
-            raise TypeError, "vars() argument must have __dict__ attribute"
+        raise TypeError("vars() takes at most 1 argument.")
+    try:
+        return obj[0].__dict__
+    except AttributeError:
+        raise TypeError("vars() argument must have __dict__ attribute")
 
 def dir(*args):
     """dir([object]) -> list of strings
@@ -38,8 +37,7 @@
         attributes of its class's base classes.
     """
     if len(args) > 1:
-        raise TypeError("dir expected at most 1 arguments, got %d"
-                        % len(args))
+        raise TypeError("dir expected at most 1 arguments, got %d" % len(args))
     if len(args) == 0:
         local_names = _caller_locals().keys() # 2 stackframes away
         if not isinstance(local_names, list):
@@ -48,92 +46,61 @@
         return local_names
 
     import types
-
     obj = args[0]
-
-    dir_meth = None
     if isinstance(obj, types.InstanceType):
-        try:
-            dir_meth = getattr(obj, "__dir__")
-        except AttributeError:
-            pass
+        dir_meth = getattr(obj, '__dir__', None)
     else:
-        dir_meth = lookup_special(obj, "__dir__")
+        dir_meth = lookup_special(obj, '__dir__')
     if dir_meth is not None:
-        result = dir_meth()
-        if not isinstance(result, list):
+        names = dir_meth()
+        if not isinstance(names, list):
             raise TypeError("__dir__() must return a list, not %r" % (
-                type(result),))
-        result.sort()
-        return result
+                type(names),))
+        names.sort()
+        return names
     elif isinstance(obj, types.ModuleType):
         try:
-            result = list(obj.__dict__)
-            result.sort()
-            return result
+            return sorted(obj.__dict__)
         except AttributeError:
             return []
-
     elif isinstance(obj, (types.TypeType, types.ClassType)):
-        #Don't look at __class__, as metaclass methods would be confusing.
-        result = _classdir(obj).keys()
-        result.sort()
-        return result
-
-    else: #(regular item)
-        Dict = {}
-        try:
-            if isinstance(obj.__dict__, dict):
-                Dict.update(obj.__dict__)
-        except AttributeError:
-            pass
-        try:
-            Dict.update(_classdir(obj.__class__))
-        except AttributeError:
-            pass
+        # Don't look at __class__, as metaclass methods would be confusing.
+        return sorted(_classdir(obj))
+    else:
+        names = set()
+        ns = getattr(obj, '__dict__', None)
+        if isinstance(ns, dict):
+            names.update(ns)
+        klass = getattr(obj, '__class__', None)
+        if klass is not None:
+            names.update(_classdir(klass))
 
         ## Comment from object.c:
         ## /* Merge in __members__ and __methods__ (if any).
         ## XXX Would like this to go away someday; for now, it's
         ## XXX needed to get at im_self etc of method objects. */
-        for attr in ['__members__','__methods__']:
-            try:
-                l = getattr(obj, attr)
-                if not isinstance(l, list):
-                    continue
-                for item in l:
-                    if isinstance(item, types.StringTypes):
-                        Dict[item] = None
-            except (AttributeError, TypeError):
-                pass
+        for attr in '__members__', '__methods__':
+            l = getattr(obj, attr, None)
+            if not isinstance(l, list):
+                continue
+            names.extend(item for item in l if isinstance(item, str))
 
-        result = Dict.keys()
-        result.sort()
-        return result
+        return sorted(names)
 
 def _classdir(klass):
-    """Return a dict of the accessible attributes of class/type klass.
+    """Return a set of the accessible attributes of class/type klass.
 
-    This includes all attributes of klass and all of the
-    base classes recursively.
-
-    The values of this dict have no meaning - only the keys have
-    meaning.  
+    This includes all attributes of klass and all of the base classes
+    recursively.
     """
-    Dict = {}
-    try:
-        Dict.update(klass.__dict__)
-    except AttributeError: pass 
-    try:
-        # XXX - Use of .__mro__ would be suggested, if the existance
-        #   of that attribute could be guarranted.
-        bases = klass.__bases__
-    except AttributeError: pass
-    else:
-        try:
-            #Note that since we are only interested in the keys,
-            #  the order we merge classes is unimportant
-            for base in bases:
-                Dict.update(_classdir(base))
-        except TypeError: pass
-    return Dict
+    names = set()
+    ns = getattr(klass, '__dict__', None)
+    if ns is not None:
+        names.update(ns)
+    bases = getattr(klass, '__bases__', None)
+    if bases is not None:
+        # Note that since we are only interested in the keys, the order
+        # we merge classes is unimportant
+        for base in bases:
+            names.update(_classdir(base))
+    return names
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
@@ -73,13 +73,12 @@
         'builtinify'                : 'interp_magic.builtinify',
         'lookup_special'            : 'interp_magic.lookup_special',
         'do_what_I_mean'            : 'interp_magic.do_what_I_mean',
-        'list_strategy'             : 'interp_magic.list_strategy',
         'validate_fd'               : 'interp_magic.validate_fd',
         'resizelist_hint'           : 'interp_magic.resizelist_hint',
         'newlist_hint'              : 'interp_magic.newlist_hint',
         'add_memory_pressure'       : 'interp_magic.add_memory_pressure',
         'newdict'                   : 'interp_dict.newdict',
-        'dictstrategy'              : 'interp_dict.dictstrategy',
+        'strategy'                  : 'interp_magic.strategy',  # dict,set,list
         'set_debug'                 : 'interp_magic.set_debug',
         'locals_to_fast'            : 'interp_magic.locals_to_fast',
     }
diff --git a/pypy/module/__pypy__/interp_dict.py 
b/pypy/module/__pypy__/interp_dict.py
--- a/pypy/module/__pypy__/interp_dict.py
+++ b/pypy/module/__pypy__/interp_dict.py
@@ -1,7 +1,6 @@
 
 from pypy.interpreter.error import OperationError, oefmt
 from pypy.interpreter.gateway import unwrap_spec
-from pypy.objspace.std.dictmultiobject import W_DictMultiObject
 
 @unwrap_spec(type=str)
 def newdict(space, type):
@@ -31,13 +30,3 @@
         return space.newdict(strdict=True)
     else:
         raise oefmt(space.w_TypeError, "unknown type of dict %s", type)
-
-def dictstrategy(space, w_obj):
-    """ dictstrategy(dict)
-
-    show the underlaying strategy used by a dict object
-    """
-    if not isinstance(w_obj, W_DictMultiObject):
-        raise OperationError(space.w_TypeError,
-                             space.wrap("expecting dict object"))
-    return space.wrap('%r' % (w_obj.strategy,))
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
@@ -2,7 +2,9 @@
 from pypy.interpreter.gateway import unwrap_spec
 from pypy.interpreter.pyframe import PyFrame
 from rpython.rlib.objectmodel import we_are_translated
+from pypy.objspace.std.dictmultiobject import W_DictMultiObject
 from pypy.objspace.std.listobject import W_ListObject
+from pypy.objspace.std.setobject import W_BaseSetObject
 from pypy.objspace.std.typeobject import MethodCache
 from pypy.objspace.std.mapdict import MapAttrCache
 from rpython.rlib import rposix, rgc
@@ -70,12 +72,23 @@
 def do_what_I_mean(space):
     return space.wrap(42)
 
-def list_strategy(space, w_list):
-    if isinstance(w_list, W_ListObject):
-        return space.wrap(w_list.strategy._applevel_repr)
+
+def strategy(space, w_obj):
+    """ strategy(dict or list or set)
+
+    Return the underlying strategy currently used by a dict, list or set object
+    """
+    if isinstance(w_obj, W_DictMultiObject):
+        name = w_obj.strategy.__class__.__name__
+    elif isinstance(w_obj, W_ListObject):
+        name = w_obj.strategy.__class__.__name__
+    elif isinstance(w_obj, W_BaseSetObject):
+        name = w_obj.strategy.__class__.__name__
     else:
-        w_msg = space.wrap("Can only get the list strategy of a list")
-        raise OperationError(space.w_TypeError, w_msg)
+        raise OperationError(space.w_TypeError,
+                             space.wrap("expecting dict or list or set 
object"))
+    return space.wrap(name)
+
 
 @unwrap_spec(fd='c_int')
 def validate_fd(space, fd):
diff --git a/pypy/module/__pypy__/test/test_special.py 
b/pypy/module/__pypy__/test/test_special.py
--- a/pypy/module/__pypy__/test/test_special.py
+++ b/pypy/module/__pypy__/test/test_special.py
@@ -46,26 +46,42 @@
         assert x == 42
 
     def test_list_strategy(self):
-        from __pypy__ import list_strategy
+        from __pypy__ import strategy
 
         l = [1, 2, 3]
-        assert list_strategy(l) == "int"
+        assert strategy(l) == "IntegerListStrategy"
         l = ["a", "b", "c"]
-        assert list_strategy(l) == "bytes"
+        assert strategy(l) == "BytesListStrategy"
         l = [u"a", u"b", u"c"]
-        assert list_strategy(l) == "unicode"
+        assert strategy(l) == "UnicodeListStrategy"
         l = [1.1, 2.2, 3.3]
-        assert list_strategy(l) == "float"
+        assert strategy(l) == "FloatListStrategy"
         l = range(3)
-        assert list_strategy(l) == "simple_range"
+        assert strategy(l) == "SimpleRangeListStrategy"
         l = range(1, 2)
-        assert list_strategy(l) == "range"
+        assert strategy(l) == "RangeListStrategy"
         l = [1, "b", 3]
-        assert list_strategy(l) == "object"
+        assert strategy(l) == "ObjectListStrategy"
         l = []
-        assert list_strategy(l) == "empty"
+        assert strategy(l) == "EmptyListStrategy"
         o = 5
-        raises(TypeError, list_strategy, 5)
+        raises(TypeError, strategy, 5)
+
+    def test_dict_strategy(self):
+        from __pypy__ import strategy
+
+        d = {}
+        assert strategy(d) == "EmptyDictStrategy"
+        d = {1: None, 5: None}
+        assert strategy(d) == "IntDictStrategy"
+
+    def test_set_strategy(self):
+        from __pypy__ import strategy
+
+        s = set()
+        assert strategy(s) == "EmptySetStrategy"
+        s = set([2, 3, 4])
+        assert strategy(s) == "IntegerSetStrategy"
 
 
 class AppTestJitFeatures(object):
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.2")',
+        '__version__': 'space.wrap("0.8.6")',
 
         'load_library': 'libraryobj.load_library',
 
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
@@ -3188,4 +3188,4 @@
 
 def test_version():
     # this test is here mostly for PyPy
-    assert __version__ == "0.8.2"
+    assert __version__ == "0.8.6"
diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py
--- a/pypy/module/_ssl/interp_ssl.py
+++ b/pypy/module/_ssl/interp_ssl.py
@@ -1,14 +1,12 @@
-from __future__ import with_statement
-from rpython.rtyper.lltypesystem import rffi, lltype
+from rpython.rlib import rpoll, rsocket
+from rpython.rlib.rarithmetic import intmask
+from rpython.rlib.ropenssl import *
+from rpython.rtyper.lltypesystem import lltype, rffi
+
+from pypy.interpreter.baseobjspace import W_Root
 from pypy.interpreter.error import OperationError
-from pypy.interpreter.baseobjspace import W_Root
+from pypy.interpreter.gateway import interp2app, unwrap_spec
 from pypy.interpreter.typedef import TypeDef
-from pypy.interpreter.gateway import interp2app, unwrap_spec
-
-from rpython.rlib.rarithmetic import intmask
-from rpython.rlib import rpoll, rsocket
-from rpython.rlib.ropenssl import *
-
 from pypy.module._socket import interp_socket
 
 
@@ -83,19 +81,15 @@
 
         Mix string into the OpenSSL PRNG state.  entropy (a float) is a lower
         bound on the entropy contained in string."""
-
-        buf = rffi.str2charp(string)
-        try:
+        with rffi.scoped_str2charp(string) as buf:
             libssl_RAND_add(buf, len(string), entropy)
-        finally:
-            rffi.free_charp(buf)
 
     def RAND_status(space):
         """RAND_status() -> 0 or 1
 
-        Returns 1 if the OpenSSL PRNG has been seeded with enough data and 0 
if not.
-        It is necessary to seed the PRNG with RAND_add() on some platforms 
before
-        using the ssl() function."""
+        Returns 1 if the OpenSSL PRNG has been seeded with enough data
+        and 0 if not.  It is necessary to seed the PRNG with RAND_add()
+        on some platforms before using the ssl() function."""
 
         res = libssl_RAND_status()
         return space.wrap(res)
@@ -107,16 +101,12 @@
         Queries the entropy gather daemon (EGD) on socket path.  Returns number
         of bytes read.  Raises socket.sslerror if connection to EGD fails or
         if it does provide enough data to seed PRNG."""
-
-        socket_path = rffi.str2charp(path)
-        try:
+        with rffi.scoped_str2charp(path) as socket_path:
             bytes = libssl_RAND_egd(socket_path)
-        finally:
-            rffi.free_charp(socket_path)
         if bytes == -1:
-            msg = "EGD connection failed or EGD did not return"
-            msg += " enough data to seed the PRNG"
-            raise ssl_error(space, msg)
+            raise ssl_error(space,
+                            "EGD connection failed or EGD did not return "
+                            "enough data to seed the PRNG")
         return space.wrap(bytes)
 
 
@@ -127,17 +117,19 @@
         self.ctx = lltype.nullptr(SSL_CTX.TO)
         self.ssl = lltype.nullptr(SSL.TO)
         self.peer_cert = lltype.nullptr(X509.TO)
-        self._server = lltype.malloc(rffi.CCHARP.TO, X509_NAME_MAXLEN, 
flavor='raw')
+        self._server = lltype.malloc(rffi.CCHARP.TO, X509_NAME_MAXLEN,
+                                     flavor='raw')
         self._server[0] = '\0'
-        self._issuer = lltype.malloc(rffi.CCHARP.TO, X509_NAME_MAXLEN, 
flavor='raw')
+        self._issuer = lltype.malloc(rffi.CCHARP.TO, X509_NAME_MAXLEN,
+                                     flavor='raw')
         self._issuer[0] = '\0'
         self.shutdown_seen_zero = False
 
-    def server(self):
-        return self.space.wrap(rffi.charp2str(self._server))
+    def server(self, space):
+        return space.wrap(rffi.charp2str(self._server))
 
-    def issuer(self):
-        return self.space.wrap(rffi.charp2str(self._issuer))
+    def issuer(self, space):
+        return space.wrap(rffi.charp2str(self._issuer))
 
     def __del__(self):
         self.enqueue_for_destruction(self.space, SSLObject.destructor,
@@ -155,21 +147,20 @@
         lltype.free(self._issuer, flavor='raw')
 
     @unwrap_spec(data='bufferstr')
-    def write(self, data):
+    def write(self, space, data):
         """write(s) -> len
 
         Writes the string s into the SSL object.  Returns the number
         of bytes written."""
-        self._refresh_nonblocking(self.space)
+        self._refresh_nonblocking(space)
 
-        sockstate = check_socket_and_wait_for_timeout(self.space,
-            self.w_socket, True)
+        sockstate = checkwait(space, self.w_socket, True)
         if sockstate == SOCKET_HAS_TIMED_OUT:
-            raise ssl_error(self.space, "The write operation timed out")
+            raise ssl_error(space, "The write operation timed out")
         elif sockstate == SOCKET_HAS_BEEN_CLOSED:
-            raise ssl_error(self.space, "Underlying socket has been closed.")
+            raise ssl_error(space, "Underlying socket has been closed.")
         elif sockstate == SOCKET_TOO_LARGE_FOR_SELECT:
-            raise ssl_error(self.space, "Underlying socket too large for 
select().")
+            raise ssl_error(space, "Underlying socket too large for select().")
 
         num_bytes = 0
         while True:
@@ -179,18 +170,16 @@
             err = libssl_SSL_get_error(self.ssl, num_bytes)
 
             if err == SSL_ERROR_WANT_READ:
-                sockstate = check_socket_and_wait_for_timeout(self.space,
-                    self.w_socket, False)
+                sockstate = checkwait(space, self.w_socket, False)
             elif err == SSL_ERROR_WANT_WRITE:
-                sockstate = check_socket_and_wait_for_timeout(self.space,
-                    self.w_socket, True)
+                sockstate = checkwait(space, self.w_socket, True)
             else:
                 sockstate = SOCKET_OPERATION_OK
 
             if sockstate == SOCKET_HAS_TIMED_OUT:
-                raise ssl_error(self.space, "The write operation timed out")
+                raise ssl_error(space, "The write operation timed out")
             elif sockstate == SOCKET_HAS_BEEN_CLOSED:
-                raise ssl_error(self.space, "Underlying socket has been 
closed.")
+                raise ssl_error(space, "Underlying socket has been closed.")
             elif sockstate == SOCKET_IS_NONBLOCKING:
                 break
 
@@ -200,38 +189,38 @@
                 break
 
         if num_bytes > 0:
-            return self.space.wrap(num_bytes)
+            return space.wrap(num_bytes)
         else:
-            raise _ssl_seterror(self.space, self, num_bytes)
+            raise _ssl_seterror(space, self, num_bytes)
 
-    def pending(self):
+    def pending(self, space):
         """pending() -> count
 
         Returns the number of already decrypted bytes available for read,
         pending on the connection."""
         count = libssl_SSL_pending(self.ssl)
         if count < 0:
-            raise _ssl_seterror(self.space, self, count)
-        return self.space.wrap(count)
+            raise _ssl_seterror(space, self, count)
+        return space.wrap(count)
 
     @unwrap_spec(num_bytes=int)
-    def read(self, num_bytes=1024):
+    def read(self, space, num_bytes=1024):
         """read([len]) -> string
 
         Read up to len bytes from the SSL socket."""
-
         count = libssl_SSL_pending(self.ssl)
         if not count:
-            sockstate = check_socket_and_wait_for_timeout(self.space,
-                self.w_socket, False)
+            sockstate = checkwait(space, self.w_socket, False)
             if sockstate == SOCKET_HAS_TIMED_OUT:
-                raise ssl_error(self.space, "The read operation timed out")
+                raise ssl_error(space, "The read operation timed out")
             elif sockstate == SOCKET_TOO_LARGE_FOR_SELECT:
-                raise ssl_error(self.space, "Underlying socket too large for 
select().")
+                raise ssl_error(space,
+                                "Underlying socket too large for select().")
             elif sockstate == SOCKET_HAS_BEEN_CLOSED:
                 if libssl_SSL_get_shutdown(self.ssl) == SSL_RECEIVED_SHUTDOWN:
-                    return self.space.wrap('')
-                raise ssl_error(self.space, "Socket closed without SSL 
shutdown handshake")
+                    return space.wrap('')
+                raise ssl_error(space,
+                                "Socket closed without SSL shutdown handshake")
 
         with rffi.scoped_alloc_buffer(num_bytes) as buf:
             while True:
@@ -241,19 +230,17 @@
                 err = libssl_SSL_get_error(self.ssl, count)
 
                 if err == SSL_ERROR_WANT_READ:
-                    sockstate = check_socket_and_wait_for_timeout(self.space,
-                        self.w_socket, False)
+                    sockstate = checkwait(space, self.w_socket, False)
                 elif err == SSL_ERROR_WANT_WRITE:
-                    sockstate = check_socket_and_wait_for_timeout(self.space,
-                        self.w_socket, True)
+                    sockstate = checkwait(space, self.w_socket, True)
                 elif (err == SSL_ERROR_ZERO_RETURN and
                    libssl_SSL_get_shutdown(self.ssl) == SSL_RECEIVED_SHUTDOWN):
-                    return self.space.wrap("")
+                    return space.wrap("")
                 else:
                     sockstate = SOCKET_OPERATION_OK
 
                 if sockstate == SOCKET_HAS_TIMED_OUT:
-                    raise ssl_error(self.space, "The read operation timed out")
+                    raise ssl_error(space, "The read operation timed out")
                 elif sockstate == SOCKET_IS_NONBLOCKING:
                     break
 
@@ -263,11 +250,11 @@
                     break
 
             if count <= 0:
-                raise _ssl_seterror(self.space, self, count)
+                raise _ssl_seterror(space, self, count)
 
             result = buf.str(count)
 
-        return self.space.wrap(result)
+        return space.wrap(result)
 
     def _refresh_nonblocking(self, space):
         # just in case the blocking state of the socket has been changed
@@ -286,11 +273,9 @@
             err = libssl_SSL_get_error(self.ssl, ret)
             # XXX PyErr_CheckSignals()
             if err == SSL_ERROR_WANT_READ:
-                sockstate = check_socket_and_wait_for_timeout(
-                    space, self.w_socket, False)
+                sockstate = checkwait(space, self.w_socket, False)
             elif err == SSL_ERROR_WANT_WRITE:
-                sockstate = check_socket_and_wait_for_timeout(
-                    space, self.w_socket, True)
+                sockstate = checkwait(space, self.w_socket, True)
             else:
                 sockstate = SOCKET_OPERATION_OK
             if sockstate == SOCKET_HAS_TIMED_OUT:
@@ -298,7 +283,8 @@
             elif sockstate == SOCKET_HAS_BEEN_CLOSED:
                 raise ssl_error(space, "Underlying socket has been closed.")
             elif sockstate == SOCKET_TOO_LARGE_FOR_SELECT:
-                raise ssl_error(space, "Underlying socket too large for 
select().")
+                raise ssl_error(space,
+                                "Underlying socket too large for select().")
             elif sockstate == SOCKET_IS_NONBLOCKING:
                 break
 
@@ -330,7 +316,6 @@
         self._refresh_nonblocking(space)
 
         zeros = 0
-
         while True:
             # Disable read-ahead so that unwrap can work correctly.
             # Otherwise OpenSSL might read in too much data,
@@ -360,21 +345,20 @@
             # Possibly retry shutdown until timeout or failure
             ssl_err = libssl_SSL_get_error(self.ssl, ret)
             if ssl_err == SSL_ERROR_WANT_READ:
-                sockstate = check_socket_and_wait_for_timeout(
-                    self.space, self.w_socket, False)
+                sockstate = checkwait(space, self.w_socket, False)
             elif ssl_err == SSL_ERROR_WANT_WRITE:
-                sockstate = check_socket_and_wait_for_timeout(
-                    self.space, self.w_socket, True)
+                sockstate = checkwait(space, self.w_socket, True)
             else:
                 break
 
             if sockstate == SOCKET_HAS_TIMED_OUT:
                 if ssl_err == SSL_ERROR_WANT_READ:
-                    raise ssl_error(self.space, "The read operation timed out")
+                    raise ssl_error(space, "The read operation timed out")
                 else:
-                    raise ssl_error(self.space, "The write operation timed 
out")
+                    raise ssl_error(space, "The write operation timed out")
             elif sockstate == SOCKET_TOO_LARGE_FOR_SELECT:
-                raise ssl_error(space, "Underlying socket too large for 
select().")
+                raise ssl_error(space,
+                                "Underlying socket too large for select().")
             elif sockstate != SOCKET_OPERATION_OK:
                 # Retain the SSL error code
                 break
@@ -392,37 +376,31 @@
             return space.w_None
 
         name = libssl_SSL_CIPHER_get_name(current)
-        if name:
-            w_name = space.wrap(rffi.charp2str(name))
-        else:
-            w_name = space.w_None
+        w_name = space.wrap(rffi.charp2str(name)) if name else space.w_None
 
         proto = libssl_SSL_CIPHER_get_version(current)
-        if proto:
-            w_proto = space.wrap(rffi.charp2str(proto))
-        else:
-            w_proto = space.w_None
+        w_proto = space.wrap(rffi.charp2str(proto)) if proto else space.w_None
 
         bits = libssl_SSL_CIPHER_get_bits(current,
                                           lltype.nullptr(rffi.INTP.TO))
         w_bits = space.newint(bits)
-
         return space.newtuple([w_name, w_proto, w_bits])
 
     @unwrap_spec(der=bool)
-    def peer_certificate(self, der=False):
+    def peer_certificate(self, space, der=False):
         """peer_certificate([der=False]) -> certificate
 
-        Returns the certificate for the peer.  If no certificate was provided,
-        returns None.  If a certificate was provided, but not validated, 
returns
-        an empty dictionary.  Otherwise returns a dict containing information
-        about the peer certificate.
+        Returns the certificate for the peer.  If no certificate was
+        provided, returns None.  If a certificate was provided, but not
+        validated, returns an empty dictionary.  Otherwise returns a
+        dict containing information about the peer certificate.
 
-        If the optional argument is True, returns a DER-encoded copy of the
-        peer certificate, or None if no certificate was provided.  This will
-        return the certificate even if it wasn't validated."""
+        If the optional argument is True, returns a DER-encoded copy of
+        the peer certificate, or None if no certificate was provided.
+        This will return the certificate even if it wasn't validated.
+        """
         if not self.peer_cert:
-            return self.space.w_None
+            return space.w_None
 
         if der:
             # return cert in DER-encoded format
@@ -430,20 +408,19 @@
                 buf_ptr[0] = lltype.nullptr(rffi.CCHARP.TO)
                 length = libssl_i2d_X509(self.peer_cert, buf_ptr)
                 if length < 0:
-                    raise _ssl_seterror(self.space, self, length)
+                    raise _ssl_seterror(space, self, length)
                 try:
                     # this is actually an immutable bytes sequence
-                    return self.space.wrap(rffi.charpsize2str(buf_ptr[0],
-                                                              length))
+                    return space.wrap(rffi.charpsize2str(buf_ptr[0], length))
                 finally:
                     libssl_OPENSSL_free(buf_ptr[0])
         else:
             verification = libssl_SSL_CTX_get_verify_mode(
                 libssl_SSL_get_SSL_CTX(self.ssl))
             if not verification & SSL_VERIFY_PEER:
-                return self.space.newdict()
+                return space.newdict()
             else:
-                return _decode_certificate(self.space, self.peer_cert)
+                return _decode_certificate(space, self.peer_cert)
 
 def _decode_certificate(space, certificate, verbose=False):
     w_retval = space.newdict()
@@ -580,15 +557,16 @@
                 name = libssl_sk_GENERAL_NAME_value(names, j)
                 gntype = intmask(name[0].c_type)
                 if gntype == GEN_DIRNAME:
-                    # we special-case DirName as a tuple of tuples of 
attributes
+                    # we special-case DirName as a tuple of tuples of
+                    # attributes
                     dirname = libssl_pypy_GENERAL_NAME_dirn(name)
                     w_t = space.newtuple([
                             space.wrap("DirName"),
                             _create_tuple_for_X509_NAME(space, dirname)
                             ])
                 elif gntype in (GEN_EMAIL, GEN_DNS, GEN_URI):
-                    # GENERAL_NAME_print() doesn't handle NULL bytes in 
ASN1_string
-                    # correctly, CVE-2013-4238
+                    # GENERAL_NAME_print() doesn't handle NULL bytes in
+                    # ASN1_string correctly, CVE-2013-4238
                     if gntype == GEN_EMAIL:
                         v = space.wrap("email")
                     elif gntype == GEN_DNS:
@@ -665,26 +643,11 @@
 
     sock_fd = space.int_w(space.call_method(w_sock, "fileno"))
     w_timeout = space.call_method(w_sock, "gettimeout")
-    if space.is_none(w_timeout):
-        has_timeout = False
-    else:
-        has_timeout = True
-    if space.is_none(w_key_file):
-        key_file = None
-    else:
-        key_file = space.str_w(w_key_file)
-    if space.is_none(w_cert_file):
-        cert_file = None
-    else:
-        cert_file = space.str_w(w_cert_file)
-    if space.is_none(w_cacerts_file):
-        cacerts_file = None
-    else:
-        cacerts_file = space.str_w(w_cacerts_file)
-    if space.is_none(w_ciphers):
-        ciphers = None
-    else:
-        ciphers = space.str_w(w_ciphers)
+    has_timeout = not space.is_none(w_timeout)
+    key_file = space.str_or_None_w(w_key_file)
+    cert_file = space.str_or_None_w(w_cert_file)
+    cacerts_file = space.str_or_None_w(w_cacerts_file)
+    ciphers = space.str_or_None_w(w_ciphers)
 
     if side == PY_SSL_SERVER and (not key_file or not cert_file):
         raise ssl_error(space, "Both the key & certificate files "
@@ -747,8 +710,8 @@
     libssl_SSL_set_fd(ss.ssl, sock_fd) # set the socket for SSL
     # The ACCEPT_MOVING_WRITE_BUFFER flag is necessary because the address
     # of a str object may be changed by the garbage collector.
-    libssl_SSL_set_mode(ss.ssl,
-                        SSL_MODE_AUTO_RETRY | 
SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER)
+    libssl_SSL_set_mode(
+        ss.ssl, SSL_MODE_AUTO_RETRY | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER)
 
     # If the socket is in non-blocking mode or timeout mode, set the BIO
     # to non-blocking mode (blocking is the default)
@@ -765,7 +728,7 @@
     ss.w_socket = w_sock
     return ss
 
-def check_socket_and_wait_for_timeout(space, w_sock, writing):
+def checkwait(space, w_sock, writing):
     """If the socket has a timeout, do a select()/poll() on the socket.
     The argument writing indicates the direction.
     Returns one of the possibilities in the timeout_state enum (above)."""
diff --git a/pypy/module/_winreg/interp_winreg.py 
b/pypy/module/_winreg/interp_winreg.py
--- a/pypy/module/_winreg/interp_winreg.py
+++ b/pypy/module/_winreg/interp_winreg.py
@@ -667,11 +667,6 @@
                                        space.wrap(nValues[0]),
                                        space.wrap(l)])
 
-def str_or_None_w(space, w_obj):
-    if space.is_w(w_obj, space.w_None):
-        return None
-    return space.str_w(w_obj)
-
 def ConnectRegistry(space, w_machine, w_hkey):
     """key = ConnectRegistry(computer_name, key)
 
@@ -683,7 +678,7 @@
 
 The return value is the handle of the opened key.
 If the function fails, an EnvironmentError exception is raised."""
-    machine = str_or_None_w(space, w_machine)
+    machine = space.str_or_None_w(w_machine)
     hkey = hkey_w(w_hkey, space)
     with lltype.scoped_alloc(rwinreg.PHKEY.TO, 1) as rethkey:
         ret = rwinreg.RegConnectRegistry(machine, hkey, rethkey)
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
@@ -228,8 +228,11 @@
         Convert the array to an array of machine values and return the string
         representation.
         """
+        size = self.len
+        if size == 0:
+            return space.wrap('')
         cbuf = self._charbuf_start()
-        s = rffi.charpsize2str(cbuf, self.len * self.itemsize)
+        s = rffi.charpsize2str(cbuf, size * self.itemsize)
         self._charbuf_stop()
         return self.space.wrap(s)
 
diff --git a/pypy/module/array/test/test_array.py 
b/pypy/module/array/test/test_array.py
--- a/pypy/module/array/test/test_array.py
+++ b/pypy/module/array/test/test_array.py
@@ -418,6 +418,10 @@
         assert self.array('u', unicode('hello')).tounicode() == \
                unicode('hello')
 
+    def test_empty_tostring(self):
+        a = self.array('l')
+        assert a.tostring() == b''
+
     def test_buffer(self):
         a = self.array('h', 'Hi')
         buf = buffer(a)
diff --git a/pypy/module/micronumpy/boxes.py b/pypy/module/micronumpy/boxes.py
--- a/pypy/module/micronumpy/boxes.py
+++ b/pypy/module/micronumpy/boxes.py
@@ -511,6 +511,9 @@
             return space.wrap(dtype.itemtype.to_str(read_val))
         return read_val
 
+    def descr_iter(self, space):
+        return space.newseqiter(self)
+
     def descr_setitem(self, space, w_item, w_value):
         if space.isinstance_w(w_item, space.w_basestring):
             item = space.str_w(w_item)
@@ -782,6 +785,7 @@
     __new__ = interp2app(W_VoidBox.descr__new__.im_func),
     __getitem__ = interp2app(W_VoidBox.descr_getitem),
     __setitem__ = interp2app(W_VoidBox.descr_setitem),
+    __iter__ = interp2app(W_VoidBox.descr_iter),
 )
 
 W_CharacterBox.typedef = TypeDef("numpy.character", W_FlexibleBox.typedef,
diff --git a/pypy/module/micronumpy/descriptor.py 
b/pypy/module/micronumpy/descriptor.py
--- a/pypy/module/micronumpy/descriptor.py
+++ b/pypy/module/micronumpy/descriptor.py
@@ -75,7 +75,7 @@
             self.base = subdtype.base
 
     def __repr__(self):
-        if self.fields is not None:
+        if self.fields:
             return '<DType %r>' % self.fields
         return '<DType %r>' % self.itemtype
 
@@ -258,7 +258,7 @@
 
     def _compute_hash(self, space, x):
         from rpython.rlib.rarithmetic import intmask
-        if self.fields is None and self.subdtype is None:
+        if not self.fields and self.subdtype is None:
             endian = self.byteorder
             if endian == NPY.NATIVE:
                 endian = NPY.NATBYTE
@@ -271,7 +271,7 @@
             if self.is_flexible():
                 y = intmask((1000003 * y) ^ self.alignment)
             return intmask((1000003 * x) ^ y)
-        if self.fields is not None:
+        if self.fields:
             for name, (offset, subdtype) in self.fields.iteritems():
                 assert isinstance(subdtype, W_Dtype)
                 y = intmask(1000003 * (0x345678 ^ compute_hash(name)))
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
@@ -428,6 +428,8 @@
         for t in [np.int_, np.float_]:
             dt = np.dtype(t)
             dt1 = dt.newbyteorder().newbyteorder()
+            assert dt.isbuiltin
+            assert not dt1.isbuiltin
             dt2 = dt.newbyteorder("<")
             dt3 = dt.newbyteorder(">")
             assert dt.byteorder != dt1.byteorder
diff --git a/pypy/module/test_lib_pypy/cffi_tests/test_function.py 
b/pypy/module/test_lib_pypy/cffi_tests/test_function.py
--- a/pypy/module/test_lib_pypy/cffi_tests/test_function.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/test_function.py
@@ -403,3 +403,18 @@
             if wr() is not None:
                 import gc; gc.collect()
         assert wr() is None    # 'data' does not leak
+
+    def test_windows_stdcall(self):
+        if sys.platform != 'win32':
+            py.test.skip("Windows-only test")
+        if self.Backend is CTypesBackend:
+            py.test.skip("not with the ctypes backend")
+        ffi = FFI(backend=self.Backend())
+        ffi.cdef("""
+            BOOL QueryPerformanceFrequency(LONGLONG *lpFrequency);
+        """)
+        m = ffi.dlopen("Kernel32.dll")
+        p_freq = ffi.new("LONGLONG *")
+        res = m.QueryPerformanceFrequency(p_freq)
+        assert res != 0
+        assert p_freq[0] != 0
diff --git a/pypy/module/test_lib_pypy/cffi_tests/test_version.py 
b/pypy/module/test_lib_pypy/cffi_tests/test_version.py
--- a/pypy/module/test_lib_pypy/cffi_tests/test_version.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/test_version.py
@@ -6,18 +6,20 @@
     if '_cffi_backend' in sys.builtin_module_names:
         py.test.skip("this is embedded version")
 
-BACKEND_VERSIONS = {
-    '0.4.2': '0.4',     # did not change
-    '0.7.1': '0.7',     # did not change
-    '0.7.2': '0.7',     # did not change
-    '0.8.1': '0.8',     # did not change (essentially)
-    }
+#BACKEND_VERSIONS = {
+#    '0.4.2': '0.4',     # did not change
+#    '0.7.1': '0.7',     # did not change
+#    '0.7.2': '0.7',     # did not change
+#    '0.8.1': '0.8',     # did not change (essentially)
+#    '0.8.4': '0.8.3',   # did not change
+#    }
 
 def test_version():
     v = cffi.__version__
     version_info = '.'.join(str(i) for i in cffi.__version_info__)
     assert v == version_info
-    assert BACKEND_VERSIONS.get(v, v) == _cffi_backend.__version__
+    #v = BACKEND_VERSIONS.get(v, v)
+    assert v == _cffi_backend.__version__
 
 def test_doc_version():
     parent = os.path.dirname(os.path.dirname(__file__))
@@ -48,5 +50,5 @@
     v = cffi.__version__
     p = os.path.join(parent, 'c', 'test_c.py')
     content = open(p).read()
-    assert (('assert __version__ == "%s"' % BACKEND_VERSIONS.get(v, v))
-            in content)
+    #v = BACKEND_VERSIONS.get(v, v)
+    assert (('assert __version__ == "%s"' % v) in content)
diff --git a/pypy/objspace/std/bytearrayobject.py 
b/pypy/objspace/std/bytearrayobject.py
--- a/pypy/objspace/std/bytearrayobject.py
+++ b/pypy/objspace/std/bytearrayobject.py
@@ -41,6 +41,8 @@
         return ''.join(self.data)
 
     def _new(self, value):
+        if value is self.data:
+            value = value[:]
         return W_BytearrayObject(value)
 
     def _new_from_buffer(self, buffer):
diff --git a/pypy/objspace/std/iterobject.py b/pypy/objspace/std/iterobject.py
--- a/pypy/objspace/std/iterobject.py
+++ b/pypy/objspace/std/iterobject.py
@@ -30,10 +30,6 @@
         raise NotImplementedError
 
     def descr_reduce(self, space):
-        """
-        XXX to do: remove this __reduce__ method and do
-        a registration with copy_reg, instead.
-        """
         from pypy.interpreter.mixedmodule import MixedModule
         w_mod = space.getbuiltinmodule('_pickle_support')
         mod = space.interp_w(MixedModule, w_mod)
@@ -125,10 +121,6 @@
         self.index = space.int_w(self.w_len) + index
 
     def descr_reduce(self, space):
-        """
-        XXX to do: remove this __reduce__ method and do
-        a registration with copy_reg, instead.
-        """
         from pypy.interpreter.mixedmodule import MixedModule
         w_mod = space.getbuiltinmodule('_pickle_support')
         mod = space.interp_w(MixedModule, w_mod)
diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py
--- a/pypy/objspace/std/listobject.py
+++ b/pypy/objspace/std/listobject.py
@@ -842,8 +842,6 @@
     W_Lists do not switch back to EmptyListStrategy when becoming empty again.
     """
 
-    _applevel_repr = "empty"
-
     def __init__(self, space):
         ListStrategy.__init__(self, space)
 
@@ -1102,8 +1100,6 @@
        method providing only positive length. The storage is a one element 
tuple
        with positive integer storing length."""
 
-    _applevel_repr = "simple_range"
-
     erase, unerase = rerased.new_erasing_pair("simple_range")
     erase = staticmethod(erase)
     unerase = staticmethod(unerase)
@@ -1176,8 +1172,6 @@
     destroying the range (inserting, appending non-ints) the strategy is
     switched to IntegerListStrategy."""
 
-    _applevel_repr = "range"
-
     erase, unerase = rerased.new_erasing_pair("range")
     erase = staticmethod(erase)
     unerase = staticmethod(unerase)
@@ -1555,7 +1549,6 @@
     import_from_mixin(AbstractUnwrappedStrategy)
 
     _none_value = None
-    _applevel_repr = "object"
 
     def unwrap(self, w_obj):
         return w_obj
@@ -1590,7 +1583,6 @@
     import_from_mixin(AbstractUnwrappedStrategy)
 
     _none_value = 0
-    _applevel_repr = "int"
 
     def wrap(self, intval):
         return self.space.wrap(intval)
@@ -1644,7 +1636,6 @@
     import_from_mixin(AbstractUnwrappedStrategy)
 
     _none_value = 0.0
-    _applevel_repr = "float"
 
     def wrap(self, floatval):
         return self.space.wrap(floatval)
@@ -1677,7 +1668,6 @@
     import_from_mixin(AbstractUnwrappedStrategy)
 
     _none_value = None
-    _applevel_repr = "bytes"
 
     def wrap(self, stringval):
         return self.space.wrap(stringval)
@@ -1710,7 +1700,6 @@
     import_from_mixin(AbstractUnwrappedStrategy)
 
     _none_value = None
-    _applevel_repr = "unicode"
 
     def wrap(self, stringval):
         return self.space.wrap(stringval)
diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py
--- a/pypy/objspace/std/setobject.py
+++ b/pypy/objspace/std/setobject.py
@@ -1060,10 +1060,14 @@
         return storage, strategy
 
     def symmetric_difference(self, w_set, w_other):
+        if w_other.length() == 0:
+            return w_set.copy_real()
         storage, strategy = self._symmetric_difference_base(w_set, w_other)
         return w_set.from_storage_and_strategy(storage, strategy)
 
     def symmetric_difference_update(self, w_set, w_other):
+        if w_other.length() == 0:
+            return
         storage, strategy = self._symmetric_difference_base(w_set, w_other)
         w_set.strategy = strategy
         w_set.sstorage = storage
@@ -1181,7 +1185,8 @@
             d_other = self.unerase(w_other.sstorage)
             d_set.update(d_other)
             return
-
+        if w_other.length() == 0:
+            return
         w_set.switch_to_object_strategy(self.space)
         w_set.update(w_other)
 
diff --git a/pypy/objspace/std/stringmethods.py 
b/pypy/objspace/std/stringmethods.py
--- a/pypy/objspace/std/stringmethods.py
+++ b/pypy/objspace/std/stringmethods.py
@@ -455,7 +455,7 @@
         d = width - len(value)
         if d > 0:
             fillchar = self._multi_chr(fillchar[0])
-            value += d * fillchar
+            value = value + fillchar * d
 
         return self._new(value)
 
diff --git a/pypy/objspace/std/test/test_bytearrayobject.py 
b/pypy/objspace/std/test/test_bytearrayobject.py
--- a/pypy/objspace/std/test/test_bytearrayobject.py
+++ b/pypy/objspace/std/test/test_bytearrayobject.py
@@ -223,6 +223,20 @@
         check(bytearray('abc').rstrip(memoryview('c')), 'ab')
         check(bytearray('aba').strip('a'), 'b')
 
+    def test_xjust_no_mutate(self):
+        # a previous regression
+        b = bytearray(b'')
+        assert b.ljust(1) == bytearray(b' ')
+        assert not len(b)
+
+        b2 = b.ljust(0)
+        b2 += b' '
+        assert not len(b)
+
+        b2 = b.rjust(0)
+        b2 += b' '
+        assert not len(b)
+
     def test_split(self):
         # methods that should return a sequence of bytearrays
         def check(result, expected):
diff --git a/pypy/objspace/std/test/test_setobject.py 
b/pypy/objspace/std/test/test_setobject.py
--- a/pypy/objspace/std/test/test_setobject.py
+++ b/pypy/objspace/std/test/test_setobject.py
@@ -960,3 +960,35 @@
         # did not work before because of an optimization that swaps both
         # operands when the first set is larger than the second
         assert type(frozenset([1, 2]) & set([2])) is frozenset
+
+    def test_update_bug_strategy(self):
+        from __pypy__ import strategy
+        s = set([1, 2, 3])
+        assert strategy(s) == "IntegerSetStrategy"
+        s.update(set())
+        assert strategy(s) == "IntegerSetStrategy"
+        #
+        s = set([1, 2, 3])
+        s |= set()
+        assert strategy(s) == "IntegerSetStrategy"
+        #
+        s = set([1, 2, 3]).difference(set())
+        assert strategy(s) == "IntegerSetStrategy"
+        #
+        s = set([1, 2, 3])
+        s.difference_update(set())
+        assert strategy(s) == "IntegerSetStrategy"
+        #
+        s = set([1, 2, 3]).symmetric_difference(set())
+        assert strategy(s) == "IntegerSetStrategy"
+        #
+        s = set([1, 2, 3])
+        s.symmetric_difference_update(set())
+        assert strategy(s) == "IntegerSetStrategy"
+        #
+        s = set([1, 2, 3]).intersection(set())
+        assert strategy(s) == "EmptySetStrategy"
+        #
+        s = set([1, 2, 3])
+        s.intersection_update(set())
+        assert strategy(s) == "EmptySetStrategy"
diff --git a/rpython/annotator/test/test_annrpython.py 
b/rpython/annotator/test/test_annrpython.py
--- a/rpython/annotator/test/test_annrpython.py
+++ b/rpython/annotator/test/test_annrpython.py
@@ -4276,6 +4276,15 @@
         py.test.raises(annmodel.AnnotatorError,
                        a.build_types, f, [annmodel.s_None])
 
+    def test_class___name__(self):
+        class Abc(object):
+            pass
+        def f():
+            return Abc().__class__.__name__
+        a = self.RPythonAnnotator()
+        s = a.build_types(f, [])
+        assert isinstance(s, annmodel.SomeString)
+
 
 def g(n):
     return [0, 1, 2, n]
diff --git a/rpython/annotator/unaryop.py b/rpython/annotator/unaryop.py
--- a/rpython/annotator/unaryop.py
+++ b/rpython/annotator/unaryop.py
@@ -745,6 +745,11 @@
 class __extend__(SomePBC):
 
     def getattr(self, s_attr):
+        assert s_attr.is_constant()
+        if s_attr.const == '__name__':
+            from rpython.annotator.description import ClassDesc
+            if self.getKind() is ClassDesc:
+                return SomeString()
         bookkeeper = getbookkeeper()
         return bookkeeper.pbc_getattr(self, s_attr)
     getattr.can_only_throw = []
diff --git a/rpython/flowspace/test/test_model.py 
b/rpython/flowspace/test/test_model.py
--- a/rpython/flowspace/test/test_model.py
+++ b/rpython/flowspace/test/test_model.py
@@ -13,7 +13,7 @@
 class pieces:
     """ The manually-built graph corresponding to the sample_function().
     """
-    i = Variable("i")
+    i0 = Variable("i0")
     i1 = Variable("i1")
     i2 = Variable("i2")
     i3 = Variable("i3")
@@ -25,12 +25,12 @@
     conditionop = SpaceOperation("gt", [i1, Constant(0)], conditionres)
     addop = SpaceOperation("add", [sum2, i2], sum3)
     decop = SpaceOperation("sub", [i2, Constant(1)], i3)
-    startblock = Block([i])
+    startblock = Block([i0])
     headerblock = Block([i1, sum1])
     whileblock = Block([i2, sum2])
 
     graph = FunctionGraph("f", startblock)
-    startblock.closeblock(Link([i, Constant(0)], headerblock))
+    startblock.closeblock(Link([i0, Constant(0)], headerblock))
     headerblock.operations.append(conditionop)
     headerblock.exitswitch = conditionres
     headerblock.closeblock(Link([sum1], graph.returnblock, False),
@@ -55,7 +55,7 @@
 def test_graphattributes():
     assert graph.startblock is pieces.startblock
     assert graph.returnblock is pieces.headerblock.exits[0].target
-    assert graph.getargs() == [pieces.i]
+    assert graph.getargs() == [pieces.i0]
     assert [graph.getreturnvar()] == graph.returnblock.inputargs
     assert graph.source == inspect.getsource(sample_function)
 
diff --git a/rpython/jit/backend/llsupport/test/ztranslation_test.py 
b/rpython/jit/backend/llsupport/test/ztranslation_test.py
--- a/rpython/jit/backend/llsupport/test/ztranslation_test.py
+++ b/rpython/jit/backend/llsupport/test/ztranslation_test.py
@@ -21,7 +21,7 @@
         # this is a basic test that tries to hit a number of features and their
         # translation:
         # - jitting of loops and bridges
-        # - virtualizables
+        # - two virtualizable types
         # - set_param interface
         # - profiler
         # - full optimizer
@@ -79,22 +79,28 @@
                 if rposix.get_errno() != total: raise ValueError
             return chr(total % 253)
         #
+        class Virt2(object):
+            _virtualizable_ = ['i']
+            def __init__(self, i):
+                self.i = i
         from rpython.rlib.libffi import types, CDLL, ArgChain
         from rpython.rlib.test.test_clibffi import get_libm_name
         libm_name = get_libm_name(sys.platform)
-        jitdriver2 = JitDriver(greens=[], reds = ['i', 'func', 'res', 'x'])
+        jitdriver2 = JitDriver(greens=[], reds = ['v2', 'func', 'res', 'x'],
+                               virtualizables = ['v2'])
         def libffi_stuff(i, j):
             lib = CDLL(libm_name)
             func = lib.getpointer('fabs', [types.double], types.double)
             res = 0.0
             x = float(j)
-            while i > 0:
-                jitdriver2.jit_merge_point(i=i, res=res, func=func, x=x)
+            v2 = Virt2(i)
+            while v2.i > 0:
+                jitdriver2.jit_merge_point(v2=v2, res=res, func=func, x=x)
                 promote(func)
                 argchain = ArgChain()
                 argchain.arg(x)
                 res = func.call(argchain, rffi.DOUBLE)
-                i -= 1
+                v2.i -= 1
             return res
         #
         def main(i, j):
diff --git a/rpython/jit/backend/test/test_ll_random.py 
b/rpython/jit/backend/test/test_ll_random.py
--- a/rpython/jit/backend/test/test_ll_random.py
+++ b/rpython/jit/backend/test/test_ll_random.py
@@ -112,11 +112,7 @@
         self.vtable_counter += 1
         S = self.get_random_structure_type(r, with_vtable=vtable, cache=False)
         name = S._name
-        vtable.name = lltype.malloc(lltype.Array(lltype.Char), len(name)+1,
-                                    immortal=True)
-        for i in range(len(name)):
-            vtable.name[i] = name[i]
-        vtable.name[len(name)] = '\x00'
+        vtable.name = rclass.alloc_array_name(name)
         self.structure_types_and_vtables.append((S, vtable))
         #
         heaptracker.register_known_gctype(self.cpu, vtable, S)
diff --git a/rpython/jit/codewriter/assembler.py 
b/rpython/jit/codewriter/assembler.py
--- a/rpython/jit/codewriter/assembler.py
+++ b/rpython/jit/codewriter/assembler.py
@@ -248,7 +248,7 @@
             if isinstance(TYPE, lltype.FuncType):
                 name = value._obj._name
             elif TYPE == rclass.OBJECT_VTABLE:
-                name = ''.join(value.name).rstrip('\x00')
+                name = ''.join(value.name.chars)
             else:
                 return
             addr = llmemory.cast_ptr_to_adr(value)
diff --git a/rpython/jit/codewriter/heaptracker.py 
b/rpython/jit/codewriter/heaptracker.py
--- a/rpython/jit/codewriter/heaptracker.py
+++ b/rpython/jit/codewriter/heaptracker.py
@@ -66,11 +66,7 @@
 def set_testing_vtable_for_gcstruct(GCSTRUCT, vtable, name):
     # only for tests that need to register the vtable of their malloc'ed
     # structures in case they are GcStruct inheriting from OBJECT.
-    namez = name + '\x00'
-    vtable.name = lltype.malloc(rclass.OBJECT_VTABLE.name.TO, len(namez),
-                                immortal=True)
-    for i in range(len(namez)):
-        vtable.name[i] = namez[i]
+    vtable.name = rclass.alloc_array_name(name)
     testing_gcstruct2vtable[GCSTRUCT] = vtable
 
 testing_gcstruct2vtable = {}
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_util.py 
b/rpython/jit/metainterp/optimizeopt/test/test_util.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_util.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_util.py
@@ -1,6 +1,6 @@
 import py, random
 
-from rpython.rtyper.lltypesystem import lltype, llmemory, rclass, rstr, rffi
+from rpython.rtyper.lltypesystem import lltype, llmemory, rclass, rffi
 from rpython.rtyper.lltypesystem.rclass import OBJECT, OBJECT_VTABLE
 from rpython.rtyper.rclass import FieldListAccessor, IR_QUASIIMMUTABLE
 
@@ -331,7 +331,7 @@
     def get_name_from_address(self, addr):
         # hack
         try:
-            return "".join(addr.ptr.name)[:-1] # remove \x00
+            return "".join(addr.ptr.name.chars)
         except AttributeError:
             return ""
 
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
@@ -1377,49 +1377,53 @@
     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
-        # list provided in argboxes, depending on the order in which
-        # the arguments are expected by the function
-        #
-        allboxes = self._build_allboxes(funcbox, argboxes, descr)
-        effectinfo = descr.get_extra_info()
-        if (assembler_call or
-                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)
+        debug_start("jit-residual-call")
+        try:
+            # First build allboxes: it may need some reordering from the
+            # list provided in argboxes, depending on the order in which
+            # the arguments are expected by the function
+            #
+            allboxes = self._build_allboxes(funcbox, argboxes, descr)
+            effectinfo = descr.get_extra_info()
+            if (assembler_call or
+                    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)
+                if effectinfo.is_call_release_gil():
+                    self.metainterp.direct_call_release_gil()
+                self.metainterp.vrefs_after_residual_call()
+                vablebox = None
+                if assembler_call:
+                    vablebox = self.metainterp.direct_assembler_call(
+                        assembler_call_jd)
                 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)
-            if effectinfo.is_call_release_gil():
-                self.metainterp.direct_call_release_gil()
-            self.metainterp.vrefs_after_residual_call()
-            vablebox = None
-            if assembler_call:
-                vablebox = self.metainterp.direct_assembler_call(
-                    assembler_call_jd)
-            if resbox is not None:
-                self.make_result_of_lastop(resbox)
-            self.metainterp.vable_after_residual_call(funcbox)
-            self.metainterp.generate_guard(rop.GUARD_NOT_FORCED, None)
-            if vablebox is not None:
-                self.metainterp.history.record(rop.KEEPALIVE, [vablebox], None)
-            self.metainterp.handle_possible_exception()
-            # XXX refactor: direct_libffi_call() is a hack
-            if effectinfo.oopspecindex == effectinfo.OS_LIBFFI_CALL:
-                self.metainterp.direct_libffi_call()
-            return resbox
-        else:
-            effect = effectinfo.extraeffect
-            if effect == effectinfo.EF_LOOPINVARIANT:
-                return self.execute_varargs(rop.CALL_LOOPINVARIANT, allboxes,
-                                            descr, False, False)
-            exc = effectinfo.check_can_raise()
-            pure = effectinfo.check_is_elidable()
-            return self.execute_varargs(rop.CALL, allboxes, descr, exc, pure)
+                    self.make_result_of_lastop(resbox)
+                self.metainterp.vable_after_residual_call(funcbox)
+                self.metainterp.generate_guard(rop.GUARD_NOT_FORCED, None)
+                if vablebox is not None:
+                    self.metainterp.history.record(rop.KEEPALIVE, [vablebox], 
None)
+                self.metainterp.handle_possible_exception()
+                # XXX refactor: direct_libffi_call() is a hack
+                if effectinfo.oopspecindex == effectinfo.OS_LIBFFI_CALL:
+                    self.metainterp.direct_libffi_call()
+                return resbox
+            else:
+                effect = effectinfo.extraeffect
+                if effect == effectinfo.EF_LOOPINVARIANT:
+                    return self.execute_varargs(rop.CALL_LOOPINVARIANT, 
allboxes,
+                                                descr, False, False)
+                exc = effectinfo.check_can_raise()
+                pure = effectinfo.check_is_elidable()
+                return self.execute_varargs(rop.CALL, allboxes, descr, exc, 
pure)
+        finally:
+            debug_stop("jit-residual-call")
 
     def do_conditional_call(self, condbox, funcbox, argboxes, descr, pc):
         if isinstance(condbox, ConstInt) and condbox.value == 0:
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
@@ -1611,6 +1611,40 @@
                  op.getopnum() == rop.GUARD_NOT_FORCED_2]
             assert len(l) == 0
 
+    def test_two_virtualizable_types(self):
+        class A:
+            _virtualizable_ = ['x']
+            def __init__(self, x):
+                self.x = x
+
+        class B:
+            _virtualizable_ = ['lst[*]']
+            def __init__(self, lst):
+                self.lst = lst
+
+        driver_a = JitDriver(greens=[], reds=['a'], virtualizables=['a'])
+        driver_b = JitDriver(greens=[], reds=['b'], virtualizables=['b'])
+
+        def foo_a(a):
+            while a.x > 0:
+                driver_a.jit_merge_point(a=a)
+                a.x -= 2
+            return a.x
+
+        def foo_b(b):
+            while b.lst[0] > 0:
+                driver_b.jit_merge_point(b=b)
+                b.lst[0] -= 2
+            return b.lst[0]
+
+        def f():
+            return foo_a(A(13)) * 100 + foo_b(B([13]))
+
+        assert f() == -101
+        res = self.meta_interp(f, [], listops=True)
+        assert res == -101
+
+
 class TestLLtype(ExplicitVirtualizableTests,
                  ImplicitVirtualizableTests,
                  LLJitMixin):
diff --git a/rpython/jit/metainterp/test/test_virtualref.py 
b/rpython/jit/metainterp/test/test_virtualref.py
--- a/rpython/jit/metainterp/test/test_virtualref.py
+++ b/rpython/jit/metainterp/test/test_virtualref.py
@@ -34,7 +34,7 @@
         #
         def check_call(op, fname):
             assert op.opname == 'direct_call'
-            assert op.args[0].value._obj._name == fname
+            assert op.args[0].value._obj._name.startswith(fname)
         #
         ops = [op for block, op in graph.iterblockops()]
         check_call(ops[-3], 'virtual_ref')
diff --git a/rpython/jit/tool/oparser_model.py 
b/rpython/jit/tool/oparser_model.py
--- a/rpython/jit/tool/oparser_model.py
+++ b/rpython/jit/tool/oparser_model.py
@@ -124,6 +124,15 @@
 
     class ExtendedTreeLoop(model.TreeLoop):
 
+        def as_json(self):
+            return {
+                'comment': self.comment,
+                'name': self.name,
+                'operations': [op.as_json() for op in self.operations],
+                'inputargs': self.inputargs,
+                'last_offset': self.last_offset
+            }
+
         def getboxes(self):
             def opboxes(operations):
                 for op in operations:
diff --git a/rpython/rlib/jit.py b/rpython/rlib/jit.py
--- a/rpython/rlib/jit.py
+++ b/rpython/rlib/jit.py
@@ -340,6 +340,7 @@
 # ____________________________________________________________
 # VRefs
 
[email protected](0)
 def virtual_ref(x):
     """Creates a 'vref' object that contains a reference to 'x'.  Calls
     to virtual_ref/virtual_ref_finish must be properly nested.  The idea
@@ -351,6 +352,7 @@
     return DirectJitVRef(x)
 virtual_ref.oopspec = 'virtual_ref(x)'
 
[email protected](1)
 def virtual_ref_finish(vref, x):
     """See docstring in virtual_ref(x)"""
     keepalive_until_here(x)   # otherwise the whole function call is removed
diff --git a/rpython/rtyper/llinterp.py b/rpython/rtyper/llinterp.py
--- a/rpython/rtyper/llinterp.py
+++ b/rpython/rtyper/llinterp.py
@@ -42,7 +42,7 @@
         return ': '.join([str(x) for x in self.args])
 
 def type_name(etype):
-    return ''.join(etype.name).rstrip('\x00')
+    return ''.join(etype.name.chars)
 
 class LLInterpreter(object):
     """ low level interpreter working with concrete values. """
@@ -145,7 +145,7 @@
         assert isinstance(exc, LLException)
         klass, inst = exc.args[0], exc.args[1]
         for cls in enumerate_exceptions_top_down():
-            if "".join(klass.name).rstrip("\0") == cls.__name__:
+            if "".join(klass.name.chars) == cls.__name__:
                 return cls
         raise ValueError("couldn't match exception, maybe it"
                       " has RPython attributes like OSError?")
diff --git a/rpython/rtyper/lltypesystem/lltype.py 
b/rpython/rtyper/lltypesystem/lltype.py
--- a/rpython/rtyper/lltypesystem/lltype.py
+++ b/rpython/rtyper/lltypesystem/lltype.py
@@ -1154,7 +1154,12 @@
                 type(other).__name__,))
         if self._TYPE != other._TYPE:
             raise TypeError("comparing %r and %r" % (self._TYPE, other._TYPE))
-        return self._obj == other._obj
+        try:
+            return self._obj == other._obj
+        except DelayedPointer:
+            # if one of the two pointers is delayed, they cannot
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to