Author: Richard Plangger <planri...@gmail.com>
Branch: py3.5-ssl
Changeset: r88738:709cadb7f491
Date: 2016-11-29 13:02 +0100
http://bitbucket.org/pypy/pypy/changeset/709cadb7f491/

Log:    merge py3.5

diff too long, truncating to 2000 out of 2056 lines

diff --git a/lib-python/2.7/distutils/sysconfig_pypy.py 
b/lib-python/2.7/distutils/sysconfig_pypy.py
--- a/lib-python/2.7/distutils/sysconfig_pypy.py
+++ b/lib-python/2.7/distutils/sysconfig_pypy.py
@@ -74,6 +74,19 @@
     g['LIBDIR'] = os.path.join(sys.prefix, 'lib')
     g['VERSION'] = get_python_version()
 
+    if sys.platform[:6] == "darwin":
+        import platform
+        if platform.machine() == 'i386':
+            if platform.architecture()[0] == '32bit':
+                arch = 'i386'
+            else:
+                arch = 'x86_64'
+        else:
+            # just a guess
+            arch = platform.machine()
+        g['LDSHARED'] += ' -undefined dynamic_lookup'
+        g['CC'] += ' -arch %s' % (arch,)
+
     global _config_vars
     _config_vars = g
 
@@ -109,6 +122,12 @@
         _config_vars['prefix'] = PREFIX
         _config_vars['exec_prefix'] = EXEC_PREFIX
 
+        # OS X platforms require special customization to handle
+        # multi-architecture, multi-os-version installers
+        if sys.platform == 'darwin':
+            import _osx_support
+            _osx_support.customize_config_vars(_config_vars)
+
     if args:
         vals = []
         for name in args:
diff --git a/lib-python/3/_weakrefset.py b/lib-python/3/_weakrefset.py
--- a/lib-python/3/_weakrefset.py
+++ b/lib-python/3/_weakrefset.py
@@ -65,7 +65,14 @@
                     yield item
 
     def __len__(self):
-        return len(self.data) - len(self._pending_removals)
+        # PyPy change: we can't rely on len(self.data) at all, because
+        # the weakref callbacks may be called at an unknown later time.
+#        return len(self.data) - len(self._pending_removals)
+#
+        result = 0
+        for wr in self.data:
+            result += (wr() is not None)
+        return result
 
     def __contains__(self, item):
         try:
diff --git a/lib-python/3/test/test_asyncio/test_base_events.py 
b/lib-python/3/test/test_asyncio/test_base_events.py
--- a/lib-python/3/test/test_asyncio/test_base_events.py
+++ b/lib-python/3/test/test_asyncio/test_base_events.py
@@ -510,6 +510,7 @@
             fut.add_done_callback(lambda *args: self.loop.stop())
             self.loop.run_forever()
             fut = None # Trigger Future.__del__ or futures._TracebackLogger
+            support.gc_collect()
             if PY34:
                 # Future.__del__ in Python 3.4 logs error with
                 # an actual exception context
diff --git a/lib-python/3/test/test_asyncio/test_futures.py 
b/lib-python/3/test/test_asyncio/test_futures.py
--- a/lib-python/3/test/test_asyncio/test_futures.py
+++ b/lib-python/3/test/test_asyncio/test_futures.py
@@ -238,6 +238,7 @@
         fut.set_exception(RuntimeError('boom'))
         del fut
         test_utils.run_briefly(self.loop)
+        support.gc_collect()
         self.assertTrue(m_log.error.called)
 
     @mock.patch('asyncio.base_events.logger')
diff --git a/lib-python/3/test/test_complex.py 
b/lib-python/3/test/test_complex.py
--- a/lib-python/3/test/test_complex.py
+++ b/lib-python/3/test/test_complex.py
@@ -310,7 +310,7 @@
         self.assertRaises(TypeError, float, 5+3j)
         self.assertRaises(ValueError, complex, "")
         self.assertRaises(TypeError, complex, None)
-        self.assertRaisesRegex(TypeError, "not 'NoneType'", complex, None)
+        self.assertRaisesRegex(TypeError, " 'NoneType'", complex, None)
         self.assertRaises(ValueError, complex, "\0")
         self.assertRaises(ValueError, complex, "3\09")
         self.assertRaises(TypeError, complex, "1", "2")
diff --git a/lib-python/3/test/test_exceptions.py 
b/lib-python/3/test/test_exceptions.py
--- a/lib-python/3/test/test_exceptions.py
+++ b/lib-python/3/test/test_exceptions.py
@@ -1013,6 +1013,7 @@
             self.assertNotEqual(wr(), None)
         else:
             self.fail("RecursionError not raised")
+        gc_collect()
         self.assertEqual(wr(), None)
 
     def test_errno_ENOTDIR(self):
diff --git a/lib-python/3/test/test_sys.py b/lib-python/3/test/test_sys.py
--- a/lib-python/3/test/test_sys.py
+++ b/lib-python/3/test/test_sys.py
@@ -811,7 +811,12 @@
             ref = AtExit()
         """
         rc, stdout, stderr = assert_python_ok('-c', code)
-        self.assertEqual(stdout.rstrip(), b'True')
+        if test.support.check_impl_detail(cpython=True):
+            self.assertEqual(stdout.rstrip(), b'True')
+        else:
+            # the __del__ method may or may not have been called
+            # in other Python implementations
+            self.assertIn(stdout.rstrip(), {b'True', b''})
 
 
 @test.support.cpython_only
diff --git a/lib-python/3/test/test_weakref.py 
b/lib-python/3/test/test_weakref.py
--- a/lib-python/3/test/test_weakref.py
+++ b/lib-python/3/test/test_weakref.py
@@ -1103,7 +1103,7 @@
         # Keep an iterator alive
         it = dct.items()
         try:
-            next(it)
+            print(next(it))
         except StopIteration:
             pass
         del items
@@ -1112,7 +1112,10 @@
         del it
         gc.collect()
         gc.collect()
+        print(list(dct.items()))
         n2 = len(dct)
+        print(len(dct))
+        print(weakref)
         # one item may be kept alive inside the iterator
         self.assertIn(n1, (0, 1))
         self.assertEqual(n2, 0)
diff --git a/lib-python/3/unittest/test/test_assertions.py 
b/lib-python/3/unittest/test/test_assertions.py
--- a/lib-python/3/unittest/test/test_assertions.py
+++ b/lib-python/3/unittest/test/test_assertions.py
@@ -2,6 +2,7 @@
 import warnings
 import weakref
 import unittest
+from test.support import gc_collect
 from itertools import product
 
 
@@ -124,8 +125,10 @@
                     self.foo()
 
         Foo("test_functional").run()
+        gc_collect()
         self.assertIsNone(wr())
         Foo("test_with").run()
+        gc_collect()
         self.assertIsNone(wr())
 
     def testAssertNotRegex(self):
diff --git a/lib-python/3/unittest/test/test_case.py 
b/lib-python/3/unittest/test/test_case.py
--- a/lib-python/3/unittest/test/test_case.py
+++ b/lib-python/3/unittest/test/test_case.py
@@ -18,7 +18,7 @@
     TestEquality, TestHashing, LoggingResult, LegacyLoggingResult,
     ResultWithNoStartTestRunStopTestRun
 )
-from test.support import captured_stderr
+from test.support import captured_stderr, gc_collect
 
 
 log_foo = logging.getLogger('foo')
@@ -1737,6 +1737,7 @@
         for method_name in ('test1', 'test2'):
             testcase = TestCase(method_name)
             testcase.run()
+            gc_collect()
             self.assertEqual(MyException.ninstance, 0)
 
 
diff --git a/lib-python/3/weakref.py b/lib-python/3/weakref.py
--- a/lib-python/3/weakref.py
+++ b/lib-python/3/weakref.py
@@ -147,7 +147,14 @@
         del self.data[key]
 
     def __len__(self):
-        return len(self.data) - len(self._pending_removals)
+        # PyPy change: we can't rely on len(self.data) at all, because
+        # the weakref callbacks may be called at an unknown later time.
+#        return len(self.data) - len(self._pending_removals)
+#
+        result = 0
+        for wr in self.data.values():
+            result += (wr() is not None)
+        return result
 
     def __contains__(self, key):
         try:
@@ -376,11 +383,18 @@
         return self.data[ref(key)]
 
     def __len__(self):
-        if self._dirty_len and self._pending_removals:
-            # self._pending_removals may still contain keys which were
-            # explicitly removed, we have to scrub them (see issue #21173).
-            self._scrub_removals()
-        return len(self.data) - len(self._pending_removals)
+        # PyPy change: we can't rely on len(self.data) at all, because
+        # the weakref callbacks may be called at an unknown later time.
+#        if self._dirty_len and self._pending_removals:
+#            # self._pending_removals may still contain keys which were
+#            # explicitly removed, we have to scrub them (see issue #21173).
+#            self._scrub_removals()
+#        return len(self.data) - len(self._pending_removals)
+#
+        result = 0
+        for wr in self.data:
+            result += (wr() is not None)
+        return result
 
     def __repr__(self):
         return "<%s at %#x>" % (self.__class__.__name__, id(self))
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
@@ -34,3 +34,7 @@
 
 Add jit.conditional_call_elidable(), a way to tell the JIT "conditonally
 call this function" returning a result.
+
+.. branch: desc-specialize
+
+Refactor FunctionDesc.specialize() and related code (RPython annotator).
diff --git a/pypy/goal/targetpypystandalone.py 
b/pypy/goal/targetpypystandalone.py
--- a/pypy/goal/targetpypystandalone.py
+++ b/pypy/goal/targetpypystandalone.py
@@ -302,6 +302,12 @@
         elif config.objspace.usemodules.pypyjit:
             config.translation.jit = True
 
+        if config.objspace.usemodules.cpyext:
+            if config.translation.gc != 'incminimark':
+                raise Exception("The 'cpyext' module requires the 
'incminimark'"
+                                " GC.  You need either 
'targetpypystandalone.py"
+                                " --withoutmod-cpyext' or '--gc=incminimark'")
+
         config.translating = True
 
         import translate
diff --git a/pypy/interpreter/app_main.py b/pypy/interpreter/app_main.py
--- a/pypy/interpreter/app_main.py
+++ b/pypy/interpreter/app_main.py
@@ -595,7 +595,7 @@
     # set up the Ctrl-C => KeyboardInterrupt signal handler, if the
     # signal module is available
     try:
-        import signal
+        import _signal as signal
     except ImportError:
         pass
     else:
diff --git a/pypy/interpreter/error.py b/pypy/interpreter/error.py
--- a/pypy/interpreter/error.py
+++ b/pypy/interpreter/error.py
@@ -559,8 +559,9 @@
                                           space.wrap(msg))
         return OperationError(exc, w_error)
 
+@specialize.arg(3)
 def wrap_oserror2(space, e, w_filename=None, exception_name='w_OSError',
-                  w_exception_class=None):
+                  w_exception_class=None, w_filename2=None):
     assert isinstance(e, OSError)
 
     if _WINDOWS and isinstance(e, WindowsError):
@@ -580,25 +581,31 @@
     else:
         exc = w_exception_class
     if w_filename is not None:
-        w_error = space.call_function(exc, space.wrap(errno),
-                                      space.wrap(msg), w_filename)
+        if w_filename2 is not None:
+            w_error = space.call_function(exc, space.wrap(errno),
+                                          space.wrap(msg), w_filename,
+                                          space.w_None, w_filename2)
+        else:
+            w_error = space.call_function(exc, space.wrap(errno),
+                                          space.wrap(msg), w_filename)
     else:
         w_error = space.call_function(exc, space.wrap(errno),
                                       space.wrap(msg))
     return OperationError(exc, w_error)
-wrap_oserror2._annspecialcase_ = 'specialize:arg(3)'
 
+@specialize.arg(3)
 def wrap_oserror(space, e, filename=None, exception_name='w_OSError',
-                 w_exception_class=None):
+                 w_exception_class=None, filename2=None):
+    w_filename = None
+    w_filename2 = None
     if filename is not None:
-        return wrap_oserror2(space, e, space.wrap(filename),
-                             exception_name=exception_name,
-                             w_exception_class=w_exception_class)
-    else:
-        return wrap_oserror2(space, e, None,
-                             exception_name=exception_name,
-                             w_exception_class=w_exception_class)
-wrap_oserror._annspecialcase_ = 'specialize:arg(3)'
+        w_filename = space.wrap(filename)
+        if filename2 is not None:
+            w_filename2 = space.wrap(filename2)
+    return wrap_oserror2(space, e, w_filename,
+                         exception_name=exception_name,
+                         w_exception_class=w_exception_class,
+                         w_filename2=w_filename2)
 
 def exception_from_saved_errno(space, w_type):
     from rpython.rlib.rposix import get_saved_errno
diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py
--- a/pypy/interpreter/generator.py
+++ b/pypy/interpreter/generator.py
@@ -20,7 +20,8 @@
         self.running = False
         self._name = name           # may be null, use get_name()
         self._qualname = qualname   # may be null, use get_qualname()
-        if self.pycode.co_flags & CO_YIELD_INSIDE_TRY:
+        if (isinstance(self, Coroutine)    # XXX would be cool not to need this
+                or self.pycode.co_flags & CO_YIELD_INSIDE_TRY):
             self.register_finalizer(self.space)
         self.saved_operr = None
 
@@ -385,7 +386,7 @@
            self.frame.last_instr == -1:
             space = self.space
             msg = u"coroutine '%s' was never awaited" % self.get_qualname()
-            space.warn(space.w_RuntimeWarning, space.wrap(msg))
+            space.warn(space.wrap(msg), space.w_RuntimeWarning)
         GeneratorOrCoroutine._finalize_(self)
 
 
diff --git a/pypy/interpreter/test/test_coroutine.py 
b/pypy/interpreter/test/test_coroutine.py
--- a/pypy/interpreter/test/test_coroutine.py
+++ b/pypy/interpreter/test/test_coroutine.py
@@ -160,3 +160,20 @@
         else:
             assert False, "should have raised"
         """
