Author: Ronan Lamy <[email protected]>
Branch: py3.5
Changeset: r92372:1f0dbee16f1f
Date: 2017-09-11 17:53 +0100
http://bitbucket.org/pypy/pypy/changeset/1f0dbee16f1f/

Log:    hg merge default (fast PyUnicode_Check disabled for now)

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
@@ -73,3 +73,11 @@
 
 Add support for leakfinder in cpyext tests (disabled for now, due to too many
 failures).
+
+.. branch: pypy_swappedbytes
+
+Added ``_swappedbytes_`` support for ``ctypes.Structure``
+
+.. branch: pycheck-macros
+
+Convert many Py*_Check cpyext functions into macros, like CPython.
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -1537,12 +1537,15 @@
     def text_or_none_w(self, w_obj):
         return None if self.is_none(w_obj) else self.text_w(w_obj)
 
+    @specialize.argtype(1)
     def bytes_w(self, w_obj):
         """ Takes an application level :py:class:`bytes`
             (on PyPy2 this equals `str`) and returns a rpython byte string.
         """
+        assert w_obj is not None
         return w_obj.bytes_w(self)
 
+    @specialize.argtype(1)
     def text_w(self, w_obj):
         """ PyPy2 takes either a :py:class:`str` and returns a
             rpython byte string, or it takes an :py:class:`unicode`
@@ -1552,6 +1555,7 @@
             On PyPy3 it takes a :py:class:`str` and it will return
             an utf-8 encoded rpython string.
         """
+        assert w_obj is not None
         return w_obj.text_w(self)
 
     @not_rpython    # tests only; should be replaced with bytes_w or text_w
@@ -1601,6 +1605,7 @@
             raise oefmt(self.w_ValueError, "byte must be in range(0, 256)")
         return chr(value)
 
+    @specialize.argtype(1)
     def int_w(self, w_obj, allow_conversion=True):
         """
         Unwrap an app-level int object into an interpret-level int.
@@ -1613,29 +1618,40 @@
         If allow_conversion=False, w_obj needs to be an app-level int or a
         subclass.
         """
+        assert w_obj is not None
         return w_obj.int_w(self, allow_conversion)
 
+    @specialize.argtype(1)
     def int(self, w_obj):
+        assert w_obj is not None
         return w_obj.int(self)
 
+    @specialize.argtype(1)
     def uint_w(self, w_obj):
+        assert w_obj is not None
         return w_obj.uint_w(self)
 
+    @specialize.argtype(1)
     def bigint_w(self, w_obj, allow_conversion=True):
         """
         Like int_w, but return a rlib.rbigint object and call __long__ if
         allow_conversion is True.
         """
+        assert w_obj is not None
         return w_obj.bigint_w(self, allow_conversion)
 
+    @specialize.argtype(1)
     def float_w(self, w_obj, allow_conversion=True):
         """
         Like int_w, but return an interp-level float and call __float__ if
         allow_conversion is True.
         """
+        assert w_obj is not None
         return w_obj.float_w(self, allow_conversion)
 
+    @specialize.argtype(1)
     def unicode_w(self, w_obj):
+        assert w_obj is not None
         return w_obj.unicode_w(self)
 
     def unicode0_w(self, w_obj):
@@ -1690,7 +1706,9 @@
         # this, but the general is_true(),  accepting any object.
         return bool(self.int_w(w_obj))
 
+    @specialize.argtype(1)
     def ord(self, w_obj):
+        assert w_obj is not None
         return w_obj.ord(self)
 
     # This is all interface for gateway.py.
diff --git a/pypy/module/_csv/interp_csv.py b/pypy/module/_csv/interp_csv.py
--- a/pypy/module/_csv/interp_csv.py
+++ b/pypy/module/_csv/interp_csv.py
@@ -29,10 +29,15 @@
         return default
     return space.is_true(w_src)
 
-def _get_int(space, w_src, default):
+def _get_int(space, w_src, default, attrname):
     if w_src is None:
         return default
-    return space.int_w(w_src)
+    try:
+        return space.int_w(w_src)
+    except OperationError as e:
+        if e.match(space, space.w_TypeError):
+            raise oefmt(space.w_TypeError, '"%s" must be a string', attrname)
+        raise
 
 def _get_str(space, w_src, default, attrname):
     if w_src is None:
@@ -100,7 +105,7 @@
     dialect.escapechar = _get_char(space, w_escapechar, u'\0', 'escapechar')
     dialect.lineterminator = _get_str(space, w_lineterminator, u'\r\n', 
'lineterminator')
     dialect.quotechar = _get_char(space, w_quotechar, u'"', 'quotechar')
-    tmp_quoting = _get_int(space, w_quoting, QUOTE_MINIMAL)
+    tmp_quoting = _get_int(space, w_quoting, QUOTE_MINIMAL, 'quoting')
     dialect.skipinitialspace = _get_bool(space, w_skipinitialspace, False)
     dialect.strict = _get_bool(space, w_strict, False)
 
diff --git a/pypy/module/_csv/test/test_dialect.py 
b/pypy/module/_csv/test/test_dialect.py
--- a/pypy/module/_csv/test/test_dialect.py
+++ b/pypy/module/_csv/test/test_dialect.py
@@ -65,7 +65,8 @@
             name = attempt[0]
             for value in attempt[1:]:
                 kwargs = {name: value}
-                raises(TypeError, _csv.register_dialect, 'foo1', **kwargs)
+                exc_info = raises(TypeError, _csv.register_dialect, 'foo1', 
**kwargs)
+                assert name in exc_info.value.args[0]
 
         exc_info = raises(TypeError, _csv.register_dialect, 'foo1', 
lineterminator=4)
         assert exc_info.value.args[0] == '"lineterminator" must be a string'
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
@@ -40,6 +40,7 @@
 from rpython.rlib import rawrefcount
 from rpython.rlib import rthread
 from rpython.rlib.debug import fatalerror_notb
+from rpython.rlib import rstackovf
 from pypy.objspace.std.typeobject import W_TypeObject, find_best_base
 from pypy.module.cpyext.cparser import CTypeSpace
 
@@ -129,6 +130,11 @@
 Py_CLEANUP_SUPPORTED
 PyBUF_FORMAT PyBUF_ND PyBUF_STRIDES PyBUF_WRITABLE PyBUF_SIMPLE PyBUF_WRITE
 """.split()
+
+for name in ('LONG', 'LIST', 'TUPLE', 'UNICODE', 'DICT', 'BASE_EXC',
+             'TYPE', 'BYTES'):
+    constant_names.append('Py_TPFLAGS_%s_SUBCLASS' % name)
+
 for name in constant_names:
     setattr(CConfig_constants, name, rffi_platform.ConstantInteger(name))
 globals().update(rffi_platform.configure(CConfig_constants))
@@ -765,6 +771,45 @@
 
     return check, check_exact
 
+def build_type_checkers_flags(type_name, cls=None, flagsubstr=None):
+    """
+    Builds two api functions: Py_XxxCheck() and Py_XxxCheckExact()
+    Does not export the functions, assumes they are macros in the *. files
+    check will try a fast path via pto flags
+    """
+    if cls is None:
+        attrname = "w_" + type_name.lower()
+        def get_w_type(space):
+            return getattr(space, attrname)
+    else:
+        def get_w_type(space):
+            return getattr(space, cls)
+    if flagsubstr is None:
+       tp_flag_str = 'Py_TPFLAGS_%s_SUBCLASS' % type_name.upper()
+    else:
+       tp_flag_str = 'Py_TPFLAGS_%s_SUBCLASS' % flagsubstr
+    check_name = "Py" + type_name + "_Check"
+    tp_flag = globals()[tp_flag_str]
+
+    @specialize.argtype(1)
+    def check(space, pto):
+        from pypy.module.cpyext.pyobject import is_pyobj, as_pyobj
+        "Implements the Py_Xxx_Check function"
+        if is_pyobj(pto):
+            return (pto.c_ob_type.c_tp_flags & tp_flag) == tp_flag
+        w_obj_type = space.type(pto)
+        w_type = get_w_type(space)
+        return (space.is_w(w_obj_type, w_type) or
+                space.issubtype_w(w_obj_type, w_type))
+
+    def check_exact(space, w_obj):
+        "Implements the Py_Xxx_CheckExact function"
+        w_obj_type = space.type(w_obj)
+        w_type = get_w_type(space)
+        return space.is_w(w_obj_type, w_type)
+
+    return check, check_exact
+
 pypy_debug_catch_fatal_exception = 
rffi.llexternal('pypy_debug_catch_fatal_exception', [], lltype.Void)
 
 
@@ -957,6 +1002,11 @@
                     message = str(e)
                 state.set_exception(OperationError(space.w_SystemError,
                                                    space.newtext(message)))
+            except rstackovf.StackOverflow as e:
+                rstackovf.check_stack_overflow()
+                failed = True
+                state.set_exception(OperationError(space.w_RuntimeError,
+                         space.newtext("maximum recursion depth exceeded")))
             else:
                 failed = False
 
@@ -1240,7 +1290,8 @@
 #  error "PyPy does not support 64-bit on Windows.  Use Win32"
 #endif
 ''',
-        '#define Signed   long           /* xxx temporary fix */',
+        '#include "cpyext_object.h"',
+        '#define Signed   Py_ssize_t     /* xxx temporary fix */',
         '#define Unsigned unsigned long  /* xxx temporary fix */',
         '',] + decls + [
         '',
diff --git a/pypy/module/cpyext/bytesobject.py 
b/pypy/module/cpyext/bytesobject.py
--- a/pypy/module/cpyext/bytesobject.py
+++ b/pypy/module/cpyext/bytesobject.py
@@ -1,7 +1,7 @@
 from pypy.interpreter.error import oefmt
 from rpython.rtyper.lltypesystem import rffi, lltype
 from pypy.module.cpyext.api import (
-    cpython_api, cpython_struct, bootstrap_function, build_type_checkers,
+    cpython_api, cpython_struct, bootstrap_function, build_type_checkers_flags,
     PyVarObjectFields, Py_ssize_t, CONST_STRING, CANNOT_FAIL, slot_function)
 from pypy.module.cpyext.pyerrors import PyErr_BadArgument
 from pypy.module.cpyext.pyobject import (
@@ -58,7 +58,7 @@
                    dealloc=bytes_dealloc,
                    realize=bytes_realize)
 
-PyBytes_Check, PyBytes_CheckExact = build_type_checkers("Bytes", "w_bytes")
+PyBytes_Check, PyBytes_CheckExact = build_type_checkers_flags("Bytes", 
"w_bytes")
 
 def new_empty_str(space, length):
     """
