[pypy-commit] pypy py3.5: hg merge default

arigo pypy.commits at gmail.com
Mon Nov 28 12:34:18 EST 2016


Author: Armin Rigo <arigo at tunes.org>
Branch: py3.5
Changeset: r88711:c8b4b78af01a
Date: 2016-11-28 18:33 +0100
http://bitbucket.org/pypy/pypy/changeset/c8b4b78af01a/

Log:	hg merge default

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/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/error.py b/pypy/interpreter/error.py
--- a/pypy/interpreter/error.py
+++ b/pypy/interpreter/error.py
@@ -559,6 +559,7 @@
                                           space.wrap(msg))
         return OperationError(exc, w_error)
 
+ at specialize.arg(3)
 def wrap_oserror2(space, e, w_filename=None, exception_name='w_OSError',
                   w_exception_class=None):
     assert isinstance(e, OSError)
@@ -586,8 +587,8 @@
         w_error = space.call_function(exc, space.wrap(errno),
                                       space.wrap(msg))
     return OperationError(exc, w_error)
-wrap_oserror2._annspecialcase_ = 'specialize:arg(3)'
 
+ at specialize.arg(3)
 def wrap_oserror(space, e, filename=None, exception_name='w_OSError',
                  w_exception_class=None):
     if filename is not None:
@@ -598,7 +599,6 @@
         return wrap_oserror2(space, e, None,
                              exception_name=exception_name,
                              w_exception_class=w_exception_class)
-wrap_oserror._annspecialcase_ = 'specialize:arg(3)'
 
 def exception_from_saved_errno(space, w_type):
     from rpython.rlib.rposix import get_saved_errno
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/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/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
 
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)
+
+ at 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)
         llfn = self.rtyper.getcallable(graph)
         return inputconst(typeOf(llfn), llfn)
 
diff --git a/rpython/rtyper/rtyper.py b/rpython/rtyper/rtyper.py
--- a/rpython/rtyper/rtyper.py
+++ b/rpython/rtyper/rtyper.py
@@ -846,28 +846,29 @@
         rtyper = self.rtyper
         args_s = []
         newargs_v = []
-        for v in args_v:
-            if v.concretetype is Void:
-                s_value = rtyper.annotation(v)
-                if s_value is None:
-                    s_value = annmodel.s_None
-                if not s_value.is_constant():
-                    raise TyperError("non-constant variable of type Void")
-                if not isinstance(s_value, (annmodel.SomePBC, annmodel.SomeNone)):
-                    raise TyperError("non-PBC Void argument: %r", (s_value,))
-                args_s.append(s_value)
-            else:
-                args_s.append(lltype_to_annotation(v.concretetype))
-            newargs_v.append(v)
+        with rtyper.annotator.using_policy(rtyper.lowlevel_ann_policy):
+            for v in args_v:
+                if v.concretetype is Void:
+                    s_value = rtyper.annotation(v)
+                    if s_value is None:
+                        s_value = annmodel.s_None
+                    if not s_value.is_constant():
+                        raise TyperError("non-constant variable of type Void")
+                    if not isinstance(s_value, (annmodel.SomePBC, annmodel.SomeNone)):
+                        raise TyperError("non-PBC Void argument: %r", (s_value,))
+                    args_s.append(s_value)
+                else:
+                    args_s.append(lltype_to_annotation(v.concretetype))
+                newargs_v.append(v)
 
-        self.rtyper.call_all_setups()  # compute ForwardReferences now
+            self.rtyper.call_all_setups()  # compute ForwardReferences now
 
-        # hack for bound methods
-        if hasattr(ll_function, 'im_func'):
-            bk = rtyper.annotator.bookkeeper
-            args_s.insert(0, bk.immutablevalue(ll_function.im_self))
-            newargs_v.insert(0, inputconst(Void, ll_function.im_self))
-            ll_function = ll_function.im_func
+            # hack for bound methods
+            if hasattr(ll_function, 'im_func'):
+                bk = rtyper.annotator.bookkeeper
+                args_s.insert(0, bk.immutablevalue(ll_function.im_self))
+                newargs_v.insert(0, inputconst(Void, ll_function.im_self))
+                ll_function = ll_function.im_func
 
         graph = annotate_lowlevel_helper(rtyper.annotator, ll_function, args_s,
                                          rtyper.lowlevel_ann_policy)


More information about the pypy-commit mailing list