+
+    def test_runtime_warning(self): """
+        import gc, warnings
+        async def foobaz():
+            pass
+        with warnings.catch_warnings(record=True) as l:
+            foobaz()
+            gc.collect()
+            gc.collect()
+            gc.collect()
+
+        assert len(l) == 1, repr(l)
+        w = l[0].message
+        assert isinstance(w, RuntimeWarning)
+        assert str(w).startswith("coroutine ")
+        assert str(w).endswith("foobaz' was never awaited")
+        """
diff --git a/pypy/module/_collections/interp_deque.py 
b/pypy/module/_collections/interp_deque.py
--- a/pypy/module/_collections/interp_deque.py
+++ b/pypy/module/_collections/interp_deque.py
@@ -1,4 +1,5 @@
 import sys
+from rpython.rlib.objectmodel import specialize
 from pypy.interpreter import gateway
 from pypy.interpreter.baseobjspace import W_Root
 from pypy.interpreter.typedef import TypeDef, make_weakref_descr
@@ -7,7 +8,6 @@
 from pypy.interpreter.error import OperationError, oefmt
 from pypy.objspace.std.sliceobject import unwrap_start_stop
 from rpython.rlib.debug import check_nonneg
-from rpython.rlib.objectmodel import specialize
 
 
 # A `dequeobject` is composed of a doubly-linked list of `block` nodes.
diff --git a/pypy/module/cppyy/test/test_zjit.py 
b/pypy/module/cppyy/test/test_zjit.py
--- a/pypy/module/cppyy/test/test_zjit.py
+++ b/pypy/module/cppyy/test/test_zjit.py
@@ -124,13 +124,13 @@
         assert isinstance(w_obj, FakeFloat)
         return w_obj.val
 
+    @specialize.arg(1)
     def interp_w(self, RequiredClass, w_obj, can_be_None=False):
         if can_be_None and w_obj is None:
             return None
         if not isinstance(w_obj, RequiredClass):
             raise TypeError
         return w_obj
-    interp_w._annspecialcase_ = 'specialize:arg(1)'
 
     def getarg_w(self, code, w_obj):    # for retrieving buffers
         return FakeBuffer(w_obj)
diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -35,8 +35,6 @@
 from rpython.rlib.objectmodel import specialize
 from pypy.module import exceptions
 from pypy.module.exceptions import interp_exceptions
-# CPython 2.4 compatibility
-from py.builtin import BaseException
 from rpython.tool.sourcetools import func_with_new_name
 from rpython.rtyper.lltypesystem.lloperation import llop
 from rpython.rlib import rawrefcount
@@ -1622,9 +1620,8 @@
     miniglobals = {'__name__':    __name__, # for module name propagation
                    }
     exec source.compile() in miniglobals
-    call_external_function = miniglobals['cpy_call_external']
+    call_external_function = specialize.ll()(miniglobals['cpy_call_external'])
     call_external_function._dont_inline_ = True
-    call_external_function._annspecialcase_ = 'specialize:ll'
     call_external_function._gctransformer_hint_close_stack_ = True
     # don't inline, as a hack to guarantee that no GC pointer is alive
     # anywhere in call_external_function
diff --git a/pypy/module/cpyext/pyobject.py b/pypy/module/cpyext/pyobject.py
--- a/pypy/module/cpyext/pyobject.py
+++ b/pypy/module/cpyext/pyobject.py
@@ -15,6 +15,7 @@
 from rpython.rlib.objectmodel import keepalive_until_here
 from rpython.rtyper.annlowlevel import llhelper
 from rpython.rlib import rawrefcount
+from rpython.rlib.debug import fatalerror
 
 
 #________________________________________________________
@@ -192,6 +193,8 @@
     rawrefcount.create_link_pypy(w_obj, py_obj)
 
 