diff --git a/pypy/module/cpyext/dictobject.py b/pypy/module/cpyext/dictobject.py
--- a/pypy/module/cpyext/dictobject.py
+++ b/pypy/module/cpyext/dictobject.py
@@ -4,7 +4,7 @@
 from pypy.objspace.std.classdict import ClassDictStrategy
 from pypy.interpreter.typedef import GetSetProperty
 from pypy.module.cpyext.api import (
-    cpython_api, CANNOT_FAIL, build_type_checkers, Py_ssize_t,
+    cpython_api, CANNOT_FAIL, build_type_checkers_flags, Py_ssize_t,
     Py_ssize_tP, CONST_STRING, PyObjectFields, cpython_struct,
     bootstrap_function, slot_function)
 from pypy.module.cpyext.pyobject import (PyObject, PyObjectP, as_pyobj, 
@@ -66,7 +66,7 @@
 def PyDict_New(space):
     return space.newdict()
 
-PyDict_Check, PyDict_CheckExact = build_type_checkers("Dict")
+PyDict_Check, PyDict_CheckExact = build_type_checkers_flags("Dict")
 
 @cpython_api([PyObject, PyObject], PyObject, error=CANNOT_FAIL,
              result_borrowed=True)
diff --git a/pypy/module/cpyext/include/bytesobject.h 
b/pypy/module/cpyext/include/bytesobject.h
--- a/pypy/module/cpyext/include/bytesobject.h
+++ b/pypy/module/cpyext/include/bytesobject.h
@@ -55,6 +55,9 @@
 #define SSTATE_INTERNED_IMMORTAL 2
 #define PyString_CHECK_INTERNED(op) (((PyStringObject *)(op))->ob_sstate)
 
+#define PyBytes_Check(op) \
+                 PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_BYTES_SUBCLASS)
+#define PyBytes_CheckExact(op) (Py_TYPE(op) == &PyBytes_Type)
 
 PyAPI_FUNC(PyObject *) PyBytes_FromFormatV(const char*, va_list);
 PyAPI_FUNC(PyObject *) PyBytes_FromFormat(const char*, ...);
diff --git a/pypy/module/cpyext/include/dictobject.h 
b/pypy/module/cpyext/include/dictobject.h
--- a/pypy/module/cpyext/include/dictobject.h
+++ b/pypy/module/cpyext/include/dictobject.h
@@ -12,6 +12,10 @@
     PyObject *_tmpkeys; /* a private place to put keys during PyDict_Next */
 } PyDictObject;
 
+#define PyDict_Check(op) \
+                PyType_FastSubclass((op)->ob_type, Py_TPFLAGS_DICT_SUBCLASS)
+#define PyDict_CheckExact(op) ((op)->ob_type == &PyDict_Type)
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/pypy/module/cpyext/include/listobject.h 
b/pypy/module/cpyext/include/listobject.h
--- a/pypy/module/cpyext/include/listobject.h
+++ b/pypy/module/cpyext/include/listobject.h
@@ -1,1 +1,4 @@
 /* empty */
+#define PyList_Check(op) \
+                PyType_FastSubclass((op)->ob_type, Py_TPFLAGS_LIST_SUBCLASS)
+#define PyList_CheckExact(op) ((op)->ob_type == &PyList_Type)
diff --git a/pypy/module/cpyext/include/longobject.h 
b/pypy/module/cpyext/include/longobject.h
--- a/pypy/module/cpyext/include/longobject.h
+++ b/pypy/module/cpyext/include/longobject.h
@@ -14,6 +14,9 @@
 
 #define PyOS_strtoul strtoul
 #define PyOS_strtol strtoul
+#define PyLong_Check(op) \
+                PyType_FastSubclass((op)->ob_type, Py_TPFLAGS_LONG_SUBCLASS)
+#define PyLong_CheckExact(op) ((op)->ob_type == &PyLong_Type)
 
 #define PyLong_AS_LONG(op) PyLong_AsLong(op)
 
diff --git a/pypy/module/cpyext/include/object.h 
b/pypy/module/cpyext/include/object.h
--- a/pypy/module/cpyext/include/object.h
+++ b/pypy/module/cpyext/include/object.h
@@ -227,6 +227,10 @@
 #endif
 #define PyType_FastSubclass(t,f)  PyType_HasFeature(t,f)
 
+#define PyType_Check(op) \
+    PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_TYPE_SUBCLASS)
+#define PyType_CheckExact(op) (Py_TYPE(op) == &PyType_Type)
+
 /* objimpl.h ----------------------------------------------*/
 #define PyObject_New(type, typeobj) \
                ( (type *) _PyObject_New(typeobj) )
diff --git a/pypy/module/cpyext/include/pyerrors.h 
b/pypy/module/cpyext/include/pyerrors.h
--- a/pypy/module/cpyext/include/pyerrors.h
+++ b/pypy/module/cpyext/include/pyerrors.h
@@ -9,7 +9,7 @@
 
 #define PyExceptionClass_Check(x)                                       \
     ((PyType_Check((x)) &&                                              \
-      PyObject_IsSubclass((x), PyExc_BaseException)))
+      PyType_FastSubclass((PyTypeObject*)(x), Py_TPFLAGS_BASE_EXC_SUBCLASS)))
 
 #define PyExceptionInstance_Check(x)                                    \
     (PyObject_IsSubclass((PyObject *)Py_TYPE(x), PyExc_BaseException))
diff --git a/pypy/module/cpyext/include/tupleobject.h 
b/pypy/module/cpyext/include/tupleobject.h
--- a/pypy/module/cpyext/include/tupleobject.h
+++ b/pypy/module/cpyext/include/tupleobject.h
@@ -26,6 +26,9 @@
 /* Macro, *only* to be used to fill in brand new tuples */
 #define PyTuple_SET_ITEM(op, i, v) (((PyTupleObject *)(op))->ob_item[i] = v)
 
+#define PyTuple_Check(op) \
+                PyType_FastSubclass((op)->ob_type, Py_TPFLAGS_TUPLE_SUBCLASS)
+#define PyTuple_CheckExact(op) ((op)->ob_type == &PyTuple_Type)
 
 #ifdef __cplusplus
 }
diff --git a/pypy/module/cpyext/include/unicodeobject.h 
b/pypy/module/cpyext/include/unicodeobject.h
--- a/pypy/module/cpyext/include/unicodeobject.h
+++ b/pypy/module/cpyext/include/unicodeobject.h
@@ -7,6 +7,11 @@
 
 #include "cpyext_unicodeobject.h"
 
+/*#define PyUnicode_Check(op) \
+**              PyType_FastSubclass((op)->ob_type, Py_TPFLAGS_UNICODE_SUBCLASS)
+**#define PyUnicode_CheckExact(op) ((op)->ob_type == &PyUnicode_Type)
+*/
+
 /* Fast access macros */
 #ifndef Py_LIMITED_API
 
diff --git a/pypy/module/cpyext/listobject.py b/pypy/module/cpyext/listobject.py
--- a/pypy/module/cpyext/listobject.py
+++ b/pypy/module/cpyext/listobject.py
@@ -2,14 +2,14 @@
 from rpython.rlib.objectmodel import always_inline
 from rpython.rtyper.lltypesystem import rffi, lltype
 from pypy.module.cpyext.api import (cpython_api, CANNOT_FAIL, Py_ssize_t,
-                                    build_type_checkers)
+                                    build_type_checkers_flags)
 from pypy.module.cpyext.pyerrors import PyErr_BadInternalCall
 from pypy.module.cpyext.pyobject import decref, incref, PyObject, make_ref
 from pypy.objspace.std.listobject import W_ListObject
 from pypy.interpreter.error import oefmt
 
 
-PyList_Check, PyList_CheckExact = build_type_checkers("List")
+PyList_Check, PyList_CheckExact = build_type_checkers_flags("List")
 
 @cpython_api([Py_ssize_t], PyObject)
 def PyList_New(space, len):
diff --git a/pypy/module/cpyext/longobject.py b/pypy/module/cpyext/longobject.py
--- a/pypy/module/cpyext/longobject.py
+++ b/pypy/module/cpyext/longobject.py
@@ -1,13 +1,13 @@
 from rpython.rtyper.lltypesystem import lltype, rffi
 from pypy.module.cpyext.api import (
-    cpython_api, PyObject, build_type_checkers, Py_ssize_t,
+    cpython_api, PyObject, build_type_checkers_flags, Py_ssize_t,
     CONST_STRING, ADDR, CANNOT_FAIL)
 from pypy.objspace.std.longobject import W_LongObject
 from pypy.interpreter.error import OperationError
 from rpython.rlib.rbigint import rbigint
 
 
-PyLong_Check, PyLong_CheckExact = build_type_checkers("Long", "w_int")
+PyLong_Check, PyLong_CheckExact = build_type_checkers_flags("Long", "w_int")
 
 @cpython_api([lltype.Signed], PyObject)
 def PyLong_FromLong(space, val):
diff --git a/pypy/module/cpyext/methodobject.py 
b/pypy/module/cpyext/methodobject.py
--- a/pypy/module/cpyext/methodobject.py
+++ b/pypy/module/cpyext/methodobject.py
@@ -10,7 +10,7 @@
 from pypy.module.cpyext.api import (
     CONST_STRING, METH_CLASS, METH_COEXIST, METH_KEYWORDS, METH_NOARGS, METH_O,
     METH_STATIC, METH_VARARGS, PyObject, bootstrap_function,
-    build_type_checkers, cpython_api, generic_cpy_call, CANNOT_FAIL,
+    cpython_api, generic_cpy_call, CANNOT_FAIL,
     PyTypeObjectPtr, slot_function, cts)
 from pypy.module.cpyext.pyobject import (
     Py_DecRef, from_ref, make_ref, as_pyobj, make_typedescr)
diff --git a/pypy/module/cpyext/parse/cpyext_object.h 
b/pypy/module/cpyext/parse/cpyext_object.h
--- a/pypy/module/cpyext/parse/cpyext_object.h
+++ b/pypy/module/cpyext/parse/cpyext_object.h
@@ -1,3 +1,4 @@
+#pragma once
 
 typedef long Py_ssize_t;
 
diff --git a/pypy/module/cpyext/pytraceback.py 
b/pypy/module/cpyext/pytraceback.py
--- a/pypy/module/cpyext/pytraceback.py
+++ b/pypy/module/cpyext/pytraceback.py
@@ -1,7 +1,7 @@
 from rpython.rtyper.lltypesystem import rffi, lltype
 from pypy.module.cpyext.api import (
     PyObjectFields, generic_cpy_call, CONST_STRING, CANNOT_FAIL, Py_ssize_t,
-    cpython_api, bootstrap_function, cpython_struct, build_type_checkers,
+    cpython_api, bootstrap_function, cpython_struct, 
     slot_function)
 from pypy.module.cpyext.pyobject import (
     PyObject, make_ref, from_ref, Py_DecRef, make_typedescr)
diff --git a/pypy/module/cpyext/test/test_memoryobject.py 
b/pypy/module/cpyext/test/test_memoryobject.py
--- a/pypy/module/cpyext/test/test_memoryobject.py
+++ b/pypy/module/cpyext/test/test_memoryobject.py
@@ -147,53 +147,6 @@
         ten = foo.test_buffer(arr)
         assert ten == 10
 