+w_marker_deallocating = W_Root()
+
 def from_ref(space, ref):
     """
     Finds the interpreter object corresponding to the given reference.  If the
@@ -202,7 +205,23 @@
         return None
     w_obj = rawrefcount.to_obj(W_Root, ref)
     if w_obj is not None:
-        return w_obj
+        if w_obj is not w_marker_deallocating:
+            return w_obj
+        fatalerror(
+            "*** Invalid usage of a dying CPython object ***\n"
+            "\n"
+            "cpyext, the emulation layer, detected that while it is calling\n"
+            "an object's tp_dealloc, the C code calls back a function that\n"
+            "tries to recreate the PyPy version of the object.  Usually it\n"
+            "means that tp_dealloc calls some general PyXxx() API.  It is\n"
+            "a dangerous and potentially buggy thing to do: even in CPython\n"
+            "the PyXxx() function could, in theory, cause a reference to the\n"
+            "object to be taken and stored somewhere, for an amount of time\n"
+            "exceeding tp_dealloc itself.  Afterwards, the object will be\n"
+            "freed, making that reference point to garbage.\n"
+            ">>> PyPy could contain some workaround to still work if\n"
+            "you are lucky, but it is not done so far; better fix the bug in\n"
+            "the CPython extension.")
 
     # This reference is not yet a real interpreter object.
     # Realize it.
@@ -233,7 +252,8 @@
 INTERPLEVEL_API['as_pyobj'] = as_pyobj
 
 def pyobj_has_w_obj(pyobj):
-    return rawrefcount.to_obj(W_Root, pyobj) is not None
+    w_obj = rawrefcount.to_obj(W_Root, pyobj)
+    return w_obj is not None and w_obj is not w_marker_deallocating
 INTERPLEVEL_API['pyobj_has_w_obj'] = staticmethod(pyobj_has_w_obj)
 
 
@@ -335,6 +355,7 @@
     pto = obj.c_ob_type
     #print >>sys.stderr, "Calling dealloc slot", pto.c_tp_dealloc, "of", obj, \
     #      "'s type which is", rffi.charp2str(pto.c_tp_name)
+    rawrefcount.mark_deallocating(w_marker_deallocating, obj)
     generic_cpy_call(space, pto.c_tp_dealloc, obj)
 
 @cpython_api([rffi.VOIDP], lltype.Signed, error=CANNOT_FAIL)
diff --git a/pypy/module/exceptions/interp_exceptions.py 
b/pypy/module/exceptions/interp_exceptions.py
--- a/pypy/module/exceptions/interp_exceptions.py
+++ b/pypy/module/exceptions/interp_exceptions.py
@@ -446,6 +446,7 @@
         self.w_errno = space.w_None
         self.w_strerror = space.w_None
         self.w_filename = space.w_None
+        self.w_filename2 = space.w_None
         self.written = -1  # only for BlockingIOError.
         W_BaseException.__init__(self, space)
 
@@ -471,15 +472,17 @@
 
     @staticmethod
     def _parse_init_args(space, args_w):
-        if 2 <= len(args_w) <= 3:
+        if 2 <= len(args_w) <= 5:
             w_errno = args_w[0]
             w_strerror = args_w[1]
-            if len(args_w) == 3:
+            w_filename = None
+            w_filename2 = None
+            if len(args_w) > 2:
                 w_filename = args_w[2]
-            else:
-                w_filename = None
-            return w_errno, w_strerror, w_filename
-        return None, None, None
+                if len(args_w) > 4:
+                    w_filename2 = args_w[4]
+            return w_errno, w_strerror, w_filename, w_filename2
+        return None, None, None, None
 
     @staticmethod
     def descr_new(space, w_subtype, __args__):
@@ -487,11 +490,12 @@
         w_errno = None
         w_strerror = None
         w_filename = None
+        w_filename2 = None
         if not W_OSError._use_init(space, w_subtype):
             if kwds_w:
                 raise oefmt(space.w_TypeError,
                             "OSError does not take keyword arguments")
-            (w_errno, w_strerror, w_filename,
+            (w_errno, w_strerror, w_filename, w_filename2
              ) = W_OSError._parse_init_args(space, args_w)
         if (not space.is_none(w_errno) and
             space.is_w(w_subtype, space.gettypeobject(W_OSError.typedef))):
@@ -509,7 +513,8 @@
         exc = space.allocate_instance(W_OSError, w_subtype)
         W_OSError.__init__(exc, space)
         if not W_OSError._use_init(space, w_subtype):
-            exc._init_error(space, args_w, w_errno, w_strerror, w_filename)
+            exc._init_error(space, args_w, w_errno, w_strerror, w_filename,
+                            w_filename2)
         return space.wrap(exc)
 
     def descr_init(self, space, __args__):
@@ -520,11 +525,13 @@
         if kwds_w:
             raise oefmt(space.w_TypeError,
                         "OSError does not take keyword arguments")
-        (w_errno, w_strerror, w_filename
+        (w_errno, w_strerror, w_filename, w_filename2
          ) = W_OSError._parse_init_args(space, args_w)
-        self._init_error(space, args_w, w_errno, w_strerror, w_filename)
+        self._init_error(space, args_w, w_errno, w_strerror, w_filename,
+                         w_filename2)
 
-    def _init_error(self, space, args_w, w_errno, w_strerror, w_filename):
+    def _init_error(self, space, args_w, w_errno, w_strerror, w_filename,
+                    w_filename2):
         W_BaseException.descr_init(self, space, args_w)
         if w_errno:
             self.w_errno = w_errno
@@ -540,17 +547,21 @@
                     self.w_filename = w_filename
             else:
                 self.w_filename = w_filename
+                if not space.is_none(w_filename2):
+                    self.w_filename2 = w_filename2
                 # filename is removed from the args tuple (for compatibility
                 # purposes, see test_exceptions.py)
                 self.args_w = [w_errno, w_strerror]
 
     # since we rebind args_w, we need special reduce, grump
     def descr_reduce(self, space):
+        extra = []
         if not space.is_w(self.w_filename, space.w_None):
-            lst = [self.getclass(space), space.newtuple(
-                self.args_w + [self.w_filename])]
-        else:
-            lst = [self.getclass(space), space.newtuple(self.args_w)]
+            extra.append(self.w_filename)
+            if not space.is_w(self.w_filename2, space.w_None):
+                extra.append(space.w_None)
+                extra.append(self.w_filename2)
+        lst = [self.getclass(space), space.newtuple(self.args_w + extra)]
         if self.w_dict is not None and space.is_true(self.w_dict):
             lst = lst + [self.w_dict]
         return space.newtuple(lst)
@@ -561,6 +572,12 @@
             errno = space.unicode_w(space.str(self.w_errno))
             strerror = space.unicode_w(space.str(self.w_strerror))
             if not space.is_w(self.w_filename, space.w_None):
+                if not space.is_w(self.w_filename2, space.w_None):
+                    return space.wrap(u"[Errno %s] %s: %s -> %s" % (
+                        errno,
+                        strerror,
+                        space.unicode_w(space.repr(self.w_filename)),
+                        space.unicode_w(space.repr(self.w_filename2))))
                 return space.wrap(u"[Errno %s] %s: %s" % (
                     errno,
                     strerror,
@@ -590,6 +607,7 @@
     errno    = readwrite_attrproperty_w('w_errno',    W_OSError),
     strerror = readwrite_attrproperty_w('w_strerror', W_OSError),
     filename = readwrite_attrproperty_w('w_filename', W_OSError),
+    filename2= readwrite_attrproperty_w('w_filename2',W_OSError),
     characters_written = GetSetProperty(W_OSError.descr_get_written,
                                         W_OSError.descr_set_written),
     )
diff --git a/pypy/module/exceptions/test/test_exc.py 
b/pypy/module/exceptions/test/test_exc.py
--- a/pypy/module/exceptions/test/test_exc.py
+++ b/pypy/module/exceptions/test/test_exc.py
@@ -374,6 +374,23 @@
         e = SubOSErrorWithNew("some message", baz="baz")
         assert e.baz == "baz"
         assert e.args == ("some message",)
+        assert e.filename is None
+        assert e.filename2 is None
+
+    def test_oserror_3_args(self):
+        e = OSError(42, "bar", "baz")
+        assert e.args == (42, "bar")
+        assert e.filename == "baz"
+        assert e.filename2 is None
+        assert str(e) == "[Errno 42] bar: 'baz'"
+
+    def test_oserror_5_args(self):
+        # NB. argument 4 is only parsed on Windows
+        e = OSError(42, "bar", "baz", None, "bok")
+        assert e.args == (42, "bar")
+        assert e.filename == "baz"
+        assert e.filename2 == "bok"
+        assert str(e) == "[Errno 42] bar: 'baz' -> 'bok'"
 
     # Check the heuristic for print & exec covers significant cases
     # As well as placing some limits on false positives
diff --git a/pypy/module/posix/interp_posix.py 
b/pypy/module/posix/interp_posix.py
--- a/pypy/module/posix/interp_posix.py
+++ b/pypy/module/posix/interp_posix.py
@@ -484,7 +484,8 @@
     def __init__(self, space):
         self.stat_float_times = True
 
-def stat_float_times(space, w_value=None):
+@unwrap_spec(newval=int)
+def stat_float_times(space, newval=-1):
     """stat_float_times([newval]) -> oldval
 
 Determine whether os.[lf]stat represents time stamps as float objects.
@@ -494,10 +495,10 @@
 """
     state = space.fromcache(StatState)
 
-    if w_value is None:
+    if newval == -1:
         return space.wrap(state.stat_float_times)
     else:
-        state.stat_float_times = space.bool_w(w_value)
+        state.stat_float_times = (newval != 0)
 
 
 @unwrap_spec(fd=c_int)
@@ -1008,7 +1009,7 @@
         else:
             dispatch_filename_2(rposix.rename)(space, w_src, w_dst)
     except OSError as e:
-        raise wrap_oserror(space, e)
+        raise wrap_oserror2(space, e, w_filename=w_src, w_filename2=w_dst)
 
 @unwrap_spec(src_dir_fd=DirFD(rposix.HAVE_RENAMEAT),
         dst_dir_fd=DirFD(rposix.HAVE_RENAMEAT))
@@ -1115,7 +1116,7 @@
     rposix.kill(os.getpid(), signal.SIGABRT)
 
 @unwrap_spec(
-    src='fsencode', dst='fsencode',
+    src='fsencode', dst='fsencode',  # <- simpler: link() is never on Windows
     src_dir_fd=DirFD(rposix.HAVE_LINKAT), dst_dir_fd=DirFD(rposix.HAVE_LINKAT),
     follow_symlinks=bool)
 def link(
@@ -1144,7 +1145,7 @@
         else:
             rposix.link(src, dst)
     except OSError as e:
-        raise wrap_oserror(space, e)
+        raise wrap_oserror(space, e, filename=src, filename2=dst)
 
 
 @unwrap_spec(dir_fd=DirFD(rposix.HAVE_SYMLINKAT))
@@ -1171,7 +1172,7 @@
         else:
             dispatch_filename_2(rposix.symlink)(space, w_src, w_dst)
     except OSError as e:
-        raise wrap_oserror(space, e)
+        raise wrap_oserror2(space, e, w_filename=w_src, w_filename2=w_dst)
 
 
 @unwrap_spec(
@@ -2219,13 +2220,20 @@
 
 @unwrap_spec(fd=c_int)
 def get_blocking(space, fd):
-    return space.newbool(rposix.get_status_flags(fd) & rposix.O_NONBLOCK == 0)
+    try:
+        flags = rposix.get_status_flags(fd)
+    except OSError as e:
+        raise wrap_oserror(space, e)
+    return space.newbool(flags & rposix.O_NONBLOCK == 0)
 
 @unwrap_spec(fd=c_int, blocking=int)
 def set_blocking(space, fd, blocking):
-    flags = rposix.get_status_flags(fd)
-    if blocking:
-        flags &= ~rposix.O_NONBLOCK
-    else:
-        flags |= rposix.O_NONBLOCK
-    rposix.set_status_flags(fd, flags)
+    try:
+        flags = rposix.get_status_flags(fd)
+        if blocking:
+            flags &= ~rposix.O_NONBLOCK
+        else:
+            flags |= rposix.O_NONBLOCK
+        rposix.set_status_flags(fd, flags)
+    except OSError as e:
+        raise wrap_oserror(space, e)
diff --git a/pypy/module/posix/test/test_posix2.py 
b/pypy/module/posix/test/test_posix2.py
--- a/pypy/module/posix/test/test_posix2.py
+++ b/pypy/module/posix/test/test_posix2.py
@@ -159,11 +159,14 @@
             st = posix.stat(path)
             assert isinstance(st.st_mtime, float)
             assert st[7] == int(st.st_atime)
+            assert posix.stat_float_times(-1) is True
 
             posix.stat_float_times(False)
             st = posix.stat(path)
             assert isinstance(st.st_mtime, int)
             assert st[7] == st.st_atime
+            assert posix.stat_float_times(-1) is False
+
         finally:
             posix.stat_float_times(current)
 
@@ -1148,6 +1151,11 @@
             assert posix.get_blocking(fd) is True
             posix.close(fd)
 
+        def test_blocking_error(self):
+            posix = self.posix
+            raises(OSError, posix.get_blocking, 1234567)
+            raises(OSError, posix.set_blocking, 1234567, True)
+
 
     def test_urandom(self):
         os = self.posix
@@ -1214,6 +1222,18 @@
         self.posix.RTLD_GLOBAL
         self.posix.RTLD_LOCAL
 
+    def test_error_message(self):
+        e = raises(OSError, self.posix.open, 'nonexistentfile1', 0)
+        assert str(e.value).endswith(": 'nonexistentfile1'")
+
+        e = raises(OSError, self.posix.link, 'nonexistentfile1', 'bok')
+        assert str(e.value).endswith(": 'nonexistentfile1' -> 'bok'")
+        e = raises(OSError, self.posix.rename, 'nonexistentfile1', 'bok')
+        assert str(e.value).endswith(": 'nonexistentfile1' -> 'bok'")
+
+        e = raises(OSError, self.posix.symlink, 'bok', '/nonexistentdir/boz')
+        assert str(e.value).endswith(": 'bok' -> '/nonexistentdir/boz'")
+
 
 class AppTestEnvironment(object):
     def setup_class(cls):
diff --git a/pypy/module/pyexpat/interp_pyexpat.py 
b/pypy/module/pyexpat/interp_pyexpat.py
--- a/pypy/module/pyexpat/interp_pyexpat.py
+++ b/pypy/module/pyexpat/interp_pyexpat.py
@@ -4,11 +4,11 @@
 from pypy.interpreter.error import OperationError, oefmt
 from pypy.interpreter.unicodehelper import encode_utf8
 from rpython.rlib import rgc, jit
+from rpython.rlib.objectmodel import specialize
 from rpython.rtyper.lltypesystem import rffi, lltype
 from rpython.rtyper.tool import rffi_platform
 from rpython.translator.tool.cbuild import ExternalCompilationInfo
 from rpython.translator.platform import platform
-from rpython.rlib.objectmodel import specialize
 
 import sys
 import weakref
diff --git a/pypy/module/signal/__init__.py b/pypy/module/signal/__init__.py
--- a/pypy/module/signal/__init__.py
+++ b/pypy/module/signal/__init__.py
@@ -3,6 +3,8 @@
 import os
 
 class Module(MixedModule):
+    applevel_name = '_signal'
+
     interpleveldefs = {
         'signal':              'interp_signal.signal',
         'getsignal':           'interp_signal.getsignal',
diff --git a/pypy/module/signal/test/test_signal.py 
b/pypy/module/signal/test/test_signal.py
--- a/pypy/module/signal/test/test_signal.py
+++ b/pypy/module/signal/test/test_signal.py
@@ -14,7 +14,7 @@
     def test_checksignals(self):
         space = self.space
         w_received = space.appexec([], """():