-    @pytest.mark.skipif(True, reason="no _numpypy on py3k")
-    #@pytest.mark.skipif(only_pypy, reason='pypy only test')
-    def test_buffer_info(self):
-        try:
-            from _numpypy import multiarray as np
-        except ImportError:
-            skip('pypy built without _numpypy')
-        module = self.import_module(name='buffer_test')
-        get_buffer_info = module.get_buffer_info
-        raises(ValueError, get_buffer_info, np.arange(5)[::2], ('SIMPLE',))
-        arr = np.zeros((1, 10), order='F')
-        shape, strides = get_buffer_info(arr, ['F_CONTIGUOUS'])
-        assert strides[0] == 8
-        arr = np.zeros((10, 1), order='C')
-        shape, strides = get_buffer_info(arr, ['C_CONTIGUOUS'])
-        assert strides[-1] == 8
-        dt1 = np.dtype(
-             [('a', 'b'), ('b', 'i'),
-              ('sub0', np.dtype('b,i')),
-              ('sub1', np.dtype('b,i')),
-              ('sub2', np.dtype('b,i')),
-              ('sub3', np.dtype('b,i')),
-              ('sub4', np.dtype('b,i')),
-              ('sub5', np.dtype('b,i')),
-              ('sub6', np.dtype('b,i')),
-              ('sub7', np.dtype('b,i')),
-              ('c', 'i')],
-             )
-        x = np.arange(dt1.itemsize, dtype='int8').view(dt1)
-        # pytest can catch warnings from v2.8 and up, we ship 2.5
-        import warnings
-        warnings.filterwarnings("error")
-        try:
-            try:
-                y = get_buffer_info(x, ['SIMPLE'])
-            except UserWarning as e:
-                pass
-            else:
-                assert False ,"PyPy-specific UserWarning not raised" \
-                          " on too long format string"
-        finally:
-            warnings.resetwarnings()
-        # calling get_buffer_info on x creates a memory leak,
-        # which is detected as an error at test teardown:
-        # Exception TypeError: "'NoneType' object is not callable"
-        #         in <bound method ConcreteArray.__del__ ...> ignored
-
     def test_releasebuffer(self):
         module = self.import_extension('foo', [
             ("create_test", "METH_NOARGS",
diff --git a/pypy/module/cpyext/test/test_ndarrayobject.py 
b/pypy/module/cpyext/test/test_ndarrayobject.py
--- a/pypy/module/cpyext/test/test_ndarrayobject.py
+++ b/pypy/module/cpyext/test/test_ndarrayobject.py
@@ -28,6 +28,8 @@
 NULL = lltype.nullptr(rffi.VOIDP.TO)
 
 class TestNDArrayObject(BaseApiTest):
+    spaceconfig = AppTestCpythonExtensionBase.spaceconfig.copy()
+    spaceconfig['usemodules'].append('micronumpy')
 
     def test_Check(self, space, api):
         a = array(space, [10, 5, 3])
diff --git a/pypy/module/cpyext/test/test_typeobject.py 
b/pypy/module/cpyext/test/test_typeobject.py
--- a/pypy/module/cpyext/test/test_typeobject.py
+++ b/pypy/module/cpyext/test/test_typeobject.py
@@ -1049,7 +1049,7 @@
 
     def test_call_tp_dealloc(self):
         module = self.import_extension('foo', [
-            ("fetchFooType", "METH_VARARGS",
+            ("fetchFooType", "METH_NOARGS",
              """
                 PyObject *o;
                 o = PyObject_New(PyObject, &Foo_Type);
@@ -1067,7 +1067,7 @@
                 Py_DECREF(e);
                 return o;
              """),
-            ("getCounter", "METH_VARARGS",
+            ("getCounter", "METH_NOARGS",
              """
                 return PyLong_FromLong(foo_counter);
              """)], prologue="""
@@ -1334,3 +1334,50 @@
         # this is equivalent to
         from collections import Hashable
         assert not isinstance(obj, Hashable)
+
+
+class AppTestFlags(AppTestCpythonExtensionBase):
+    def test_has_subclass_flag(self):
+        module = self.import_extension('foo', [
+           ("test_flags", "METH_VARARGS",
+            '''
+                long in_flag, my_flag;
+                PyObject * obj;
+                if (!PyArg_ParseTuple(args, "Ol", &obj, &in_flag))
+                    return NULL;
+                if (!PyType_Check(obj))
+                {
+                    PyErr_SetString(PyExc_ValueError, "input must be type");
+                    return NULL;
+                }
+                my_flag = ((PyTypeObject*)obj)->tp_flags;
+                if ((my_flag & in_flag) != in_flag)
+                    return PyLong_FromLong(-1);
+                if (!PyType_CheckExact(obj)) {
+                    if ((my_flag & Py_TPFLAGS_TYPE_SUBCLASS) == 
Py_TPFLAGS_TYPE_SUBCLASS)
+                        return PyLong_FromLong(-2);
+                }
+                return PyLong_FromLong(0);
+            '''),])
+        # copied from object.h
+        Py_TPFLAGS_LONG_SUBCLASS = (1<<24)
+        Py_TPFLAGS_LIST_SUBCLASS = (1<<25)
+        Py_TPFLAGS_TUPLE_SUBCLASS = (1<<26)
+        Py_TPFLAGS_BYTES_SUBCLASS = (1<<27)
+        Py_TPFLAGS_UNICODE_SUBCLASS = (1<<28)
+        Py_TPFLAGS_DICT_SUBCLASS = (1<<29)
+        Py_TPFLAGS_BASE_EXC_SUBCLASS = (1<<30)
+        Py_TPFLAGS_TYPE_SUBCLASS = (1<<31)
+        for t,f in ((int, Py_TPFLAGS_LONG_SUBCLASS),
+                    (list, Py_TPFLAGS_LIST_SUBCLASS),
+                    (tuple, Py_TPFLAGS_TUPLE_SUBCLASS),
+                    (bytes, Py_TPFLAGS_BYTES_SUBCLASS),
+                    (str, Py_TPFLAGS_UNICODE_SUBCLASS),
+                    (dict, Py_TPFLAGS_DICT_SUBCLASS),
+                    (Exception, Py_TPFLAGS_BASE_EXC_SUBCLASS),
+                    (type, Py_TPFLAGS_TYPE_SUBCLASS),
+                   ):
+            assert module.test_flags(t, f) == 0
+        class MyList(list):
+            pass
+        assert module.test_flags(MyList, Py_TPFLAGS_LIST_SUBCLASS) == 0
diff --git a/pypy/module/cpyext/tupleobject.py 
b/pypy/module/cpyext/tupleobject.py
--- a/pypy/module/cpyext/tupleobject.py
+++ b/pypy/module/cpyext/tupleobject.py
@@ -2,7 +2,7 @@
 from rpython.rtyper.lltypesystem import rffi, lltype
 from rpython.rlib.debug import fatalerror_notb
 from pypy.module.cpyext.api import (
-    cpython_api, Py_ssize_t, build_type_checkers,
+    cpython_api, Py_ssize_t, build_type_checkers_flags,
     PyVarObjectFields, cpython_struct, bootstrap_function, slot_function)
 from pypy.module.cpyext.pyobject import (
     PyObject, PyObjectP, make_ref, from_ref, decref, incref,
@@ -42,7 +42,7 @@
                    dealloc=tuple_dealloc,
                    realize=tuple_realize)
 
-PyTuple_Check, PyTuple_CheckExact = build_type_checkers("Tuple")
+PyTuple_Check, PyTuple_CheckExact = build_type_checkers_flags("Tuple")
 
 def tuple_check_ref(space, ref):
     w_type = from_ref(space, rffi.cast(PyObject, ref.c_ob_type))
diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py
--- a/pypy/module/cpyext/typeobject.py
+++ b/pypy/module/cpyext/typeobject.py
@@ -1,23 +1,25 @@
-import os
-
 from rpython.rlib.unroll import unrolling_iterable
 from rpython.rlib import jit
 from rpython.rlib.objectmodel import specialize, we_are_translated
 from rpython.rtyper.lltypesystem import rffi, lltype
 
-from pypy.interpreter.baseobjspace import W_Root, DescrMismatch
+from pypy.interpreter.baseobjspace import DescrMismatch
 from pypy.interpreter.error import oefmt
-from pypy.interpreter.typedef import (GetSetProperty, TypeDef,
-        interp_attrproperty, interp2app)
+from pypy.interpreter.typedef import (
+    GetSetProperty, TypeDef, interp_attrproperty, interp2app)
 from pypy.module.__builtin__.abstractinst import abstract_issubclass_w
 from pypy.module.cpyext import structmemberdefs
 from pypy.module.cpyext.api import (
-    cpython_api, cpython_struct, bootstrap_function, Py_ssize_t, Py_ssize_tP,
-    slot_function, generic_cpy_call, Py_TPFLAGS_READY, Py_TPFLAGS_READYING, 
Py_buffer,
-    Py_TPFLAGS_HEAPTYPE, METH_VARARGS, METH_KEYWORDS, CANNOT_FAIL,
-    build_type_checkers, Py_TPFLAGS_BASETYPE,
-    PyObjectFields, PyTypeObject, PyTypeObjectPtr,
-    cts, parse_dir)
+    cpython_api, cpython_struct, bootstrap_function, Py_ssize_t,
+    slot_function, generic_cpy_call, METH_VARARGS, METH_KEYWORDS, CANNOT_FAIL,
+    build_type_checkers_flags, cts, parse_dir, PyObjectFields, PyTypeObject,
+    PyTypeObjectPtr, Py_buffer,
+    Py_TPFLAGS_HEAPTYPE, Py_TPFLAGS_READY, Py_TPFLAGS_READYING,
+    Py_TPFLAGS_LONG_SUBCLASS, Py_TPFLAGS_LIST_SUBCLASS,
+    Py_TPFLAGS_TUPLE_SUBCLASS, Py_TPFLAGS_UNICODE_SUBCLASS,
+    Py_TPFLAGS_DICT_SUBCLASS, Py_TPFLAGS_BASE_EXC_SUBCLASS,
+    Py_TPFLAGS_TYPE_SUBCLASS,
+    Py_TPFLAGS_BYTES_SUBCLASS)
 from pypy.module.cpyext.cparser import CTypeSpace
 from pypy.module.cpyext.methodobject import (W_PyCClassMethodObject,
     W_PyCWrapperObject, PyCFunction_NewEx, PyCFunction, PyMethodDef,
@@ -32,14 +34,14 @@
 from pypy.module.cpyext.state import State
 from pypy.module.cpyext.structmember import PyMember_GetOne, PyMember_SetOne
 from pypy.module.cpyext.typeobjectdefs import (
-    PyGetSetDef, PyMemberDef, PyMappingMethods, getter, setter,
+    PyGetSetDef, PyMemberDef, PyMappingMethods,
     PyNumberMethods, PySequenceMethods, PyBufferProcs)
 from pypy.objspace.std.typeobject import W_TypeObject, find_best_base
 
 
 #WARN_ABOUT_MISSING_SLOT_FUNCTIONS = False
 
-PyType_Check, PyType_CheckExact = build_type_checkers("Type", "w_type")
+PyType_Check, PyType_CheckExact = build_type_checkers_flags("Type")
 
 PyHeapTypeObject = cts.gettype('PyHeapTypeObject *')
 
@@ -431,7 +433,7 @@
     dict_w["__new__"] = PyCFunction_NewEx(space, get_new_method_def(space),
                                           from_ref(space, pyo), None)
 
-def inherit_special(space, pto, base_pto):
+def inherit_special(space, pto, w_obj, base_pto):
     # XXX missing: copy basicsize and flags in a magical way
     # (minimally, if tp_basicsize is zero or too low, we copy it from the base)
     if pto.c_tp_basicsize < base_pto.c_tp_basicsize:
@@ -439,6 +441,24 @@
     if pto.c_tp_itemsize < base_pto.c_tp_itemsize:
         pto.c_tp_itemsize = base_pto.c_tp_itemsize
 
+    #/* Setup fast subclass flags */
+    if space.issubtype_w(w_obj, space.w_BaseException):
+        pto.c_tp_flags |= Py_TPFLAGS_BASE_EXC_SUBCLASS
+    elif space.issubtype_w(w_obj, space.w_type):
+        pto.c_tp_flags |= Py_TPFLAGS_TYPE_SUBCLASS
+    elif space.issubtype_w(w_obj, space.w_int):
+        pto.c_tp_flags |= Py_TPFLAGS_LONG_SUBCLASS
+    elif space.issubtype_w(w_obj, space.w_bytes):
+        pto.c_tp_flags |= Py_TPFLAGS_BYTES_SUBCLASS
+    elif space.issubtype_w(w_obj, space.w_unicode):
+        pto.c_tp_flags |= Py_TPFLAGS_UNICODE_SUBCLASS
+    elif space.issubtype_w(w_obj, space.w_tuple):
+        pto.c_tp_flags |= Py_TPFLAGS_TUPLE_SUBCLASS
+    elif space.issubtype_w(w_obj, space.w_list):
+        pto.c_tp_flags |= Py_TPFLAGS_LIST_SUBCLASS
+    elif space.issubtype_w(w_obj, space.w_dict):
+        pto.c_tp_flags |= Py_TPFLAGS_DICT_SUBCLASS
+
 def check_descr(space, w_self, w_type):
     if not space.isinstance_w(w_self, w_type):
         raise DescrMismatch()
@@ -845,7 +865,7 @@
     pto.c_tp_mro = make_ref(space, space.newtuple(w_obj.mro_w))
     base = pto.c_tp_base
     if base:
-        inherit_special(space, pto, base)
+        inherit_special(space, pto, w_obj, base)
     for w_base in space.fixedview(from_ref(space, pto.c_tp_bases)):
         if isinstance(w_base, W_TypeObject):
             inherit_slots(space, pto, w_base)
diff --git a/pypy/module/cpyext/unicodeobject.py 
b/pypy/module/cpyext/unicodeobject.py
--- a/pypy/module/cpyext/unicodeobject.py
+++ b/pypy/module/cpyext/unicodeobject.py
@@ -38,7 +38,7 @@
 default_encoding = lltype.malloc(rffi.CCHARP.TO, DEFAULT_ENCODING_SIZE,
                                  flavor='raw', zero=True)
 
-PyUnicode_Check, PyUnicode_CheckExact = build_type_checkers("Unicode", 
"w_unicode")
+PyUnicode_Check, PyUnicode_CheckExact = build_type_checkers("Unicode")
 
 MAX_UNICODE = 1114111
 WCHAR_KIND = 0
diff --git a/pypy/module/itertools/test/test_itertools.py 
b/pypy/module/itertools/test/test_itertools.py
--- a/pypy/module/itertools/test/test_itertools.py
+++ b/pypy/module/itertools/test/test_itertools.py
@@ -2,7 +2,7 @@
 import pytest
 
 
-class AppTestItertools:
+class AppTestItertools(object):
     spaceconfig = dict(usemodules=['itertools'])
 
     def test_count(self):
@@ -646,7 +646,7 @@
         assert itertools.tee(a, 0) == ()
 
 
-class AppTestItertools26:
+class AppTestItertools26(object):
     spaceconfig = dict(usemodules=['itertools'])
 
     def test_count_overflow(self):
@@ -908,10 +908,8 @@
         raises(ValueError, permutations, [1, 2], -1)
 
 
-class AppTestItertools27:
-    spaceconfig = {
-        "usemodules": ['itertools', 'struct', 'binascii'],
-    }
+class AppTestItertools27(object):
+    spaceconfig = {"usemodules": ['itertools', 'struct', 'binascii']}
 
     def test_compress(self):
         import itertools
diff --git a/pypy/module/pyexpat/__init__.py b/pypy/module/pyexpat/__init__.py
--- a/pypy/module/pyexpat/__init__.py
+++ b/pypy/module/pyexpat/__init__.py
@@ -65,6 +65,14 @@
                  'XML_PARAM_ENTITY_PARSING_ALWAYS']:
         interpleveldefs[name] = 'space.newint(interp_pyexpat.%s)' % (name,)
 
+    def __init__(self, space, w_name):
+        "NOT_RPYTHON"
+        from pypy.module.pyexpat import interp_pyexpat
+        super(Module, self).__init__(space, w_name)
+        ver = space.unwrap(interp_pyexpat.get_expat_version(space))
+        assert len(ver) >= 5, (
+            "Cannot compile with the wide (UTF-16) version of Expat")
+
     def startup(self, space):
         from pypy.module.pyexpat import interp_pyexpat
         w_ver = interp_pyexpat.get_expat_version(space)
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
@@ -120,18 +120,6 @@
         locals()[name] = rffi_platform.ConstantInteger(name)
     for name in xml_model_list:
         locals()[name] = rffi_platform.ConstantInteger(name)
-    for name in xml_model_list:
-        locals()[name] = rffi_platform.ConstantInteger(name)
-    for name in xml_model_list:
-        locals()[name] = rffi_platform.ConstantInteger(name)
-    for name in xml_model_list:
-        locals()[name] = rffi_platform.ConstantInteger(name)
-    for name in xml_model_list:
-        locals()[name] = rffi_platform.ConstantInteger(name)
-    for name in xml_model_list:
-        locals()[name] = rffi_platform.ConstantInteger(name)
-    for name in xml_model_list:
-        locals()[name] = rffi_platform.ConstantInteger(name)
     XML_Parser_SIZE = rffi_platform.SizeOf("XML_Parser")
 
 for k, v in rffi_platform.configure(CConfigure).items():
diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py
--- a/pypy/objspace/std/listobject.py
+++ b/pypy/objspace/std/listobject.py
@@ -115,10 +115,10 @@
     if check_int_or_float:
         for w_obj in list_w:
             if type(w_obj) is W_IntObject:
-                if longlong2float.can_encode_int32(space.int_w(w_obj)):
+                if longlong2float.can_encode_int32(w_obj.int_w(space)):
                     continue    # ok
             elif type(w_obj) is W_FloatObject:
-                if longlong2float.can_encode_float(space.float_w(w_obj)):
+                if longlong2float.can_encode_float(w_obj.float_w(space)):
                     continue    # ok
             break
         else:
diff --git a/pypy/objspace/std/specialisedtupleobject.py 
b/pypy/objspace/std/specialisedtupleobject.py
--- a/pypy/objspace/std/specialisedtupleobject.py
+++ b/pypy/objspace/std/specialisedtupleobject.py
@@ -31,23 +31,23 @@
     class cls(W_AbstractTupleObject):
         _immutable_fields_ = ['value%s' % i for i in iter_n]
 
-        def __init__(self, space, *values_w):
+        def __init__(self, space, *values):
             self.space = space
-            assert len(values_w) == typelen
+            assert len(values) == typelen
             for i in iter_n:
-                w_obj = values_w[i]
+                obj = values[i]
                 val_type = typetuple[i]
                 if val_type == int:
-                    unwrapped = w_obj.int_w(space)
+                    assert isinstance(obj, int)
                 elif val_type == float:
-                    unwrapped = w_obj.float_w(space)
+                    assert isinstance(obj, float)
                 elif val_type == str:
-                    unwrapped = w_obj.str_w(space)
+                    assert isinstance(obj, str)
                 elif val_type == object:
-                    unwrapped = w_obj
+                    pass
                 else:
                     raise AssertionError
-                setattr(self, 'value%s' % i, unwrapped)
+                setattr(self, 'value%s' % i, obj)
 
         def length(self):
             return typelen
@@ -155,10 +155,10 @@
         w_arg1, w_arg2 = list_w
         if type(w_arg1) is W_IntObject:
             if type(w_arg2) is W_IntObject:
-                return Cls_ii(space, w_arg1, w_arg2)
+                return Cls_ii(space, space.int_w(w_arg1), space.int_w(w_arg2))
         elif type(w_arg1) is W_FloatObject:
             if type(w_arg2) is W_FloatObject:
-                return Cls_ff(space, w_arg1, w_arg2)
+                return Cls_ff(space, space.float_w(w_arg1), 
space.float_w(w_arg2))
         return Cls_oo(space, w_arg1, w_arg2)
     else:
         raise NotSpecialised
@@ -175,10 +175,9 @@
 # faster to move the decision out of the loop.
 
 @specialize.arg(1)
-def _build_zipped_spec(space, Cls, lst1, lst2, wrap1, wrap2):
+def _build_zipped_spec(space, Cls, lst1, lst2):
     length = min(len(lst1), len(lst2))
-    return [Cls(space, wrap1(lst1[i]),
-                       wrap2(lst2[i])) for i in range(length)]
+    return [Cls(space, lst1[i], lst2[i]) for i in range(length)]
 
 def _build_zipped_spec_oo(space, w_list1, w_list2):
     strat1 = w_list1.strategy
@@ -205,8 +204,7 @@
             intlist2 = w_list2.getitems_int()
             if intlist2 is not None:
                 lst_w = _build_zipped_spec(
-                        space, Cls_ii, intlist1, intlist2,
-                        space.newint, space.newint)
+                        space, Cls_ii, intlist1, intlist2)
                 return space.newlist(lst_w)
         else:
             floatlist1 = w_list1.getitems_float()
@@ -214,8 +212,7 @@
                 floatlist2 = w_list2.getitems_float()
                 if floatlist2 is not None:
                     lst_w = _build_zipped_spec(
-                        space, Cls_ff, floatlist1, floatlist2, space.newfloat,
-                        space.newfloat)
+                        space, Cls_ff, floatlist1, floatlist2)
                     return space.newlist(lst_w)
 
         lst_w = _build_zipped_spec_oo(space, w_list1, w_list2)
diff --git a/rpython/annotator/test/test_annrpython.py 
b/rpython/annotator/test/test_annrpython.py
--- a/rpython/annotator/test/test_annrpython.py
+++ b/rpython/annotator/test/test_annrpython.py
@@ -4644,6 +4644,25 @@
         s_exc = a.binding(graphof(a, f).exceptblock.inputargs[1])
         assert not s_exc.can_be_none()
 
+    def test_specialize_argtype_with_subclasses(self):
+        # checks that specialize:argtype() makes two copies of a
+        # function f(), one for the base class and one for the subclass
+        class A:
+            def foo(self):
+                return 123
+        class B(A):
+            def foo(self):
+                return 456
+        def f(x):
+            return x.foo()
+        f._annspecialcase_ = "specialize:argtype(0)"
+        def h(y):
+            if y > 5:
+                f(A())
+            return f(B())
+        a = self.RPythonAnnotator()
+        assert a.build_types(h, [int]).const == 456
+
 
 def g(n):
     return [0, 1, 2, n]
diff --git a/rpython/jit/backend/llsupport/regalloc.py 
b/rpython/jit/backend/llsupport/regalloc.py
--- a/rpython/jit/backend/llsupport/regalloc.py
+++ b/rpython/jit/backend/llsupport/regalloc.py
@@ -10,6 +10,10 @@
 except ImportError:
     OrderedDict = dict # too bad
 
+SAVE_DEFAULT_REGS = 0
+SAVE_GCREF_REGS = 2
+SAVE_ALL_REGS = 1
+
 class TempVar(AbstractValue):
     def __init__(self):
         pass
@@ -586,7 +590,8 @@
                                                  force_store, save_all_regs)
 
     def spill_or_move_registers_before_call(self, save_sublist,
-                                            force_store=[], save_all_regs=0):
+                                            force_store=[],
+                                            save_all_regs=SAVE_DEFAULT_REGS):
         """Spill or move some registers before a call.
 
         By default, this means: for every register in 'save_sublist',
@@ -602,8 +607,9 @@
         valid, but only *if they are in self.save_around_call_regs,*
         not if they are callee-saved registers!
 
-        'save_all_regs' can be 0 (default set of registers), 1 (do that
-        for all registers), or 2 (default + gc ptrs).
+        'save_all_regs' can be SAVE_DEFAULT_REGS (default set of registers),
+        SAVE_ALL_REGS (do that for all registers), or SAVE_GCREF_REGS (default
+        + gc ptrs).
 
         Overview of what we do (the implementation does it differently,
         for the same result):
@@ -651,11 +657,11 @@
                 new_free_regs.append(reg)
                 continue
 
-            if save_all_regs == 1:
+            if save_all_regs == SAVE_ALL_REGS:
                 # we need to spill all registers in this mode
                 self._bc_spill(v, new_free_regs)
                 #
-            elif save_all_regs == 2 and v.type == REF:
+            elif save_all_regs == SAVE_GCREF_REGS and v.type == REF:
                 # we need to spill all GC ptrs in this mode
                 self._bc_spill(v, new_free_regs)
                 #
diff --git a/rpython/jit/backend/x86/regalloc.py 
b/rpython/jit/backend/x86/regalloc.py
--- a/rpython/jit/backend/x86/regalloc.py
+++ b/rpython/jit/backend/x86/regalloc.py
@@ -2,13 +2,13 @@
 """ Register allocation scheme.
 """
 
-import os, sys
 from rpython.jit.backend.llsupport import symbolic
 from rpython.jit.backend.llsupport.descr import CallDescr, unpack_arraydescr
 from rpython.jit.backend.llsupport.gcmap import allocate_gcmap
 from rpython.jit.backend.llsupport.regalloc import (FrameManager, BaseRegalloc,
      RegisterManager, TempVar, compute_vars_longevity, is_comparison_or_ovf_op,
-     valid_addressing_size, get_scale)
+     valid_addressing_size, get_scale, SAVE_DEFAULT_REGS, SAVE_GCREF_REGS,
+     SAVE_ALL_REGS)
 from rpython.jit.backend.x86 import rx86
 from rpython.jit.backend.x86.arch import (WORD, JITFRAME_FIXED_SIZE, IS_X86_32,
     IS_X86_64, DEFAULT_FRAME_BYTES)
@@ -23,12 +23,11 @@
 from rpython.jit.codewriter.effectinfo import EffectInfo
 from rpython.jit.metainterp.history import (Const, ConstInt, ConstPtr,
     ConstFloat, INT, REF, FLOAT, VECTOR, TargetToken, AbstractFailDescr)
-from rpython.jit.metainterp.resoperation import rop, ResOperation
+from rpython.jit.metainterp.resoperation import rop
 from rpython.jit.metainterp.resume import AccumInfo
 from rpython.rlib import rgc
 from rpython.rlib.objectmodel import we_are_translated
 from rpython.rlib.rarithmetic import r_longlong, r_uint
-from rpython.rtyper.annlowlevel import cast_instance_to_gcref
 from rpython.rtyper.lltypesystem import lltype, rffi, rstr
 from rpython.rtyper.lltypesystem.lloperation import llop
 from rpython.jit.backend.x86.regloc import AddressLoc
@@ -799,25 +798,29 @@
         # we need to save registers on the stack:
         #
         #  - at least the non-callee-saved registers
+        #    (gc_level == SAVE_DEFAULT_REGS)
         #
-        #  - if gc_level > 0, we save also the callee-saved registers that
-        #    contain GC pointers
+        #  - if gc_level == SAVE_GCREF_REGS we save also the callee-saved
+        #    registers that contain GC pointers
         #
-        #  - gc_level == 2 for CALL_MAY_FORCE or CALL_ASSEMBLER.  We
+        #  - gc_level == SAVE_ALL_REGS for CALL_MAY_FORCE or CALL_ASSEMBLER.  
We
         #    have to save all regs anyway, in case we need to do
         #    cpu.force().  The issue is that grab_frame_values() would
         #    not be able to locate values in callee-saved registers.
         #
-        save_all_regs = gc_level == 2
+        if gc_level == SAVE_ALL_REGS:
+            save_all_regs = SAVE_ALL_REGS
+        else:
+            save_all_regs = SAVE_DEFAULT_REGS
         self.xrm.before_call(save_all_regs=save_all_regs)
-        if gc_level == 1:
+        if gc_level == SAVE_GCREF_REGS:
             gcrootmap = self.assembler.cpu.gc_ll_descr.gcrootmap
-            # we save all the registers for shadowstack and asmgcc for now
+            # we save all the GCREF registers for shadowstack and asmgcc for 
now
             # --- for asmgcc too: we can't say "register x is a gc ref"
             # without distinguishing call sites, which we don't do any
             # more for now.
             if gcrootmap: # and gcrootmap.is_shadow_stack:
-                save_all_regs = 2
+                save_all_regs = SAVE_GCREF_REGS
         self.rm.before_call(save_all_regs=save_all_regs)
         if op.type != 'v':
             if op.type == FLOAT:
@@ -841,11 +844,11 @@
         #
         effectinfo = calldescr.get_extra_info()
         if guard_not_forced:
-            gc_level = 2
+            gc_level = SAVE_ALL_REGS
         elif effectinfo is None or effectinfo.check_can_collect():
-            gc_level = 1
+            gc_level = SAVE_GCREF_REGS
         else:
-            gc_level = 0
+            gc_level = SAVE_DEFAULT_REGS
         #
         self._call(op, [imm(size), sign_loc] +
                        [self.loc(op.getarg(i)) for i in range(op.numargs())],
@@ -909,7 +912,7 @@
 
     def _consider_call_assembler(self, op):
         locs = self.locs_for_call_assembler(op)
-        self._call(op, locs, gc_level=2)
+        self._call(op, locs, gc_level=SAVE_ALL_REGS)
     consider_call_assembler_i = _consider_call_assembler
     consider_call_assembler_r = _consider_call_assembler
     consider_call_assembler_f = _consider_call_assembler
diff --git a/rpython/jit/codewriter/call.py b/rpython/jit/codewriter/call.py
--- a/rpython/jit/codewriter/call.py
+++ b/rpython/jit/codewriter/call.py
@@ -185,8 +185,30 @@
                                          FUNC.RESULT, EffectInfo.MOST_GENERAL)
         return (fnaddr, calldescr)
 
+    def _raise_effect_error(self, op, extraeffect, functype, calling_graph):
+        explanation = []
+        if extraeffect == EffectInfo.EF_RANDOM_EFFECTS:
+            explanation = 
self.randomeffects_analyzer.explain_analyze_slowly(op)
+        elif extraeffect == EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE:
+            explanation = 
self.virtualizable_analyzer.explain_analyze_slowly(op)
+        msg = []
+        if explanation:
+            msg = [
+                "_______ ERROR AT BOTTOM ______",
+                "RPython callstack leading to problem:",
+                ]
+            msg.extend(explanation)
+            msg.append("_______ ERROR: ______")
+        msg.append("operation %r" % op)
+        msg.append("in graph %s" % (calling_graph or "<unknown>"))
+        msg.append("this calls a %s function," % (functype, ))
+        msg.append(" but this contradicts other sources (e.g. it can have 
random"
+                   " effects): EF=%s" % (extraeffect, ))
+        raise Exception("\n".join(msg))
+
     def getcalldescr(self, op, oopspecindex=EffectInfo.OS_NONE,
-                     extraeffect=None, extradescr=None):
+                     extraeffect=None, extradescr=None,
+                     calling_graph=None):
         """Return the calldescr that describes all calls done by 'op'.
         This returns a calldescr that we can put in the corresponding
         call operation in the calling jitcode.  It gets an effectinfo
@@ -202,13 +224,13 @@
         ARGS = FUNC.ARGS
         if NON_VOID_ARGS != [T for T in ARGS if T is not lltype.Void]:
             raise Exception(
-                "in operation %r: calling a function with signature %r, "
+                "operation %r in %s: calling a function with signature %r, "
                 "but passing actual arguments (ignoring voids) of types %r"
-                % (op, FUNC, NON_VOID_ARGS))
+                % (op, calling_graph, FUNC, NON_VOID_ARGS))
         if RESULT != FUNC.RESULT:
             raise Exception(
-                "in operation %r: calling a function with signature %r, "
-                "but the actual return type is %r" % (op, FUNC, RESULT))
+                "%r in %s: calling a function with signature %r, "
+                "but the actual return type is %r" % (op, calling_graph, FUNC, 
RESULT))
         # ok
         # get the 'elidable' and 'loopinvariant' flags from the function object
         elidable = False
@@ -217,7 +239,7 @@
         if op.opname == "direct_call":
             funcobj = op.args[0].value._obj
             assert getattr(funcobj, 'calling_conv', 'c') == 'c', (
-                "%r: getcalldescr() with a non-default call ABI" % (op,))
+                "%r in %s: getcalldescr() with a non-default call ABI" % (op, 
calling_graph))
             func = getattr(funcobj, '_callable', None)
             elidable = getattr(func, "_elidable_function_", False)
             loopinvariant = getattr(func, "_jit_loop_invariant_", False)
@@ -245,11 +267,11 @@
                 if not error:
                     continue
                 raise Exception(
-                    "%r is an indirect call to a family of functions "
+                    "%r in %s is an indirect call to a family of functions "
                     "(or methods) that includes %r. However, the latter "
                     "is marked %r. You need to use an indirection: replace "
                     "it with a non-marked function/method which calls the "
-                    "marked function." % (op, graph, error))
+                    "marked function." % (op, calling_graph, graph, error))
         # build the extraeffect
         random_effects = self.randomeffects_analyzer.analyze(op)
         if random_effects:
@@ -277,22 +299,17 @@
         # check that the result is really as expected
         if loopinvariant:
             if extraeffect != EffectInfo.EF_LOOPINVARIANT:
-                raise Exception(
-                "in operation %r: this calls a _jit_loop_invariant_ function,"
-                " but this contradicts other sources (e.g. it can have random"
-                " effects): EF=%s" % (op, extraeffect))
+                self._raise_effect_error(op, extraeffect, 
"_jit_loop_invariant_", calling_graph)
         if elidable:
             if extraeffect not in (EffectInfo.EF_ELIDABLE_CANNOT_RAISE,
                                    EffectInfo.EF_ELIDABLE_OR_MEMORYERROR,
                                    EffectInfo.EF_ELIDABLE_CAN_RAISE):
-                raise Exception(
-                "in operation %r: this calls an elidable function,"
-                " but this contradicts other sources (e.g. it can have random"
-                " effects): EF=%s" % (op, extraeffect))
+
+                self._raise_effect_error(op, extraeffect, "elidable", 
calling_graph)
             elif RESULT is lltype.Void:
                 raise Exception(
-                    "in operation %r: this calls an elidable function "
-                    "but the function has no result" % (op, ))
+                    "operation %r in %s: this calls an elidable function "
+                    "but the function has no result" % (op, calling_graph))
         #
         effectinfo = effectinfo_from_writeanalyze(
             self.readwrite_analyzer.analyze(op, self.seen_rw), self.cpu,
diff --git a/rpython/jit/codewriter/jtransform.py 
b/rpython/jit/codewriter/jtransform.py
--- a/rpython/jit/codewriter/jtransform.py
+++ b/rpython/jit/codewriter/jtransform.py
@@ -64,6 +64,7 @@
         self.cpu = cpu
         self.callcontrol = callcontrol
         self.portal_jd = portal_jd   # non-None only for the portal graph(s)
+        self.graph = None
 
     def transform(self, graph):
         self.graph = graph
@@ -424,7 +425,8 @@
         of 'residual_call_xxx' are the function to call, and its calldescr."""
         calldescr = self.callcontrol.getcalldescr(op, 
oopspecindex=oopspecindex,
                                                   extraeffect=extraeffect,
-                                                  extradescr=extradescr)
+                                                  extradescr=extradescr,
+                                                  calling_graph=self.graph)
         op1 = self.rewrite_call(op, 'residual_call',
                                 [op.args[0]] + extraargs, calldescr=calldescr)
         if may_call_jitcodes or self.callcontrol.calldescr_canraise(calldescr):
@@ -1613,7 +1615,9 @@
         if len(op.args) > 4 + 2 or have_floats:
             raise Exception("Conditional call does not support floats or more 
than 4 arguments")
         callop = SpaceOperation('direct_call', op.args[1:], op.result)
-        calldescr = self.callcontrol.getcalldescr(callop)
+        calldescr = self.callcontrol.getcalldescr(
+                callop,
+                calling_graph=self.graph)
         assert not 
calldescr.get_extra_info().check_forces_virtual_or_virtualizable()
         op1 = self.rewrite_call(op, rewritten_opname,
                                 op.args[:2], args=op.args[2:],
@@ -1924,7 +1928,8 @@
                              extradescr=None):
         calldescr = self.callcontrol.getcalldescr(op, oopspecindex,
                                                   extraeffect,
-                                                  extradescr=extradescr)
+                                                  extradescr=extradescr,
+                                                  calling_graph=self.graph)
         if extraeffect is not None:
             assert (is_test_calldescr(calldescr)      # for tests
                     or calldescr.get_extra_info().extraeffect == extraeffect)
@@ -1954,7 +1959,8 @@
                             [c_func] + [varoftype(T) for T in argtypes],
                             varoftype(resulttype))
         calldescr = self.callcontrol.getcalldescr(op, oopspecindex,
-                                                  effectinfo)
+                                                  effectinfo,
+                                                  calling_graph=self.graph)
         if isinstance(c_func.value, str):    # in tests only
             func = c_func.value
         else:
diff --git a/rpython/jit/codewriter/test/test_call.py 
b/rpython/jit/codewriter/test/test_call.py
--- a/rpython/jit/codewriter/test/test_call.py
+++ b/rpython/jit/codewriter/test/test_call.py
@@ -299,11 +299,23 @@
     def f4(n, m):
         return compute_hash(str(n) + str(m))
 
+    T = rffi.CArrayPtr(rffi.TIME_T)
+    external = rffi.llexternal("time", [T], rffi.TIME_T, releasegil=True)
+
+    def effect():
+        return external(lltype.nullptr(T.TO))
+
+    @jit.elidable
+    def f5(n, m):
+        effect()
+        return 1
+
     def f(n, m):
         a = f1(n, m)
         b = f2(n, m)
         c = f3(n, m)
         d = f4(n, m)
+        f5(n, m)
         enable_siphash24()
         return a + len(b) + c + d
 
@@ -323,25 +335,33 @@
         call_descr = cc.getcalldescr(call_op)
         assert call_descr.extrainfo.extraeffect == expected
 
+    call_op = f_graph.startblock.operations[4]
+    assert call_op.opname == 'direct_call'
+    excinfo = py.test.raises(Exception, cc.getcalldescr, call_op)
+    lines = excinfo.value.args[0].splitlines()
+    assert "f5" in lines[2]
+    assert "effect" in lines[3]
+    assert "random effects" in lines[-1]
+
 def test_raise_elidable_no_result():
     from rpython.jit.backend.llgraph.runner import LLGraphCPU
     l = []
     @jit.elidable
     def f1(n, m):
         l.append(n)
-    def f(n, m):
+    def fancy_graph_name(n, m):
         f1(n, m)
         return n + m
 
-    rtyper = support.annotate(f, [7, 9])
+    rtyper = support.annotate(fancy_graph_name, [7, 9])
     jitdriver_sd = FakeJitDriverSD(rtyper.annotator.translator.graphs[0])
     cc = CallControl(LLGraphCPU(rtyper), jitdrivers_sd=[jitdriver_sd])
     res = cc.find_all_graphs(FakePolicy())
-    [f_graph] = [x for x in res if x.func is f]
+    [f_graph] = [x for x in res if x.func is fancy_graph_name]
     call_op = f_graph.startblock.operations[0]
     assert call_op.opname == 'direct_call'
-    with py.test.raises(Exception):
-        call_descr = cc.getcalldescr(call_op)
+    x = py.test.raises(Exception, cc.getcalldescr, call_op, 
calling_graph=f_graph)
+    assert "fancy_graph_name" in str(x.value)
 
 def test_can_or_cannot_collect():
     from rpython.jit.backend.llgraph.runner import LLGraphCPU
diff --git a/rpython/jit/codewriter/test/test_flatten.py 
b/rpython/jit/codewriter/test/test_flatten.py
--- a/rpython/jit/codewriter/test/test_flatten.py
+++ b/rpython/jit/codewriter/test/test_flatten.py
@@ -73,7 +73,7 @@
     def guess_call_kind(self, op):
         return 'residual'
     def getcalldescr(self, op, oopspecindex=EffectInfo.OS_NONE,
-                     extraeffect=None, extradescr=None):
+                     extraeffect=None, extradescr=None, calling_graph=None):
         try:
             name = op.args[0].value._obj._name
             if 'cannot_raise' in name or name.startswith('cast_'):
diff --git a/rpython/jit/codewriter/test/test_jtransform.py 
b/rpython/jit/codewriter/test/test_jtransform.py
--- a/rpython/jit/codewriter/test/test_jtransform.py
+++ b/rpython/jit/codewriter/test/test_jtransform.py
@@ -48,7 +48,7 @@
     def guess_call_kind(self, op):
         return 'residual'
     def getcalldescr(self, op, oopspecindex=None, extraeffect=None,
-                     extradescr=None):
+                     extradescr=None, calling_graph=None):
         return 'calldescr'
     def calldescr_canraise(self, calldescr):
         return True
@@ -106,7 +106,7 @@
     def guess_call_kind(self, op):
         return 'builtin'
     def getcalldescr(self, op, oopspecindex=None, extraeffect=None,
-                     extradescr=None):
+                     extradescr=None, calling_graph=None):
         assert oopspecindex is not None    # in this test
         EI = effectinfo.EffectInfo
         if oopspecindex != EI.OS_ARRAYCOPY:
diff --git a/rpython/jit/codewriter/test/test_list.py 
b/rpython/jit/codewriter/test/test_list.py
--- a/rpython/jit/codewriter/test/test_list.py
+++ b/rpython/jit/codewriter/test/test_list.py
@@ -39,7 +39,7 @@
 class FakeCallControl:
     class getcalldescr(AbstractDescr):
         def __init__(self, op, oopspecindex=0, extraeffect=None,
-                     extradescr=None):
+                     extradescr=None, calling_graph=None):
             self.op = op
             self.oopspecindex = oopspecindex
         def __repr__(self):