-            import signal
+            import _signal as signal
             received = []
             def myhandler(signum, frame):
                 received.append(signum)
@@ -40,7 +40,7 @@
     }
 
     def setup_class(cls):
-        cls.w_signal = cls.space.getbuiltinmodule('signal')
+        cls.w_signal = cls.space.getbuiltinmodule('_signal')
         cls.w_temppath = cls.space.wrap(
             str(py.test.ensuretemp("signal").join("foo.txt")))
         cls.w_appdirect = cls.space.wrap(cls.runappdirect)
@@ -92,7 +92,7 @@
         """
         Test that signal.signal returns SIG_DFL if that is the current handler.
         """
-        from signal import signal, SIGINT, SIG_DFL, SIG_IGN
+        from _signal import signal, SIGINT, SIG_DFL, SIG_IGN
 
         try:
             for handler in SIG_DFL, SIG_IGN, lambda *a: None:
@@ -105,7 +105,7 @@
         """
         Test that signal.signal returns SIG_IGN if that is the current handler.
         """
-        from signal import signal, SIGINT, SIG_DFL, SIG_IGN
+        from _signal import signal, SIGINT, SIG_DFL, SIG_IGN
 
         try:
             for handler in SIG_DFL, SIG_IGN, lambda *a: None:
@@ -119,7 +119,7 @@
         Test that signal.signal returns a Python object if one is the current
         handler.
         """
-        from signal import signal, SIGINT, SIG_DFL, SIG_IGN
+        from _signal import signal, SIGINT, SIG_DFL, SIG_IGN
         def installed(*a):
             pass
 
@@ -134,7 +134,7 @@
         """
         Test that signal.getsignal returns the currently installed handler.
         """
-        from signal import getsignal, signal, SIGINT, SIG_DFL, SIG_IGN
+        from _signal import getsignal, signal, SIGINT, SIG_DFL, SIG_IGN
 
         def handler(*a):
             pass
@@ -153,7 +153,7 @@
 
     def test_check_signum(self):
         import sys
-        from signal import getsignal, signal, NSIG
+        from _signal import getsignal, signal, NSIG
 
         # signum out of range fails
         raises(ValueError, getsignal, NSIG)
@@ -166,7 +166,7 @@
 
     def test_alarm(self):
         try:
-            from signal import alarm, signal, SIG_DFL, SIGALRM
+            from _signal import alarm, signal, SIG_DFL, SIGALRM
         except:
             skip('no alarm on this platform')
         import time
@@ -186,7 +186,7 @@
 
     def test_set_wakeup_fd(self):
         try:
-            import signal, posix, fcntl
+            import _signal as signal, posix, fcntl
         except ImportError:
             skip('cannot import posix or fcntl')
         def myhandler(signum, frame):
@@ -222,13 +222,13 @@
         signal.signal(signal.SIGINT, signal.SIG_DFL)
 
     def test_set_wakeup_fd_invalid(self):
-        import signal
+        import _signal as signal
         with open(self.temppath, 'wb') as f:
             fd = f.fileno()
         raises(ValueError, signal.set_wakeup_fd, fd)
 
     def test_siginterrupt(self):
-        import signal, os, time
+        import _signal as signal, os, time
         if not hasattr(signal, 'siginterrupt'):
             skip('non siginterrupt in signal')
         signum = signal.SIGUSR1
@@ -267,7 +267,7 @@
 
     def test_alarm_raise(self):
         try:
-            from signal import alarm, signal, SIG_DFL, SIGALRM
+            from _signal import alarm, signal, SIG_DFL, SIGALRM
         except ImportError:
             skip("no SIGALRM on this platform")
         import _socket
@@ -299,7 +299,7 @@
             py.test.skip("Unix only")
 
     def test_itimer_real(self):
-        import signal
+        import _signal as signal
 
         def sig_alrm(*args):
             self.called = True
@@ -316,7 +316,7 @@
         assert self.called
 
     def test_itimer_exc(self):
-        import signal
+        import _signal as signal
 
         raises(signal.ItimerError, signal.setitimer, -1, 0)
 
@@ -324,7 +324,7 @@
     spaceconfig = dict(usemodules=['signal', 'thread', 'time'])
 
     def test_pthread_kill(self):
-        import signal
+        import _signal as signal
         import _thread
         signum = signal.SIGUSR1
         def handler(signum, frame):
@@ -334,7 +334,7 @@
         raises(ZeroDivisionError, signal.pthread_kill, tid, signum)
         
     def test_sigwait(self):
-        import signal
+        import _signal as signal
         def handler(signum, frame):
             1/0
         signal.signal(signal.SIGALRM, handler)
@@ -343,7 +343,7 @@
         assert received == signal.SIGALRM
         
     def test_sigmask(self):
-        import signal, posix
+        import _signal as signal, posix
         signum1 = signal.SIGUSR1
         signum2 = signal.SIGUSR2
 
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
@@ -208,6 +208,7 @@
     def newunicode(self, x):
         return w_some_obj()
 
+    @specialize.argtype(1)
     def wrap(self, x):
         if not we_are_translated():
             if isinstance(x, gateway.interp2app):
@@ -221,7 +222,6 @@
                 return w_some_obj()
             self._wrap_not_rpython(x)
         return w_some_obj()
-    wrap._annspecialcase_ = "specialize:argtype(1)"
 
     def _wrap_not_rpython(self, x):
         "NOT_RPYTHON"
@@ -314,10 +314,10 @@
         is_root(w_complex)
         return 1.1, 2.2
 
+    @specialize.arg(1)
     def allocate_instance(self, cls, w_subtype):
         is_root(w_subtype)
         return instantiate(cls)
-    allocate_instance._annspecialcase_ = "specialize:arg(1)"
 
     def decode_index(self, w_index_or_slice, seqlength):
         is_root(w_index_or_slice)
diff --git a/pypy/objspace/fake/test/test_checkmodule.py 
b/pypy/objspace/fake/test/test_checkmodule.py
--- a/pypy/objspace/fake/test/test_checkmodule.py
+++ b/pypy/objspace/fake/test/test_checkmodule.py
@@ -9,9 +9,9 @@
 
 def make_checker():
     check = []
+    @specialize.memo()
     def see():
         check.append(True)
-    see._annspecialcase_ = 'specialize:memo'
     return see, check
 
 def test_wrap_interp2app():
diff --git a/pypy/objspace/std/formatting.py b/pypy/objspace/std/formatting.py
--- a/pypy/objspace/std/formatting.py
+++ b/pypy/objspace/std/formatting.py
@@ -2,12 +2,12 @@
 import sys
 
 from rpython.rlib import jit
+from rpython.rlib.objectmodel import specialize
 from rpython.rlib.rarithmetic import INT_MAX
 from rpython.rlib.rfloat import DTSF_ALT, formatd, isnan, isinf
 from rpython.rlib.rstring import StringBuilder, UnicodeBuilder
 from rpython.rlib.unroll import unrolling_iterable
 from rpython.tool.sourcetools import func_with_new_name
-from rpython.rlib.objectmodel import specialize
 
 from pypy.interpreter.error import OperationError, oefmt
 
@@ -483,24 +483,28 @@
                                     "character code not in range(256)")
                     self.std_wp(s)
                 return
-            if space.isinstance_w(w_value, space.w_str):
-                s = space.str_w(w_value)
+            if not do_unicode:
+                if space.isinstance_w(w_value, space.w_str):
+                    s = space.str_w(w_value)
+                elif space.isinstance_w(w_value, space.w_bytearray):
+                    s = w_value.buffer_w(space, 0).as_str()
+                else:
+                    s = ''
                 if len(s) == 1:
                     self.std_wp(s)
                     return
-            elif space.isinstance_w(w_value, space.w_unicode):
-                if not do_unicode:
-                    raise NeedUnicodeFormattingError
-                ustr = space.unicode_w(w_value)
-                if len(ustr) == 1:
-                    self.std_wp(ustr)
-                    return
-            if do_unicode:
+                raise oefmt(space.w_TypeError, "%c requires int or single 
byte")
+            else:
+                if space.isinstance_w(w_value, space.w_unicode):
+                    ustr = space.unicode_w(w_value)
+                    if len(ustr) == 1:
+                        self.std_wp(ustr)
+                        return
                 raise oefmt(space.w_TypeError, "%c requires int or char")
-            else:
-                raise oefmt(space.w_TypeError, "%c requires int or single 
byte")
 
         def fmt_b(self, w_value):
+            if do_unicode:
+                self.unknown_fmtchar()
             space = self.space
             # cpython explicitly checks for bytes & bytearray
             if space.isinstance_w(w_value, space.w_bytes):
@@ -522,7 +526,7 @@
                 return
 
             raise oefmt(space.w_TypeError,
-                    "requires bytes, or an object that" \
+                    "requires bytes, or an object that "
                     "implements __bytes__, not '%T'", w_value)
 
     return StringFormatter
diff --git a/pypy/objspace/std/test/test_stringformat.py 
b/pypy/objspace/std/test/test_stringformat.py
--- a/pypy/objspace/std/test/test_stringformat.py
+++ b/pypy/objspace/std/test/test_stringformat.py
@@ -178,6 +178,7 @@
         raises(TypeError, '%c'.__mod__, ("bla",))
         raises(TypeError, '%c'.__mod__, ("",))
         raises(TypeError, '%c'.__mod__, (['c'],))
+        raises(TypeError, '%c'.__mod__, b'A')
 
     def test___int__index__(self):
         class MyInt(object):
@@ -320,6 +321,10 @@
         f = 4
         raises(ValueError, '"%\u1234" % (f,)')
 
+    def test_invalid_b_with_unicode(self):
+        raises(ValueError, '"%b" % b"A"')
+        raises(ValueError, '"%b" % 42')
+
     def test_formatting_huge_precision(self):
         prec = 2**31
         format_string = u"%.{}f".format(prec)
@@ -368,6 +373,11 @@
         assert b"<%c>" % 48 == b"<0>"
         assert b"<%c>" % b"?" == b"<?>"
         raises(TypeError, 'b"<%c>" % "?"')
+        assert b"<%c>" % bytearray(b"?") == b"<?>"
+        class X:
+            def __bytes__(self):
+                return b'5'
+        raises(TypeError, 'b"<%c>" % X()')
 
     def test_bytes_bytes(self):
         assert b"<%b>" % b"123" == b"<123>"
@@ -421,6 +431,8 @@
         assert bytearray(b"<%c>") % 48 == bytearray(b"<0>")
         assert bytearray(b"<%c>") % b"?" == bytearray(b"<?>")
         raises(TypeError, 'bytearray(b"<%c>") % "?"')
+        assert bytearray(b"<%c>") % bytearray(b"?") == bytearray(b"<?>")
+        raises(TypeError, 'bytearray(b"<%c>") % memoryview(b"X")')
 
     def test_bytes_bytes(self):
         assert bytearray(b"<%b>") % b"123" == bytearray(b"<123>")
diff --git a/pypy/tool/cpyext/extbuild.py b/pypy/tool/cpyext/extbuild.py
--- a/pypy/tool/cpyext/extbuild.py
+++ b/pypy/tool/cpyext/extbuild.py
@@ -206,6 +206,10 @@
         pass
     from distutils.ccompiler import new_compiler
     from distutils import sysconfig
+
+    # XXX for Darwin running old versions of CPython 2.7.x
+    sysconfig.get_config_vars()
+
     compiler = new_compiler(force=1)
     sysconfig.customize_compiler(compiler)  # XXX
     objects = []
diff --git a/rpython/annotator/annrpython.py b/rpython/annotator/annrpython.py
--- a/rpython/annotator/annrpython.py
+++ b/rpython/annotator/annrpython.py
@@ -2,6 +2,7 @@
 
 import types
 from collections import defaultdict
+from contextlib import contextmanager
 
 from rpython.tool.ansi_print import AnsiLogger
 from rpython.tool.pairtype import pair
@@ -83,22 +84,17 @@
         annmodel.TLS.check_str_without_nul = (
             self.translator.config.translation.check_str_without_nul)
 
-        flowgraph, inputs_s = self.get_call_parameters(function, args_s, 
policy)
+        with self.using_policy(policy):
+            flowgraph, inputs_s = self.get_call_parameters(function, args_s)
 
         if main_entry_point:
             self.translator.entry_point_graph = flowgraph
         return self.build_graph_types(flowgraph, inputs_s, 
complete_now=complete_now)
 
-    def get_call_parameters(self, function, args_s, policy):
-        desc = self.bookkeeper.getdesc(function)
-        prevpolicy = self.policy
-        self.policy = policy
-        self.bookkeeper.enter(None)
-        try:
+    def get_call_parameters(self, function, args_s):
+        with self.bookkeeper.at_position(None):
+            desc = self.bookkeeper.getdesc(function)
             return desc.get_call_parameters(args_s)
-        finally:
-            self.bookkeeper.leave()
-            self.policy = prevpolicy
 
     def annotate_helper(self, function, args_s, policy=None):
         if policy is None:
@@ -107,21 +103,29 @@
             # XXX hack
             annmodel.TLS.check_str_without_nul = (
                 self.translator.config.translation.check_str_without_nul)
-        graph, inputcells = self.get_call_parameters(function, args_s, policy)
-        self.build_graph_types(graph, inputcells, complete_now=False)
-        self.complete_helpers(policy)
+        with self.using_policy(policy):
+            graph, inputcells = self.get_call_parameters(function, args_s)
+            self.build_graph_types(graph, inputcells, complete_now=False)
+            self.complete_helpers()
         return graph
 
-    def complete_helpers(self, policy):
-        saved = self.policy, self.added_blocks
-        self.policy = policy
+    def complete_helpers(self):
+        saved = self.added_blocks
+        self.added_blocks = {}
         try:
-            self.added_blocks = {}
             self.complete()
             # invoke annotation simplifications for the new blocks
             self.simplify(block_subset=self.added_blocks)
         finally:
-            self.policy, self.added_blocks = saved
+            self.added_blocks = saved
+
+    @contextmanager
+    def using_policy(self, policy):
+        """A context manager that temporarily replaces the annotator policy"""
+        old_policy = self.policy
+        self.policy = policy
+        yield
+        self.policy = old_policy
 
     def build_graph_types(self, flowgraph, inputcells, complete_now=True):
         checkgraph(flowgraph)
diff --git a/rpython/annotator/bookkeeper.py b/rpython/annotator/bookkeeper.py
--- a/rpython/annotator/bookkeeper.py
+++ b/rpython/annotator/bookkeeper.py
@@ -9,6 +9,7 @@
 from collections import OrderedDict
 
 from rpython.flowspace.model import Constant
+from rpython.flowspace.bytecode import cpython_code_signature
 from rpython.annotator.model import (
     SomeOrderedDict, SomeString, SomeChar, SomeFloat, unionof, SomeInstance,
     SomeDict, SomeBuiltin, SomePBC, SomeInteger, TLS, SomeUnicodeCodePoint,
@@ -21,6 +22,7 @@
 from rpython.annotator import description
 from rpython.annotator.signature import annotationoftype
 from rpython.annotator.argument import simple_args
+from rpython.annotator.specialize import memo
 from rpython.rlib.objectmodel import r_dict, r_ordereddict, Symbolic
 from rpython.tool.algo.unionfind import UnionFind
 from rpython.rtyper import extregistry
@@ -358,7 +360,7 @@
             return self.descs[obj_key]
         except KeyError:
             if isinstance(pyobj, types.FunctionType):
-                result = description.FunctionDesc(self, pyobj)
+                result = self.newfuncdesc(pyobj)
             elif isinstance(pyobj, (type, types.ClassType)):
                 if pyobj is object:
                     raise Exception("ClassDesc for object not supported")
@@ -403,6 +405,23 @@
             self.descs[obj_key] = result
             return result
 
+    def newfuncdesc(self, pyfunc):
+        name = pyfunc.__name__
+        if hasattr(pyfunc, '_generator_next_method_of_'):
+            from rpython.flowspace.argument import Signature
+            signature = Signature(['entry'])     # haaaaaack
+            defaults = ()
+        else:
+            signature = cpython_code_signature(pyfunc.func_code)
+            defaults = pyfunc.func_defaults
+        # get the specializer based on the tag of the 'pyobj'
+        # (if any), according to the current policy
+        tag = getattr(pyfunc, '_annspecialcase_', None)
+        specializer = self.annotator.policy.get_specializer(tag)
+        if specializer is memo:
+            return description.MemoDesc(self, pyfunc, name, signature, 
defaults, specializer)
+        return description.FunctionDesc(self, pyfunc, name, signature, 
defaults, specializer)
+
     def getfrozen(self, pyobj):
         return description.FrozenDesc(self, pyobj)
 
diff --git a/rpython/annotator/classdesc.py b/rpython/annotator/classdesc.py
--- a/rpython/annotator/classdesc.py
+++ b/rpython/annotator/classdesc.py
@@ -608,7 +608,7 @@
             if mixin:
                 # make a new copy of the FunctionDesc for this class,
                 # but don't specialize further for all subclasses
-                funcdesc = FunctionDesc(self.bookkeeper, value)
+                funcdesc = self.bookkeeper.newfuncdesc(value)
                 self.classdict[name] = funcdesc
                 return
             # NB. if value is, say, AssertionError.__init__, then we
diff --git a/rpython/annotator/description.py b/rpython/annotator/description.py
--- a/rpython/annotator/description.py
+++ b/rpython/annotator/description.py
@@ -3,11 +3,10 @@
 from rpython.annotator.signature import (
     enforce_signature_args, enforce_signature_return, finish_type)
 from rpython.flowspace.model import FunctionGraph
-from rpython.flowspace.bytecode import cpython_code_signature
 from rpython.annotator.argument import rawshape, ArgErr, simple_args
 from rpython.tool.sourcetools import valid_identifier
 from rpython.tool.pairtype import extendabletype
-from rpython.annotator.model import AnnotatorError, s_ImpossibleValue
+from rpython.annotator.model import AnnotatorError, s_ImpossibleValue, unionof
 
 class CallFamily(object):
     """A family of Desc objects that could be called from common call sites.