diff --git a/rpython/jit/codewriter/test/test_longlong.py 
b/rpython/jit/codewriter/test/test_longlong.py
--- a/rpython/jit/codewriter/test/test_longlong.py
+++ b/rpython/jit/codewriter/test/test_longlong.py
@@ -17,7 +17,7 @@
 class FakeBuiltinCallControl:
     def guess_call_kind(self, op):
         return 'builtin'
-    def getcalldescr(self, op, oopspecindex=None, extraeffect=None, 
extradescr=None):
+    def getcalldescr(self, op, oopspecindex=None, extraeffect=None, 
extradescr=None, **kwargs):
         assert oopspecindex is not None    # in this test
         return 'calldescr-%d' % oopspecindex
     def calldescr_canraise(self, calldescr):
diff --git a/rpython/jit/metainterp/optimizeopt/heap.py 
b/rpython/jit/metainterp/optimizeopt/heap.py
--- a/rpython/jit/metainterp/optimizeopt/heap.py
+++ b/rpython/jit/metainterp/optimizeopt/heap.py
@@ -445,13 +445,13 @@
             if effectinfo.check_readonly_descr_field(fielddescr):
                 cf.force_lazy_set(self, fielddescr)
             if effectinfo.check_write_descr_field(fielddescr):
+                cf.force_lazy_set(self, fielddescr, can_cache=False)
                 if fielddescr.is_always_pure():
                     continue
                 try:
                     del self.cached_dict_reads[fielddescr]
                 except KeyError:
                     pass
-                cf.force_lazy_set(self, fielddescr, can_cache=False)
         #
         for arraydescr, submap in self.cached_arrayitems.items():
             if effectinfo.check_readonly_descr_array(arraydescr):
diff --git a/rpython/jit/metainterp/optimizeopt/info.py 
b/rpython/jit/metainterp/optimizeopt/info.py
--- a/rpython/jit/metainterp/optimizeopt/info.py
+++ b/rpython/jit/metainterp/optimizeopt/info.py
@@ -329,11 +329,14 @@
 
     def make_guards(self, op, short, optimizer):
         if self._known_class is not None:
-            short.append(ResOperation(rop.GUARD_NONNULL, [op]))
             if not optimizer.cpu.remove_gctypeptr:
+                short.append(ResOperation(rop.GUARD_NONNULL, [op]))
                 short.append(ResOperation(rop.GUARD_IS_OBJECT, [op]))
-            short.append(ResOperation(rop.GUARD_CLASS,
-                                      [op, self._known_class]))
+                short.append(ResOperation(rop.GUARD_CLASS,
+                                          [op, self._known_class]))
+            else:
+                short.append(ResOperation(rop.GUARD_NONNULL_CLASS,
+                    [op, self._known_class]))
         elif self.descr is not None:
             short.append(ResOperation(rop.GUARD_NONNULL, [op]))
             if not optimizer.cpu.remove_gctypeptr:
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py 
b/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py
@@ -3562,6 +3562,27 @@
         """
         self.optimize_loop(ops, expected, expected_preamble=expected_preamble)
 
+    def test_residual_call_still_forces_immutable_writes_though(self):
+        ops = """
+        [p1]
+        setfield_gc(p1, 6, descr=valuedescr3)
+        i2 = call_i(5, descr=writevalue3descr)
+        jump(p1)
+        """
+        expected_preamble = """
+        [p1]
+        setfield_gc(p1, 6, descr=valuedescr3)
+        i2 = call_i(5, descr=writevalue3descr)
+        jump(p1)
+        """
+        expected = """
+        [p1]
+        setfield_gc(p1, 6, descr=valuedescr3)
+        i2 = call_i(5, descr=writevalue3descr)
+        jump(p1)
+        """
+        self.optimize_loop(ops, expected, expected_preamble=expected_preamble)
+
     def test_residual_call_invalidate_some_caches(self):
         ops = """
         [p1, p2]