@@ -117,7 +116,6 @@
         self.s_value = s_ImpossibleValue    # union of possible values
 
     def update(self, other):
-        from rpython.annotator.model import unionof
         self.descs.update(other.descs)
         self.read_locations.update(other.read_locations)
         self.s_value = unionof(self.s_value, other.s_value)
@@ -192,24 +190,12 @@
 class FunctionDesc(Desc):
     knowntype = types.FunctionType
 
-    def __init__(self, bookkeeper, pyobj=None,
-                 name=None, signature=None, defaults=None,
+    def __init__(self, bookkeeper, pyobj, name, signature, defaults,
                  specializer=None):
         super(FunctionDesc, self).__init__(bookkeeper, pyobj)
-        if name is None:
-            name = pyobj.func_name
-        if signature is None:
-            if hasattr(pyobj, '_generator_next_method_of_'):
-                from rpython.flowspace.argument import Signature
-                signature = Signature(['entry'])     # haaaaaack
-                defaults = ()
-            else:
-                signature = cpython_code_signature(pyobj.func_code)
-        if defaults is None:
-            defaults = pyobj.func_defaults
         self.name = name
         self.signature = signature
-        self.defaults = defaults or ()
+        self.defaults = defaults if defaults is not None else ()
         # 'specializer' is a function with the following signature:
         #      specializer(funcdesc, args_s) => graph
         #                                 or => s_result (overridden/memo 
cases)
@@ -288,12 +274,43 @@
                 getattr(self.bookkeeper, "position_key", None) is not None):
             _, block, i = self.bookkeeper.position_key
             op = block.operations[i]