@@ -7541,6 +7562,33 @@
         """
         self.optimize_loop(ops, expected, expected_short=short)
 
+    def test_guards_before_getfields_in_short_preamble_removetypeptr(self, 
monkeypatch):
+        monkeypatch.setattr(self.cpu, "remove_gctypeptr", True)
+        ops = """
+        [p0]
+        guard_nonnull_class(p0, ConstClass(node_vtable)) []
+        p1 = getfield_gc_r(p0, descr=nextdescr)
+        guard_nonnull_class(p1, ConstClass(node_vtable)) []
+        p2 = getfield_gc_r(p1, descr=nextdescr)
+        guard_nonnull_class(p2, ConstClass(node_vtable)) []
+        jump(p0)
+        """
+        expected = """
+        [p0, p1]
+        jump(p0, p1)
+        """
+        short = """
+        [p0]
+        guard_nonnull_class(p0, ConstClass(node_vtable)) []
+        p1 = getfield_gc_r(p0, descr=nextdescr)
+        guard_nonnull_class(p1, ConstClass(node_vtable)) []
+        p2 = getfield_gc_r(p1, descr=nextdescr)
+        guard_nonnull_class(p2, ConstClass(node_vtable)) []
+        jump(p1)
+        """
+        self.optimize_loop(ops, expected, expected_short=short)
+
+
     def test_forced_virtual_pure_getfield(self):
         ops = """
         [p0]
diff --git a/rpython/jit/metainterp/test/test_loop.py 
b/rpython/jit/metainterp/test/test_loop.py
--- a/rpython/jit/metainterp/test/test_loop.py
+++ b/rpython/jit/metainterp/test/test_loop.py
@@ -1114,5 +1114,40 @@
         # one guard_false got removed
         self.check_resops(guard_false=4, guard_true=5)
 
+    def test_heapcache_bug(self):
+        class W_Object(object):
+            _attrs_ = []
+        class W_Nil(W_Object):
+            _attrs_ = []
+        class W_Cons(W_Object):
+            _attrs_ = ['first', 'rest']
+            _immutable_fields_ = ['first', 'rest']
+            def __init__(self, v1, v2):
+                self.first = v1
+                self.rest = v2
+
+        def reverse(xs):
+            result = W_Nil()
+            while isinstance(xs, W_Cons):
+                result = W_Cons(xs.first, result)
+                xs = xs.rest
+            return result
+
+        driver = JitDriver(reds=['repetitions', 'v'], greens=['pc'],
+                       get_printable_location=lambda pc: str(pc))
+        def entry_point():
+            repetitions = 0
+            while repetitions < 10:
+                pc = 0
+                v = W_Nil()
+                while pc < 10:
+                    driver.jit_merge_point(v=v, repetitions=repetitions, pc=pc)
+                    v = reverse(W_Cons(pc + 1, W_Cons(pc + 2, W_Cons(pc + 3, 
W_Cons(pc + 4, W_Nil())))))
+                    pc = pc + 1
+                repetitions += 1
+        
+        self.meta_interp(entry_point, [])
+
+
 class TestLLtype(LoopTest, LLJitMixin):
     pass
diff --git a/rpython/rlib/_rsocket_rffi.py b/rpython/rlib/_rsocket_rffi.py
--- a/rpython/rlib/_rsocket_rffi.py
+++ b/rpython/rlib/_rsocket_rffi.py
@@ -985,11 +985,14 @@
                          ]
 
 
-    compilation_info = ExternalCompilationInfo(
+    compilation_info = eci.merge(ExternalCompilationInfo(
                                     includes=includes,
                                     
separate_module_sources=separate_module_sources,
                                     post_include_bits=post_include_bits,
-                               )
+                               ))
+else:
+    compilation_info = eci
+
 
 if _WIN32:
     CConfig.WSAEVENT = platform.SimpleType('WSAEVENT', rffi.VOIDP)
diff --git a/rpython/translator/backendopt/graphanalyze.py 
b/rpython/translator/backendopt/graphanalyze.py
--- a/rpython/translator/backendopt/graphanalyze.py
+++ b/rpython/translator/backendopt/graphanalyze.py
@@ -4,6 +4,7 @@
 
 class GraphAnalyzer(object):
     verbose = False
+    explanation = None
 
     def __init__(self, translator):
         self.translator = translator
@@ -73,6 +74,20 @@
     def compute_graph_info(self, graph):
         return None
 
+    def explain_analyze_slowly(self, op):
+        # this is a hack! usually done before a crash
+        self.__init__(self.translator)
+        self.explanation = explanation = []
+        oldverbose = self.verbose
+        self.verbose = True
+        try:
+            self.analyze(op)
+        finally:
+            del self.explanation
+            self.verbose = oldverbose
+        explanation.reverse()
+        return explanation
+
     def analyze(self, op, seen=None, graphinfo=None):
         if op.opname == "direct_call":
             try:
@@ -113,7 +128,11 @@
         return x
 
     def dump_info(self, info):
-        print '[%s] %s' % (self.__class__.__name__, info)
+        st = '[%s] %s' % (self.__class__.__name__, info)
+        if self.explanation is not None:
+            self.explanation.append(st)
+        else:
+            print st
 
     def analyze_direct_call(self, graph, seen=None):
         if seen is None:
diff --git a/rpython/translator/backendopt/test/test_writeanalyze.py 
b/rpython/translator/backendopt/test/test_writeanalyze.py
--- a/rpython/translator/backendopt/test/test_writeanalyze.py
+++ b/rpython/translator/backendopt/test/test_writeanalyze.py
@@ -531,3 +531,37 @@
         typed_effects = self._analyze_graph(t, wa, typed_write)
         typed_effects = self._filter_reads(typed_effects)
         assert typed_effects == direct_effects
+
+    def test_explanation(self):
+        class A(object):
+            def methodname(self):
+                self.x = 1
+                return 1
+            def m(self):
+                raise ValueError
+        class B(A):
+            def methodname(self):
+                return 2
+            def m(self):
+                return 3
+        def fancyname(a):
+            return a.methodname()
+        def m(a):
+            return a.m()
+        def h(flag):
+            if flag:
+                obj = A()
+            else:
+                obj = B()
+            fancyname(obj)
+            m(obj)
+
+        t, wa = self.translate(h, [int])
+        hgraph = graphof(t, h)
+        # fiiiish :-(
+        block = hgraph.startblock.exits[0].target.exits[0].target
+        op_call_fancyname = block.operations[0]
+
+        explanation = wa.explain_analyze_slowly(op_call_fancyname)
+        assert "fancyname" in explanation[0]
+        assert "methodname" in explanation[1]
diff --git a/rpython/translator/platform/__init__.py 
b/rpython/translator/platform/__init__.py
--- a/rpython/translator/platform/__init__.py
+++ b/rpython/translator/platform/__init__.py
@@ -151,8 +151,9 @@
                 # Also, ERROR confuses lib-python/conftest.py.
             raise CompilationError(stdout, stderr)
         else:
-            for line in stderr.splitlines():
-                log.WARNING(line)
+            if self.log_errors:
+                for line in stderr.splitlines():
+                    log.WARNING(line)
 
     def _make_o_file(self, cfile, ext):
         """Create an object file name under the udir for a .c file"""
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to