-        if self.specializer is None:
-            # get the specializer based on the tag of the 'pyobj'
-            # (if any), according to the current policy
-            tag = getattr(self.pyobj, '_annspecialcase_', None)
-            policy = self.bookkeeper.annotator.policy
-            self.specializer = policy.get_specializer(tag)
+        self.normalize_args(inputcells)
+        if getattr(self.pyobj, '_annspecialcase_', 
'').endswith("call_location"):
+            return self.specializer(self, inputcells, op)
+        else:
+            return self.specializer(self, inputcells)
+
+    def pycall(self, whence, args, s_previous_result, op=None):
+        inputcells = self.parse_arguments(args)
+        graph = self.specialize(inputcells, op)
+        assert isinstance(graph, FunctionGraph)
+        # if that graph has a different signature, we need to re-parse
+        # the arguments.
+        # recreate the args object because inputcells may have been changed
+        new_args = args.unmatch_signature(self.signature, inputcells)
+        inputcells = self.parse_arguments(new_args, graph)
+        annotator = self.bookkeeper.annotator
+        result = annotator.recursivecall(graph, whence, inputcells)
+        signature = getattr(self.pyobj, '_signature_', None)
+        if signature:
+            sigresult = enforce_signature_return(self, signature[1], result)
+            if sigresult is not None:
+                annotator.addpendingblock(
+                    graph, graph.returnblock, [sigresult])
+                result = sigresult
+        # Some specializations may break the invariant of returning
+        # annotations that are always more general than the previous time.
+        # We restore it here:
+        result = unionof(result, s_previous_result)
+        return result
+
+    def normalize_args(self, inputs_s):
+        """
+        Canonicalize argument annotations into the exact parameter
+        annotations of a specific specialized graph.
+
+        Note: this method has no return value but mutates its argument instead.
+        """
         enforceargs = getattr(self.pyobj, '_annenforceargs_', None)
         signature = getattr(self.pyobj, '_signature_', None)
         if enforceargs and signature:
@@ -304,39 +321,9 @@
                 from rpython.annotator.signature import Sig
                 enforceargs = Sig(*enforceargs)
                 self.pyobj._annenforceargs_ = enforceargs
-            enforceargs(self, inputcells)  # can modify inputcells in-place
+            enforceargs(self, inputs_s)  # can modify inputs_s in-place
         if signature:
-            enforce_signature_args(self, signature[0], inputcells)  # mutates 
inputcells
-        if getattr(self.pyobj, '_annspecialcase_', 
'').endswith("call_location"):
-            return self.specializer(self, inputcells, op)
-        else:
-            return self.specializer(self, inputcells)
-
-    def pycall(self, whence, args, s_previous_result, op=None):
-        inputcells = self.parse_arguments(args)
-        result = self.specialize(inputcells, op)
-        if isinstance(result, FunctionGraph):
-            graph = result         # common case
-            annotator = self.bookkeeper.annotator
-            # if that graph has a different signature, we need to re-parse
-            # the arguments.
-            # recreate the args object because inputcells may have been changed
-            new_args = args.unmatch_signature(self.signature, inputcells)
-            inputcells = self.parse_arguments(new_args, graph)
-            result = annotator.recursivecall(graph, whence, inputcells)
-            signature = getattr(self.pyobj, '_signature_', None)
-            if signature:
-                sigresult = enforce_signature_return(self, signature[1], 
result)
-                if sigresult is not None:
-                    annotator.addpendingblock(
-                        graph, graph.returnblock, [sigresult])
-                    result = sigresult
-        # Some specializations may break the invariant of returning
-        # annotations that are always more general than the previous time.
-        # We restore it here:
-        from rpython.annotator.model import unionof
-        result = unionof(result, s_previous_result)
-        return result
+            enforce_signature_args(self, signature[0], inputs_s)  # mutates 
inputs_s
 
     def get_graph(self, args, op):
         inputs_s = self.parse_arguments(args)
@@ -405,6 +392,16 @@
 
             return s_sigs
 
+class MemoDesc(FunctionDesc):
+    def pycall(self, whence, args, s_previous_result, op=None):
+        inputcells = self.parse_arguments(args)
+        s_result = self.specialize(inputcells, op)
+        if isinstance(s_result, FunctionGraph):
+            s_result = s_result.getreturnvar().annotation
+        s_result = unionof(s_result, s_previous_result)
+        return s_result
+
+
 class MethodDesc(Desc):
     knowntype = types.MethodType
 
diff --git a/rpython/annotator/specialize.py b/rpython/annotator/specialize.py
--- a/rpython/annotator/specialize.py
+++ b/rpython/annotator/specialize.py
@@ -3,11 +3,13 @@
 
 from rpython.tool.sourcetools import func_with_new_name
 from rpython.tool.algo.unionfind import UnionFind
-from rpython.flowspace.model import Block, Link, Variable, SpaceOperation
+from rpython.flowspace.model import Block, Link, Variable
 from rpython.flowspace.model import checkgraph
 from rpython.flowspace.operation import op
 from rpython.annotator import model as annmodel
 from rpython.flowspace.argument import Signature
+from rpython.annotator.model import SomePBC, SomeImpossibleValue, SomeBool
+from rpython.annotator.model import unionof
 
 def flatten_star_args(funcdesc, args_s):
     argnames, vararg, kwarg = funcdesc.signature
@@ -127,7 +129,6 @@
     def finish(self):
         if self.do_not_process:
             return
-        from rpython.annotator.model import unionof
         assert self.graph is None, "MemoTable already finished"
         # list of which argument positions can take more than one value
         example_args, example_value = self.table.iteritems().next()
@@ -246,34 +247,36 @@
             args_s.append(unionof(*values_s))
         annotator.addpendinggraph(self.graph, args_s)
 
+def all_values(s):
+    """Return the exhaustive list of possible values matching annotation `s`.
 
-def memo(funcdesc, arglist_s):
-    from rpython.annotator.model import SomePBC, SomeImpossibleValue, SomeBool
-    from rpython.annotator.model import unionof
+    Raises `AnnotatorError` if no such (reasonably small) finite list exists.
+    """
+    if s.is_constant():
+        return [s.const]
+    elif isinstance(s, SomePBC):
+        values = []
+        assert not s.can_be_None, "memo call: cannot mix None and PBCs"
+        for desc in s.descriptions:
+            if desc.pyobj is None:
+                raise annmodel.AnnotatorError(
+                    "memo call with a class or PBC that has no "
+                    "corresponding Python object (%r)" % (desc,))
+            values.append(desc.pyobj)
+        return values
+    elif isinstance(s, SomeImpossibleValue):
+        return []
+    elif isinstance(s, SomeBool):
+        return [False, True]
+    else:
+        raise annmodel.AnnotatorError("memo call: argument must be a class "
+                                        "or a frozen PBC, got %r" % (s,))
+
+def memo(funcdesc, args_s):
     # call the function now, and collect possible results
-    argvalues = []
-    for s in arglist_s:
-        if s.is_constant():
-            values = [s.const]
-        elif isinstance(s, SomePBC):
-            values = []
-            assert not s.can_be_None, "memo call: cannot mix None and PBCs"
-            for desc in s.descriptions:
-                if desc.pyobj is None:
-                    raise annmodel.AnnotatorError(
-                        "memo call with a class or PBC that has no "
-                        "corresponding Python object (%r)" % (desc,))
-                values.append(desc.pyobj)
-        elif isinstance(s, SomeImpossibleValue):
-            return s    # we will probably get more possible args later
-        elif isinstance(s, SomeBool):
-            values = [False, True]
-        else:
-            raise annmodel.AnnotatorError("memo call: argument must be a class 
"
-                                          "or a frozen PBC, got %r" % (s,))
-        argvalues.append(values)
+
     # the list of all possible tuples of arguments to give to the memo function
-    possiblevalues = cartesian_product(argvalues)
+    possiblevalues = cartesian_product([all_values(s_arg) for s_arg in args_s])
 
     # a MemoTable factory -- one MemoTable per family of arguments that can
     # be called together, merged via a UnionFind.
diff --git a/rpython/memory/gc/incminimark.py b/rpython/memory/gc/incminimark.py
--- a/rpython/memory/gc/incminimark.py
+++ b/rpython/memory/gc/incminimark.py
@@ -2936,6 +2936,12 @@
         self._pyobj(pyobject).ob_pypy_link = objint
         # there is no rrc_o_dict
 
+    def rawrefcount_mark_deallocating(self, gcobj, pyobject):
+        ll_assert(self.rrc_enabled, "rawrefcount.init not called")
+        obj = llmemory.cast_ptr_to_adr(gcobj)   # should be a prebuilt obj
+        objint = llmemory.cast_adr_to_int(obj, "symbolic")
+        self._pyobj(pyobject).ob_pypy_link = objint
+
     def rawrefcount_from_obj(self, gcobj):
         obj = llmemory.cast_ptr_to_adr(gcobj)
         if self.is_in_nursery(obj):
diff --git a/rpython/memory/gctransform/framework.py 
b/rpython/memory/gctransform/framework.py
--- a/rpython/memory/gctransform/framework.py
+++ b/rpython/memory/gctransform/framework.py
@@ -476,6 +476,10 @@
                 GCClass.rawrefcount_create_link_pyobj,
                 [s_gc, s_gcref, SomeAddress()],
                 annmodel.s_None)
+            self.rawrefcount_mark_deallocating = getfn(
+                GCClass.rawrefcount_mark_deallocating,
+                [s_gc, s_gcref, SomeAddress()],
+                annmodel.s_None)
             self.rawrefcount_from_obj_ptr = getfn(
                 GCClass.rawrefcount_from_obj, [s_gc, s_gcref], SomeAddress(),
                 inline = True)
@@ -1281,6 +1285,14 @@
                   [self.rawrefcount_create_link_pyobj_ptr, self.c_const_gc,
                    v_gcobj, v_pyobject])
 
+    def gct_gc_rawrefcount_mark_deallocating(self, hop):
+        [v_gcobj, v_pyobject] = hop.spaceop.args
+        assert v_gcobj.concretetype == llmemory.GCREF
+        assert v_pyobject.concretetype == llmemory.Address
+        hop.genop("direct_call",
+                  [self.rawrefcount_mark_deallocating, self.c_const_gc,
+                   v_gcobj, v_pyobject])
+
     def gct_gc_rawrefcount_from_obj(self, hop):
         [v_gcobj] = hop.spaceop.args
         assert v_gcobj.concretetype == llmemory.GCREF
diff --git a/rpython/rlib/jit.py b/rpython/rlib/jit.py
--- a/rpython/rlib/jit.py
+++ b/rpython/rlib/jit.py
@@ -3,7 +3,7 @@
 import py
 
 from rpython.rlib.nonconst import NonConstant
-from rpython.rlib.objectmodel import CDefinedIntSymbolic, 
keepalive_until_here, specialize, not_rpython
+from rpython.rlib.objectmodel import CDefinedIntSymbolic, 
keepalive_until_here, specialize, not_rpython, we_are_translated
 from rpython.rlib.unroll import unrolling_iterable
 from rpython.rtyper.extregistry import ExtRegistryEntry
 from rpython.tool.sourcetools import rpython_wrapper
@@ -1221,7 +1221,8 @@
         x = jit.conditional_call_elidable(self.cache, _compute_and_cache, ...)
 
     """
-    if we_are_jitted():
+    if we_are_translated() and we_are_jitted():
+        #^^^ the occasional test patches we_are_jitted() to True
         return _jit_conditional_call_value(value, function, *args)
     else:
         if isinstance(value, int):
diff --git a/rpython/rlib/rarithmetic.py b/rpython/rlib/rarithmetic.py
--- a/rpython/rlib/rarithmetic.py
+++ b/rpython/rlib/rarithmetic.py
@@ -25,6 +25,10 @@
          lltype.Unsigned, widen it to lltype.Signed.
          Useful because the translator doesn't support
          arithmetic on the smaller types.
+ovfcheck_int32_add/sub/mul(x, y)
+         perform an add/sub/mul between two regular integers,
+         but assumes that they fit inside signed 32-bit ints
+         and raises OverflowError if the result no longer does
 
 These are meant to be erased by translation, r_uint
 in the process should mark unsigned values, ovfcheck should
@@ -796,6 +800,47 @@
         return longlong2float(rffi.cast(rffi.LONGLONG, res))
     return rffi.cast(T, res)
 
+if sys.maxint == 2147483647:
+    def ovfcheck_int32_add(x, y):
+        return ovfcheck(x + y)
+    def ovfcheck_int32_sub(x, y):
+        return ovfcheck(x - y)
+    def ovfcheck_int32_mul(x, y):
+        return ovfcheck(x * y)
+else:
+    def ovfcheck_int32_add(x, y):
+        """x and y are assumed to fit inside the 32-bit rffi.INT;
+        raises OverflowError if the result doesn't fit rffi.INT"""
+        from rpython.rtyper.lltypesystem import lltype, rffi
+        x = rffi.cast(lltype.Signed, x)
+        y = rffi.cast(lltype.Signed, y)
+        z = x + y
+        if z != rffi.cast(lltype.Signed, rffi.cast(rffi.INT, z)):
+            raise OverflowError
+        return z
+
+    def ovfcheck_int32_sub(x, y):
+        """x and y are assumed to fit inside the 32-bit rffi.INT;
+        raises OverflowError if the result doesn't fit rffi.INT"""
+        from rpython.rtyper.lltypesystem import lltype, rffi
+        x = rffi.cast(lltype.Signed, x)
+        y = rffi.cast(lltype.Signed, y)
+        z = x - y
+        if z != rffi.cast(lltype.Signed, rffi.cast(rffi.INT, z)):
+            raise OverflowError
+        return z
+
+    def ovfcheck_int32_mul(x, y):
+        """x and y are assumed to fit inside the 32-bit rffi.INT;
+        raises OverflowError if the result doesn't fit rffi.INT"""
+        from rpython.rtyper.lltypesystem import lltype, rffi
+        x = rffi.cast(lltype.Signed, x)
+        y = rffi.cast(lltype.Signed, y)
+        z = x * y
+        if z != rffi.cast(lltype.Signed, rffi.cast(rffi.INT, z)):
+            raise OverflowError
+        return z
+
 
 # String parsing support
 # ---------------------------
diff --git a/rpython/rlib/rawrefcount.py b/rpython/rlib/rawrefcount.py
--- a/rpython/rlib/rawrefcount.py
+++ b/rpython/rlib/rawrefcount.py
@@ -36,6 +36,7 @@
     _pypy2ob = {}
     _pypy2ob_rev = {}
     _d_list = []
+    _d_marker = None
     _dealloc_trigger_callback = dealloc_trigger_callback
 
 @not_rpython
@@ -62,6 +63,14 @@
     _o_list.append(ob)
 
 @not_rpython
+def mark_deallocating(marker, ob):
+    """mark the PyObject as deallocating, by storing 'marker'
+    inside its ob_pypy_link field"""
+    assert ob._obj not in _pypy2ob_rev
+    assert not ob.c_ob_pypy_link
+    ob.c_ob_pypy_link = _build_pypy_link(marker)
+
+@not_rpython
 def from_obj(OB_PTR_TYPE, p):
     ob = _pypy2ob.get(p)
     if ob is None:
@@ -221,7 +230,7 @@
 
 
 class Entry(ExtRegistryEntry):
-    _about_ = (create_link_pypy, create_link_pyobj)
+    _about_ = (create_link_pypy, create_link_pyobj, mark_deallocating)
 
     def compute_result_annotation(self, s_p, s_ob):
         pass
@@ -231,6 +240,8 @@
             name = 'gc_rawrefcount_create_link_pypy'
         elif self.instance is create_link_pyobj:
             name = 'gc_rawrefcount_create_link_pyobj'
+        elif self.instance is mark_deallocating:
+            name = 'gc_rawrefcount_mark_deallocating'
         v_p, v_ob = hop.inputargs(*hop.args_r)
         hop.exception_cannot_occur()
         hop.genop(name, [_unspec_p(hop, v_p), _unspec_ob(hop, v_ob)])
diff --git a/rpython/rlib/rjitlog/rjitlog.py b/rpython/rlib/rjitlog/rjitlog.py
--- a/rpython/rlib/rjitlog/rjitlog.py
+++ b/rpython/rlib/rjitlog/rjitlog.py
@@ -13,6 +13,7 @@
 from rpython.jit.metainterp.resoperation import rop
 from rpython.jit.metainterp.history import ConstInt, ConstFloat
 from rpython.rlib.objectmodel import we_are_translated
+from rpython.rlib.rarithmetic import r_longlong
 from rpython.rtyper.lltypesystem import lltype, llmemory, rffi
 from rpython.rlib.objectmodel import compute_unique_id, always_inline
 from rpython.rlib.objectmodel import we_are_translated, specialize
@@ -113,6 +114,7 @@
 
 @always_inline
 def encode_le_64bit(val):
+    val = r_longlong(val)     # force 64-bit, even on 32-bit
     return ''.join([chr((val >> 0) & 0xff),
                     chr((val >> 8) & 0xff),
                     chr((val >> 16) & 0xff),
diff --git a/rpython/rlib/rurandom.py b/rpython/rlib/rurandom.py
--- a/rpython/rlib/rurandom.py
+++ b/rpython/rlib/rurandom.py
@@ -75,16 +75,6 @@
 
             return rffi.charpsize2str(rffi.cast(rffi.CCHARP, buf), n)
 
-elif 0:  # __VMS
-    from rpython.rlib.ropenssl import libssl_RAND_pseudo_bytes
-    def init_urandom():
-        pass
-
-    def urandom(context, n):
-        with rffi.scoped_alloc_buffer(n) as buf:
-            if libssl_RAND_pseudo_bytes(self.raw, n) < 0:
-                raise ValueError("RAND_pseudo_bytes")
-            return buf.str(n)
 else:  # Posix implementation
     @not_rpython
     def init_urandom():
diff --git a/rpython/rlib/rvmprof/src/vmprof_getpc.h 
b/rpython/rlib/rvmprof/src/vmprof_getpc.h
--- a/rpython/rlib/rvmprof/src/vmprof_getpc.h
+++ b/rpython/rlib/rvmprof/src/vmprof_getpc.h
@@ -126,13 +126,14 @@
 // how we'd get the PC (using StackWalk64?)
 //    http://msdn2.microsoft.com/en-us/library/ms680650.aspx
 
-#include "base/logging.h"   // for RAW_LOG
-#ifndef HAVE_CYGWIN_SIGNAL_H
-typedef int ucontext_t;
-#endif
+// #include "base/logging.h"   // for RAW_LOG
+// #ifndef HAVE_CYGWIN_SIGNAL_H
+// typedef int ucontext_t;
+// #endif
 
 intptr_t GetPC(ucontext_t *signal_ucontext) {
-  RAW_LOG(ERROR, "GetPC is not yet implemented on Windows\n");
+  // RAW_LOG(ERROR, "GetPC is not yet implemented on Windows\n");
+  fprintf(stderr, "GetPC is not yet implemented on Windows\n");
   return NULL;
 }
 
diff --git a/rpython/rlib/test/test_rarithmetic.py 
b/rpython/rlib/test/test_rarithmetic.py
--- a/rpython/rlib/test/test_rarithmetic.py
+++ b/rpython/rlib/test/test_rarithmetic.py
@@ -675,3 +675,11 @@
     assert a ^ r_uint32(42) == "a^42"
     assert r_uint32(42) ** a == "42**a"
     assert a ** r_uint32(42) == "a**42"
+
+def test_ovfcheck_int32():
+    assert ovfcheck_int32_add(-2**30, -2**30) == -2**31
+    py.test.raises(OverflowError, ovfcheck_int32_add, 2**30, 2**30)
+    assert ovfcheck_int32_sub(-2**30, 2**30) == -2**31
+    py.test.raises(OverflowError, ovfcheck_int32_sub, 2**30, -2**30)
+    assert ovfcheck_int32_mul(-2**16, 2**15) == -2**31
+    py.test.raises(OverflowError, ovfcheck_int32_mul, -2**16, -2**15)
diff --git a/rpython/rlib/test/test_rawrefcount.py 
b/rpython/rlib/test/test_rawrefcount.py
--- a/rpython/rlib/test/test_rawrefcount.py
+++ b/rpython/rlib/test/test_rawrefcount.py
@@ -212,6 +212,15 @@
         assert rawrefcount.to_obj(W_Root, ob) == p
         lltype.free(ob, flavor='raw')
 
+    def test_mark_deallocating(self):
+        ob = lltype.malloc(PyObjectS, flavor='raw', zero=True)
+        w_marker = W_Root(42)
+        rawrefcount.mark_deallocating(w_marker, ob)
+        assert rawrefcount.to_obj(W_Root, ob) is w_marker
+        rawrefcount._collect()
+        assert rawrefcount.to_obj(W_Root, ob) is w_marker
+        lltype.free(ob, flavor='raw')
+
 
 class TestTranslated(StandaloneTests):
 
@@ -222,6 +231,7 @@
         state.seen = []
         def dealloc_trigger():
             state.seen.append(1)
+        w_marker = W_Root(-1)
 
         def make_p():
             p = W_Root(42)
@@ -257,6 +267,13 @@
             if rawrefcount.next_dead(PyObject) != lltype.nullptr(PyObjectS):
                 print "NEXT_DEAD second time != NULL"
                 return 1
+            if rawrefcount.to_obj(W_Root, ob) is not None:
+                print "to_obj(dead) is not None?"
+                return 1
+            rawrefcount.mark_deallocating(w_marker, ob)
+            if rawrefcount.to_obj(W_Root, ob) is not w_marker:
+                print "to_obj(marked-dead) is not w_marker"
+                return 1
             print "OK!"
             lltype.free(ob, flavor='raw')
             return 0
diff --git a/rpython/rtyper/annlowlevel.py b/rpython/rtyper/annlowlevel.py
--- a/rpython/rtyper/annlowlevel.py
+++ b/rpython/rtyper/annlowlevel.py
@@ -138,11 +138,12 @@
         # get the graph of the mix-level helper ll_function and prepare it for
         # being annotated.  Annotation and RTyping should be done in a single 
shot
         # at the end with finish().
-        graph, args_s = self.rtyper.annotator.get_call_parameters(
-            ll_function, args_s, policy = self.policy)
+        ann = self.rtyper.annotator
+        with ann.using_policy(self.policy):
+            graph, args_s = ann.get_call_parameters(ll_function, args_s)
         for v_arg, s_arg in zip(graph.getargs(), args_s):
-            self.rtyper.annotator.setbinding(v_arg, s_arg)
-        self.rtyper.annotator.setbinding(graph.getreturnvar(), s_result)
+            ann.setbinding(v_arg, s_arg)
+        ann.setbinding(graph.getreturnvar(), s_result)
         #self.rtyper.annotator.annotated[graph.returnblock] = graph
         self.pending.append((ll_function, graph, args_s, s_result))
         return graph
@@ -224,16 +225,17 @@
         bk = ann.bookkeeper
         translator = ann.translator
         original_graph_count = len(translator.graphs)
-        for ll_function, graph, args_s, s_result in self.pending:
-            # mark the return block as already annotated, because the return 
var
-            # annotation was forced in getgraph() above.  This prevents 
temporary
-            # less general values reaching the return block from crashing the
-            # annotator (on the assert-that-new-binding-is-not-less-general).
-            ann.annotated[graph.returnblock] = graph
-            s_function = bk.immutablevalue(ll_function)
-            bk.emulate_pbc_call(graph, s_function, args_s)
-            self.newgraphs.add(graph)
-        ann.complete_helpers(self.policy)
+        with ann.using_policy(self.policy):
+            for ll_function, graph, args_s, s_result in self.pending:
+                # mark the return block as already annotated, because the 
return var
+                # annotation was forced in getgraph() above.  This prevents 
temporary
+                # less general values reaching the return block from crashing 
the
+                # annotator (on the 
assert-that-new-binding-is-not-less-general).
+                ann.annotated[graph.returnblock] = graph
+                s_function = bk.immutablevalue(ll_function)
+                bk.emulate_pbc_call(graph, s_function, args_s)
+                self.newgraphs.add(graph)
+            ann.complete_helpers()
         for ll_function, graph, args_s, s_result in self.pending:
             s_real_result = ann.binding(graph.getreturnvar())
             if s_real_result != s_result:
diff --git a/rpython/rtyper/llinterp.py b/rpython/rtyper/llinterp.py
--- a/rpython/rtyper/llinterp.py
+++ b/rpython/rtyper/llinterp.py
@@ -959,6 +959,9 @@
     def op_gc_rawrefcount_create_link_pypy(self, *args):
         raise NotImplementedError("gc_rawrefcount_create_link_pypy")
 
+    def op_gc_rawrefcount_mark_deallocating(self, *args):
+        raise NotImplementedError("gc_rawrefcount_mark_deallocating")
+
     def op_do_malloc_fixedsize(self):
         raise NotImplementedError("do_malloc_fixedsize")
     def op_do_malloc_fixedsize_clear(self):
diff --git a/rpython/rtyper/lltypesystem/llmemory.py 
b/rpython/rtyper/lltypesystem/llmemory.py
--- a/rpython/rtyper/lltypesystem/llmemory.py
+++ b/rpython/rtyper/lltypesystem/llmemory.py
@@ -384,7 +384,6 @@
 def _sizeof_none(TYPE):
     assert not TYPE._is_varsize()
     return ItemOffset(TYPE)
-_sizeof_none._annspecialcase_ = 'specialize:memo'
 
 @specialize.memo()
 def _internal_array_field(TYPE):
diff --git a/rpython/rtyper/lltypesystem/lloperation.py 
b/rpython/rtyper/lltypesystem/lloperation.py
--- a/rpython/rtyper/lltypesystem/lloperation.py
+++ b/rpython/rtyper/lltypesystem/lloperation.py
@@ -490,6 +490,7 @@
     'gc_rawrefcount_init':              LLOp(),
     'gc_rawrefcount_create_link_pypy':  LLOp(),
     'gc_rawrefcount_create_link_pyobj': LLOp(),
+    'gc_rawrefcount_mark_deallocating': LLOp(),
     'gc_rawrefcount_from_obj':          LLOp(sideeffects=False),
     'gc_rawrefcount_to_obj':            LLOp(sideeffects=False),
 
diff --git a/rpython/rtyper/lltypesystem/rffi.py 
b/rpython/rtyper/lltypesystem/rffi.py
--- a/rpython/rtyper/lltypesystem/rffi.py
+++ b/rpython/rtyper/lltypesystem/rffi.py
@@ -7,7 +7,7 @@
 from rpython.rtyper.lltypesystem.llmemory import itemoffsetof
 from rpython.rtyper.llannotation import lltype_to_annotation
 from rpython.tool.sourcetools import func_with_new_name
-from rpython.rlib.objectmodel import Symbolic
+from rpython.rlib.objectmodel import Symbolic, specialize
 from rpython.rlib.objectmodel import keepalive_until_here, enforceargs
 from rpython.rlib import rarithmetic, rgc
 from rpython.rtyper.extregistry import ExtRegistryEntry
@@ -74,7 +74,7 @@
 def llexternal(name, args, result, _callable=None,
                compilation_info=ExternalCompilationInfo(),
                sandboxsafe=False, releasegil='auto',
-               _nowrapper=False, calling_conv='c',
+               _nowrapper=False, calling_conv=None,
                elidable_function=False, macro=None,
                random_effects_on_gcobjs='auto',
                save_err=RFFI_ERR_NONE):
@@ -96,7 +96,17 @@
                 we consider that the function is really short-running and
                 don't bother releasing the GIL.  An explicit True or False
                 overrides this logic.
+
+    calling_conv: if 'unknown' or 'win', the C function is not directly seen
+                  by the JIT.  If 'c', it can be seen (depending on
+                  releasegil=False).  For tests only, or if _nowrapper,
+                  it defaults to 'c'.
     """
+    if calling_conv is None:
+        if sys.platform == 'win32' and not _nowrapper:
+            calling_conv = 'unknown'
+        else:
+            calling_conv = 'c'
     if _callable is not None:
         assert callable(_callable)
     ext_type = lltype.FuncType(args, result)
@@ -107,7 +117,8 @@
             _callable = generate_macro_wrapper(
                 name, macro, ext_type, compilation_info)
         else:
-            _callable = ll2ctypes.LL2CtypesCallable(ext_type, calling_conv)
+            _callable = ll2ctypes.LL2CtypesCallable(ext_type,
+                'c' if calling_conv == 'unknown' else calling_conv)
     else:
         assert macro is None, "'macro' is useless if you specify '_callable'"
     if elidable_function:
@@ -205,11 +216,17 @@
     else:
         # if we don't have to invoke the GIL handling, we can just call
         # the low-level function pointer carelessly
-        if macro is None and save_err == RFFI_ERR_NONE:
+        # ...well, unless it's a macro, in which case we still have
+        # to hide it from the JIT...
+        need_wrapper = (macro is not None or save_err != RFFI_ERR_NONE)
+        # ...and unless we're on Windows and the calling convention is
+        # 'win' or 'unknown'
+        if calling_conv != 'c':
+            need_wrapper = True
+        #
+        if not need_wrapper:
             call_external_function = funcptr
         else:
-            # ...well, unless it's a macro, in which case we still have
-            # to hide it from the JIT...
             argnames = ', '.join(['a%d' % i for i in range(len(args))])
             source = py.code.Source("""
                 def call_external_function(%(argnames)s):
@@ -308,10 +325,6 @@
     # for debugging, stick ll func ptr to that
     wrapper._ptr = funcptr
     wrapper = func_with_new_name(wrapper, name)
-
-    if calling_conv != "c":
-        wrapper = jit.dont_look_inside(wrapper)
-
     return wrapper
 
 
@@ -1288,10 +1301,12 @@
 c_memcpy = llexternal("memcpy",
             [VOIDP, VOIDP, SIZE_T],
             lltype.Void,
-            releasegil=False
+            releasegil=False,
+            calling_conv='c',
         )
 c_memset = llexternal("memset",
             [VOIDP, lltype.Signed, SIZE_T],
             lltype.Void,
-            releasegil=False
+            releasegil=False,
+            calling_conv='c',
         )
diff --git a/rpython/rtyper/rpbc.py b/rpython/rtyper/rpbc.py
--- a/rpython/rtyper/rpbc.py
+++ b/rpython/rtyper/rpbc.py
@@ -362,9 +362,9 @@
     def get_concrete_llfn(self, s_pbc, args_s, op):
         bk = self.rtyper.annotator.bookkeeper
         funcdesc, = s_pbc.descriptions
-        args = simple_args(args_s)
         with bk.at_position(None):
-            graph = funcdesc.get_graph(args, op)
+            argspec = simple_args(args_s)
+            graph = funcdesc.get_graph(argspec, op)
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to