Author: Ronan Lamy <ronan.l...@gmail.com>
Branch: py3.5
Changeset: r90683:afbf09453369
Date: 2017-03-14 14:26 +0000
http://bitbucket.org/pypy/pypy/changeset/afbf09453369/

Log:    hg merge default

diff --git a/pypy/doc/index-of-release-notes.rst 
b/pypy/doc/index-of-release-notes.rst
--- a/pypy/doc/index-of-release-notes.rst
+++ b/pypy/doc/index-of-release-notes.rst
@@ -6,6 +6,7 @@
 
 .. toctree::
 
+   release-v5.7.0.rst
    release-pypy2.7-v5.6.0.rst
    release-pypy2.7-v5.4.1.rst
    release-pypy2.7-v5.4.0.rst
@@ -53,6 +54,12 @@
    release-0.7.0.rst
    release-0.6
 
+CPython 3.5 compatible versions
+-------------------------------
+
+.. toctree::
+
+   release-v5.7.0.rst
 
 CPython 3.3 compatible versions
 -------------------------------
diff --git a/pypy/doc/index-of-whatsnew.rst b/pypy/doc/index-of-whatsnew.rst
--- a/pypy/doc/index-of-whatsnew.rst
+++ b/pypy/doc/index-of-whatsnew.rst
@@ -7,6 +7,7 @@
 .. toctree::
 
    whatsnew-head.rst
+   whatsnew-pypy2-5.7.0.rst
    whatsnew-pypy2-5.6.0.rst
    whatsnew-pypy2-5.4.0.rst
    whatsnew-pypy2-5.3.1.rst
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
@@ -1,204 +1,8 @@
 ==========================
-What's new in PyPy2.7 5.6+
+What's new in PyPy2.7 5.8+
 ==========================
 
-.. this is a revision shortly after release-pypy2.7-v5.6
-.. startrev: 7e9787939641
+.. this is a revision shortly after release-pypy2.7-v5.7
+.. startrev: 44f31f6dd39f
 
 
-Since a while now, PyPy preserves the order of dictionaries and sets.
-However, the set literal syntax ``{x, y, z}`` would by mistake build a
-set with the opposite order: ``set([z, y, x])``.  This has been fixed.
-Note that CPython is inconsistent too: in 2.7.12, ``{5, 5.0}`` would be
-``set([5.0])``, but in 2.7.trunk it is ``set([5])``.  PyPy's behavior
-changed in exactly the same way because of this fix.
-
-
-.. branch: mappingproxy
-.. branch: py3k-finish_time
-.. branch: py3k-kwonly-builtin
-.. branch: py3k_add_terminal_size
-.. branch: testing-cleanup-py3k
-
-.. branch: rpython-resync
-Backport rpython changes made directly on the py3k and py3.5 branches.
-
-.. branch: rpython-error-to-systemerror
-
-Any uncaught RPython exception (from a PyPy bug) is turned into an
-app-level SystemError.  This should improve the lot of users hitting an
-uncaught RPython error.
-
-.. branch: union-side-effects-2
-
-Try to improve the consistency of RPython annotation unions.
-
-.. branch: pytest-2.9.2
-
-.. branch: clean-exported-state
-
-Clean-ups in the jit optimizeopt
-
-.. branch: conditional_call_value_4
-
-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).
-
-.. branch: raw-calloc
-
-.. branch: issue2446
-
-Assign ``tp_doc`` to the new TypeObject's type dictionary ``__doc__`` key
-so it will be picked up by app-level objects of that type
-
-.. branch: cling-support
-
-Module cppyy now uses cling as its backend (Reflex has been removed). The
-user-facing interface and main developer tools (genreflex, selection files,
-class loader, etc.) remain the same.  A libcppyy_backend.so library is still
-needed but is now available through PyPI with pip: PyPy-cppyy-backend.
-
-The Cling-backend brings support for modern C++ (11, 14, etc.), dynamic
-template instantations, and improved integration with CFFI for better
-performance.  It also provides interactive C++ (and bindings to that).
-
-.. branch: better-PyDict_Next
-
-Improve the performance of ``PyDict_Next``. When trying ``PyDict_Next`` on a
-typedef dict, the test exposed a problem converting a ``GetSetProperty`` to a
-``PyGetSetDescrObject``. The other direction seem to be fully implemented.
-This branch made a minimal effort to convert the basic fields to avoid
-segfaults, but trying to use the ``PyGetSetDescrObject`` will probably fail.
-
-.. branch: stdlib-2.7.13
-
-Updated the implementation to match CPython 2.7.13 instead of 2.7.13.
-
-.. branch: issue2444
-
-Fix ``PyObject_GetBuffer`` and ``PyMemoryView_GET_BUFFER``, which leaked
-memory and held references. Add a finalizer to CPyBuffer, add a
-PyMemoryViewObject with a PyBuffer attached so that the call to 
-``PyMemoryView_GET_BUFFER`` does not leak a PyBuffer-sized piece of memory.
-Properly call ``bf_releasebuffer`` when not ``NULL``.
-
-.. branch: boehm-rawrefcount
-
-Support translations of cpyext with the Boehm GC (for special cases like
-revdb).
-
-.. branch: strbuf-as-buffer
-
-Implement StringBuffer.get_raw_address (missing feature for the buffer 
protocol).
-More generally it is now possible to obtain the address of any object (if it
-is readonly) without pinning it.
-
-.. branch: cpyext-cleanup
-.. branch: api_func-refactor
-
-Refactor cpyext initialisation.
-
-.. branch: cpyext-from2
-
-Fix a test failure introduced by strbuf-as-buffer
-
-.. branch: cpyext-FromBuffer
-
-Do not recreate the object in PyMemoryView_FromBuffer, rather pass it to
-the returned PyMemoryViewObject, to take ownership of it. Fixes a ref leak.
-
-.. branch: issue2464
-
-Give (almost?) all GetSetProperties a valid __objclass__.
-
-.. branch: TreeStain/fixed-typo-line-29-mostly-to-most-1484469416419
-.. branch: TreeStain/main-lines-changed-in-l77-l83-made-para-1484471558033
-
-.. branch: missing-tp_new
-
-Improve mixing app-level classes in c-extensions, especially if the app-level
-class has a ``tp_new`` or ``tp_dealloc``. The issue is that c-extensions expect
-all the method slots to be filled with a function pointer, where app-level will
-search up the mro for an appropriate function at runtime. With this branch we
-now fill many more slots in the c-extenion type objects.
-Also fix for c-extension type that calls ``tp_hash`` during initialization
-(str, unicode types), and fix instantiating c-extension types from built-in
-classes by enforcing an order of instaniation.
-
-.. branch: rffi-parser-2
-
-rffi structures in cpyext can now be created by parsing simple C headers.
-Additionally, the cts object that holds the parsed information can act like
-cffi's ffi objects, with the methods cts.cast() and cts.gettype().
-
-.. branch: rpython-hash
-
-Don't freeze hashes in the translated pypy.  In practice, that means
-that we can now translate PyPy with the option --hash=siphash24 and get
-the same hashes as CPython 3.5, which can be randomized (in a
-crypographically good way).  It is the default in PyPy3.  The default of
-PyPy2 remains unchanged: there are user programs out there that depend
-on constant hashes (or even sometimes on specific hash results).
-
-.. branch: dict-move-to-end
-
-Our dicts, which are always ordered, now have an extra "method" for
-Python 3.x which moves an item to first or last position.  In PyPy 3.5
-it is the standard ``OrderedDict.move_to_end()`` method, but the
-behavior is also available on Python 2.x or for the ``dict`` type by
-calling ``__pypy__.move_to_end(dict, key, last=True)``.
-
-
-.. branch optinfo-into-bridges-3
-
-Improve the optimization of branchy Python code by retaining more information
-across failing guards.
-
-
-.. branch: space-newtext
-
-Internal refactoring of ``space.wrap()``, which is now replaced with
-explicitly-typed methods.  Notably, there are now ``space.newbytes()``
-and ``space.newtext()``: these two methods are identical on PyPy 2.7 but
-not on PyPy 3.x.  The latter is used to get an app-level unicode string
-by decoding the RPython string, assumed to be utf-8.
-
-.. branch: space-wrap
-
-.. branch: fix_bool_restype
-
-Fix for ``ctypes.c_bool``-returning ctypes functions
-
-.. branch: py3.5-text-utf8
-
-space.text_w now encodes to utf-8 not preserving surrogates.
-
-.. branch: fix-cpyext-releasebuffer
-
-Improve handling of the Py3-style buffer slots in cpyext: fix memoryviews
-keeping objects alive forever (missing decref), and make sure that
-bf_releasebuffer is called when it should, e.g. from PyBuffer_Release.
-
-.. branch: fix-global
-
-Fix bug (bad reported info) when asked to translate SyntaxWarning to
-SyntaxError.
-
-.. branch: optinfo-into-bridges-3
-
-Improve the optimization of branchy Python code by retaining more
-information across failing guards. This is done by appending some
-carefully encoded extra information into the resume code.
-
-.. branch: shadowstack-perf-2
-
-Two changes that together bring the performance of shadowstack close to
-asmgcc---close enough that we can now make shadowstack the default even
-on Linux.  This should remove a whole class of rare bugs introduced by
-asmgcc.
-
-.. branch: fniephaus/fix-typo-1488123166752
diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-pypy2-5.7.0.rst
copy from pypy/doc/whatsnew-head.rst
copy to pypy/doc/whatsnew-pypy2-5.7.0.rst
--- a/pypy/doc/whatsnew-head.rst
+++ b/pypy/doc/whatsnew-pypy2-5.7.0.rst
@@ -1,6 +1,6 @@
-==========================
-What's new in PyPy2.7 5.6+
-==========================
+=========================
+What's new in PyPy2.7 5.7
+=========================
 
 .. this is a revision shortly after release-pypy2.7-v5.6
 .. startrev: 7e9787939641
diff --git a/pypy/module/_cffi_backend/test/test_recompiler.py 
b/pypy/module/_cffi_backend/test/test_recompiler.py
--- a/pypy/module/_cffi_backend/test/test_recompiler.py
+++ b/pypy/module/_cffi_backend/test/test_recompiler.py
@@ -1866,7 +1866,7 @@
     def test_call_with_nested_anonymous_struct(self):
         import sys
         if sys.platform == 'win32':
-            py.test.skip("needs a GCC extension")
+            skip("needs a GCC extension")
         ffi, lib = self.prepare("""
             struct foo { int a; union { int b, c; }; };
             struct foo f(void);
@@ -1914,6 +1914,9 @@
             "set_source() and not taking a final '...' argument)")
 
     def test_call_with_zero_length_field(self):
+        import sys
+        if sys.platform == 'win32':
+            skip("zero-length field not supported by MSVC")
         ffi, lib = self.prepare("""
             struct foo { int a; int x[0]; };
             struct foo f(void);
@@ -1959,7 +1962,7 @@
     def test_call_with_packed_struct(self):
         import sys
         if sys.platform == 'win32':
-            py.test.skip("needs a GCC extension")
+            skip("needs a GCC extension")
         ffi, lib = self.prepare("""
             struct foo { char y; int x; };
             struct foo f(void);
diff --git a/pypy/module/_rawffi/alt/test/test_funcptr.py 
b/pypy/module/_rawffi/alt/test/test_funcptr.py
--- a/pypy/module/_rawffi/alt/test/test_funcptr.py
+++ b/pypy/module/_rawffi/alt/test/test_funcptr.py
@@ -32,7 +32,10 @@
         #
         c_file.write(py.code.Source('\n'.join(snippets)))
         eci = ExternalCompilationInfo(include_dirs=[cdir])
-        return str(platform.compile([c_file], eci, 'x', standalone=False))
+        # Windows note: can't reuse the same file name 'x.dll', because
+        # the previous one is likely still opened
+        return str(platform.compile([c_file], eci, 'x' + cls.__name__,
+                                    standalone=False))
 
     def setup_class(cls):
         space = cls.space
diff --git a/pypy/module/cpyext/src/pymem.c b/pypy/module/cpyext/src/pymem.c
--- a/pypy/module/cpyext/src/pymem.c
+++ b/pypy/module/cpyext/src/pymem.c
@@ -1,5 +1,14 @@
+#ifdef _WIN32
+#  define _WIN32_WINNT 0x0501
+#endif
+
 #include <Python.h>
 
+#ifdef _WIN32
+#  include <Windows.h>
+#endif
+
+
 void *
 PyMem_RawMalloc(size_t size)
 {
@@ -120,10 +129,21 @@
         _PyPyGC_AddMemoryPressure(report);
         PyGILState_Release(state);
     }
+
+    /* Should we return -2 or 0?  In theory it should be -2, because
+       we're not using the info to really track the allocations.
+       But I'm sure someone is too clever somewhere and stops calling
+       _PyTraceMalloc_Track() if it returns -2.  On the other hand,
+       returning 0 might lead to expectations that importing
+       'tracemalloc' works on Python 3.  Oh well, in that case we'll
+       just crash with ImportError during 'import tracemalloc'.
+     */
+    return 0;
 }
 
 int _PyTraceMalloc_Untrack(_PyTraceMalloc_domain_t domain,
                            uintptr_t ptr)
 {
-    /* nothing */
+    /* nothing to do */
+    return 0;
 }
diff --git a/pypy/module/cpyext/test/test_pystate.py 
b/pypy/module/cpyext/test/test_pystate.py
--- a/pypy/module/cpyext/test/test_pystate.py
+++ b/pypy/module/cpyext/test/test_pystate.py
@@ -71,6 +71,7 @@
                 ("dance", "METH_NOARGS",
                  """
                      PyThreadState *old_tstate, *new_tstate;
+                     PyObject *d;
 
                      PyEval_InitThreads();
 
@@ -79,7 +80,7 @@
                          return PyLong_FromLong(0);
                      }
 
-                     PyObject* d = PyThreadState_GetDict(); /* fails on 
cpython */
+                     d = PyThreadState_GetDict(); /* fails on cpython */
                      if (d != NULL) {
                          return PyLong_FromLong(1);
                      }
@@ -142,6 +143,9 @@
             ("bounce", "METH_NOARGS",
             """
             PyThreadState * tstate;
+            PyObject *dict;
+            PyGILState_STATE gilstate;
+
             if (PyEval_ThreadsInitialized() == 0)
             {
             PyEval_InitThreads();
@@ -150,11 +154,11 @@
             if (tstate == NULL) {
                 return PyLong_FromLong(0);
             }
-            PyObject* dict = PyThreadState_GetDict();
+            dict = PyThreadState_GetDict();
             if (dict != NULL) {
             return PyLong_FromLong(1);
             }
-            PyGILState_STATE gilstate = PyGILState_Ensure();
+            gilstate = PyGILState_Ensure();
             dict = PyThreadState_GetDict();
             if (dict == NULL) {
             return PyLong_FromLong(2);
diff --git a/pypy/module/cpyext/test/test_tupleobject.py 
b/pypy/module/cpyext/test/test_tupleobject.py
--- a/pypy/module/cpyext/test/test_tupleobject.py
+++ b/pypy/module/cpyext/test/test_tupleobject.py
@@ -154,5 +154,10 @@
 
     def test_tuple_subclass(self):
         module = self.import_module(name='foo')
-        a = module.TupleLike([1, 2, 3])
+        a = module.TupleLike(range(100, 400, 100))
         assert module.is_TupleLike(a) == 1
+        assert isinstance(a, tuple)
+        assert issubclass(type(a), tuple)
+        assert list(a) == range(100, 400, 100)
+        assert list(a) == range(100, 400, 100)
+        assert list(a) == range(100, 400, 100)
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
@@ -947,12 +947,15 @@
             pass
         class bar(f1, f2):
             pass
+        class foo(f2, f1):
+            pass
         assert bar.__base__ is f2
         # On cpython, the size changes.
         if '__pypy__' in sys.builtin_module_names:
             assert module.size_of_instances(bar) == size
         else:
             assert module.size_of_instances(bar) >= size
+        assert module.size_of_instances(foo) == module.size_of_instances(bar)
 
     def test_app_cant_subclass_two_types(self):
         import sys
@@ -1176,4 +1179,21 @@
         assert type(obj).__doc__ == "The Base12 type or object"
         assert obj.__doc__ == "The Base12 type or object"
 
-
+    def test_multiple_inheritance_fetch_tp_bases(self):
+        module = self.import_extension('foo', [
+           ("foo", "METH_O",
+            '''
+                PyTypeObject *tp;
+                tp = (PyTypeObject*)args;
+                Py_INCREF(tp->tp_bases);
+                return tp->tp_bases;
+            '''
+            )])
+        class A(object):
+            pass
+        class B(object):
+            pass
+        class C(A, B):
+            pass
+        bases = module.foo(C)
+        assert bases == (A, B)
diff --git a/pypy/module/cpyext/test/test_userslots.py 
b/pypy/module/cpyext/test/test_userslots.py
--- a/pypy/module/cpyext/test/test_userslots.py
+++ b/pypy/module/cpyext/test/test_userslots.py
@@ -160,8 +160,9 @@
                 };
             ''', more_init='''
                 PyObject * mod1 = PyImport_ImportModule("datetime");
+                PyObject * dt;
                 if (mod1 == NULL) INITERROR;
-                PyObject * dt = PyUnicode_FromString("datetime");
+                dt = PyUnicode_FromString("datetime");
                 datetime_cls = (PyTypeObject*)PyObject_GetAttr(mod1, dt);
                 if (datetime_cls == NULL) INITERROR;
                 _Timestamp.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE;
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
@@ -417,8 +417,8 @@
 
 def inherit_special(space, pto, base_pto):
     # XXX missing: copy basicsize and flags in a magical way
-    # (minimally, if tp_basicsize is zero we copy it from the base)
-    if not pto.c_tp_basicsize:
+    # (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:
         pto.c_tp_basicsize = base_pto.c_tp_basicsize
     if pto.c_tp_itemsize < base_pto.c_tp_itemsize:
         pto.c_tp_itemsize = base_pto.c_tp_itemsize
@@ -672,7 +672,7 @@
     if builder.cpyext_type_init is not None:
         builder.cpyext_type_init.append((pto, w_type))
     else:
-        finish_type_1(space, pto)
+        finish_type_1(space, pto, w_type.bases_w)
         finish_type_2(space, pto, w_type)
 
     pto.c_tp_basicsize = rffi.sizeof(typedescr.basestruct)
@@ -804,7 +804,7 @@
 
     return w_obj
 
-def finish_type_1(space, pto):
+def finish_type_1(space, pto, bases_w=None):
     """
     Sets up tp_bases, necessary before creating the interpreter type.
     """
@@ -816,11 +816,12 @@
     if base and not pto.c_ob_type: # will be filled later
         pto.c_ob_type = base.c_ob_type
     if not pto.c_tp_bases:
-        if not base:
-            bases = space.newtuple([])
-        else:
-            bases = space.newtuple([from_ref(space, base_pyo)])
-        pto.c_tp_bases = make_ref(space, bases)
+        if bases_w is None:
+            if not base:
+                bases_w = []
+            else:
+                bases_w = [from_ref(space, base_pyo)]
+        pto.c_tp_bases = make_ref(space, space.newtuple(bases_w))
 
 def finish_type_2(space, pto, w_obj):
     """
diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py 
b/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py
--- a/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py
@@ -1231,7 +1231,8 @@
     def test_ffi_buffer_comparisons(self):
         ffi = FFI(backend=self.Backend())
         ba = bytearray(range(100, 110))
-        assert ba == memoryview(ba)    # justification for the following
+        if sys.version_info >= (2, 7):
+            assert ba == memoryview(ba)    # justification for the following
         a = ffi.new("uint8_t[]", list(ba))
         c = ffi.new("uint8_t[]", [99] + list(ba))
         try:
diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py 
b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py
--- a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py
@@ -2040,7 +2040,7 @@
             struct foo s = { 40, 200 };
             return s;
         }
-        struct foo g(int a, ...) { }
+        struct foo g(int a, ...) { return f(); }
     """)
     assert lib.f().x == 200
     e = py.test.raises(NotImplementedError, lib.g, 0)
@@ -2069,7 +2069,7 @@
             s.b = 200;
             return s;
         }
-        struct foo g(int a, ...) { }
+        struct foo g(int a, ...) { return f(); }
     """)
     assert lib.f().b == 200
     e = py.test.raises(NotImplementedError, lib.g, 0)
@@ -2095,7 +2095,7 @@
             struct foo s = { 11 };
             return s;
         }
-        struct foo g(int a, ...) { }
+        struct foo g(int a, ...) { return f(); }
     """)
     assert lib.f().x == 11
     e = py.test.raises(NotImplementedError, lib.g, 0)
@@ -2107,6 +2107,8 @@
         "set_source() and not taking a final '...' argument)")
 
 def test_call_with_zero_length_field():
+    if sys.platform == 'win32':
+        py.test.skip("zero-length field not supported by MSVC")
     ffi = FFI()
     ffi.cdef("""
         struct foo { int a; int x[0]; };
@@ -2119,7 +2121,7 @@
             struct foo s = { 42 };
             return s;
         }
-        struct foo g(int a, ...) { }
+        struct foo g(int a, ...) { return f(); }
     """)
     assert lib.f().a == 42
     e = py.test.raises(NotImplementedError, lib.g, 0)
@@ -2143,7 +2145,7 @@
             union foo s = { 42 };
             return s;
         }
-        union foo g(int a, ...) { }
+        union foo g(int a, ...) { return f(); }
     """)
     assert lib.f().a == 42
     e = py.test.raises(NotImplementedError, lib.g, 0)
diff --git a/rpython/config/translationoption.py 
b/rpython/config/translationoption.py
--- a/rpython/config/translationoption.py
+++ b/rpython/config/translationoption.py
@@ -26,10 +26,15 @@
 
 SUPPORT__THREAD = (    # whether the particular C compiler supports __thread
     sys.platform.startswith("linux") or     # Linux works
-    sys.platform.startswith("darwin"))      # OS/X >= 10.7 works
+    #sys.platform.startswith("darwin") or   # OS/X >= 10.7 works (*)
+    False)
     # Windows doesn't work.  Please
     # add other platforms here if it works on them.
 
+# (*) NOTE: __thread on OS/X does not work together with
+# pthread_key_create(): when the destructor is called, the __thread is
+# already freed!
+
 MAINDIR = os.path.dirname(os.path.dirname(__file__))
 CACHE_DIR = os.path.realpath(os.path.join(MAINDIR, '_cache'))
 
diff --git a/rpython/jit/backend/x86/assembler.py 
b/rpython/jit/backend/x86/assembler.py
--- a/rpython/jit/backend/x86/assembler.py
+++ b/rpython/jit/backend/x86/assembler.py
@@ -349,15 +349,12 @@
         #
         mc.MOV(eax, heap(self.cpu.pos_exception()))
         mc.TEST_rr(eax.value, eax.value)
-        mc.J_il8(rx86.Conditions['NZ'], 0)
-        jnz_location = mc.get_relative_pos()
+        jnz_location = mc.emit_forward_jump('NZ')
         #
         mc.RET()
         #
         # patch the JNZ above
-        offset = mc.get_relative_pos() - jnz_location
-        assert 0 < offset <= 127
-        mc.overwrite(jnz_location-1, chr(offset))
+        mc.patch_forward_jump(jnz_location)
         # From now on this function is basically "merged" with
         # its caller and so contains DEFAULT_FRAME_BYTES bytes
         # plus my own return address, which we'll ignore next
@@ -834,16 +831,13 @@
         ofs = self.cpu.unpack_fielddescr(descrs.arraydescr.lendescr)
         mc.CMP_bi(ofs, 0xffffff)     # force writing 32 bit
         stack_check_cmp_ofs = mc.get_relative_pos() - 4
-        mc.J_il8(rx86.Conditions['GE'], 0)
-        jg_location = mc.get_relative_pos()
+        jg_location = mc.emit_forward_jump('GE')
         mc.MOV_si(WORD, 0xffffff)     # force writing 32 bit
         ofs2 = mc.get_relative_pos() - 4
         self.push_gcmap(mc, gcmap, store=True)
         mc.CALL(imm(self._frame_realloc_slowpath))
         # patch the JG above
-        offset = mc.get_relative_pos() - jg_location
-        assert 0 < offset <= 127
-        mc.overwrite(jg_location-1, chr(offset))
+        mc.patch_forward_jump(jg_location)
         self.frame_depth_to_patch.append(stack_check_cmp_ofs)
         self.frame_depth_to_patch.append(ofs2)
 
@@ -857,16 +851,13 @@
         ofs = self.cpu.unpack_fielddescr(descrs.arraydescr.lendescr)
         mc.CMP_bi(ofs, 0xffffff)
         stack_check_cmp_ofs = mc.get_relative_pos() - 4
-        mc.J_il8(rx86.Conditions['GE'], 0)
-        jg_location = mc.get_relative_pos()
+        jg_location = mc.emit_forward_jump('GE')
         mc.MOV_rr(edi.value, ebp.value)
         mc.MOV_ri(esi.value, 0xffffff)
         ofs2 = mc.get_relative_pos() - 4
         mc.CALL(imm(self.cpu.realloc_frame_crash))
         # patch the JG above
-        offset = mc.get_relative_pos() - jg_location
-        assert 0 < offset <= 127
-        mc.overwrite(jg_location-1, chr(offset))
+        mc.patch_forward_jump(jg_location)
         self.frame_depth_to_patch.append(stack_check_cmp_ofs)
         self.frame_depth_to_patch.append(ofs2)
 
@@ -1002,13 +993,10 @@
             self.mc.MOV(eax, heap(endaddr))             # MOV eax, [start]
             self.mc.SUB(eax, esp)                       # SUB eax, current
             self.mc.CMP(eax, heap(lengthaddr))          # CMP eax, [length]
-            self.mc.J_il8(rx86.Conditions['BE'], 0)     # JBE .skip
-            jb_location = self.mc.get_relative_pos()
+            jb_location = self.mc.emit_forward_jump('BE')#JBE .skip
             self.mc.CALL(imm(self.stack_check_slowpath))# CALL slowpath
             # patch the JB above                        # .skip:
-            offset = self.mc.get_relative_pos() - jb_location
-            assert 0 < offset <= 127
-            self.mc.overwrite(jb_location-1, chr(offset))
+            self.mc.patch_forward_jump(jb_location)
             #
 
     def _call_footer(self):
@@ -1242,15 +1230,12 @@
         return genop_cmp
 
     def _if_parity_clear_zero_and_carry(self):
-        self.mc.J_il8(rx86.Conditions['NP'], 0)
-        jnp_location = self.mc.get_relative_pos()
+        jnp_location = self.mc.emit_forward_jump('NP')
         # CMP EBP, 0: as EBP cannot be null here, that operation should
         # always clear zero and carry
         self.mc.CMP_ri(ebp.value, 0)
         # patch the JNP above
-        offset = self.mc.get_relative_pos() - jnp_location
-        assert 0 < offset <= 127
-        self.mc.overwrite(jnp_location-1, chr(offset))
+        self.mc.patch_forward_jump(jnp_location)
 
     def _cmpop_float(cond, rev_cond):
         is_ne           = cond == 'NE'
@@ -1728,10 +1713,11 @@
         # jump to jump over this GUARD_NO_EXCEPTION as well, if we can
         if self._find_nearby_operation(-1).getopnum() in (
                 rop.COND_CALL, rop.COND_CALL_VALUE_I, rop.COND_CALL_VALUE_R):
-            jmp_adr = self.previous_cond_call_jcond
-            offset = self.mc.get_relative_pos() - jmp_adr
-            if offset <= 127:
-                self.mc.overwrite(jmp_adr-1, chr(offset))
+            j_location = self.previous_cond_call_jcond
+            try:
+                self.mc.patch_forward_jump(j_location)
+            except codebuf.ShortJumpTooFar:
+                pass    # ignore this case
 
     def genop_guard_guard_not_invalidated(self, guard_op, guard_token,
                                           locs, ign):
@@ -1842,13 +1828,10 @@
     def genop_guard_guard_nonnull_class(self, guard_op, guard_token, locs, 
ign):
         self.mc.CMP(locs[0], imm1)
         # Patched below
-        self.mc.J_il8(rx86.Conditions['B'], 0)
-        jb_location = self.mc.get_relative_pos()
+        jb_location = self.mc.emit_forward_jump('B')
         self._cmp_guard_class(locs)
         # patch the JB above
-        offset = self.mc.get_relative_pos() - jb_location
-        assert 0 < offset <= 127
-        self.mc.overwrite(jb_location-1, chr(offset))
+        self.mc.patch_forward_jump(jb_location)
         #
         self.guard_success_cc = rx86.Conditions['E']
         self.implement_guard(guard_token)
@@ -2223,19 +2206,15 @@
         ofs = self.cpu.get_ofs_of_frame_field('jf_descr')
         self.mc.CMP(mem(eax, ofs), imm(value))
         # patched later
-        self.mc.J_il8(rx86.Conditions['E'], 0) # goto B if we get 
'done_with_this_frame'
-        return self.mc.get_relative_pos()
+        return self.mc.emit_forward_jump('E') # goto B if we get 
'done_with_this_frame'
 
     def _call_assembler_patch_je(self, result_loc, je_location):
         if (IS_X86_32 and isinstance(result_loc, FrameLoc) and
             result_loc.type == FLOAT):
             self.mc.FSTPL_b(result_loc.value)
-        self.mc.JMP_l8(0) # jump to done, patched later
-        jmp_location = self.mc.get_relative_pos()
+        jmp_location = self.mc.emit_forward_jump_uncond()   # jump to the end
         #
-        offset = jmp_location - je_location
-        assert 0 < offset <= 127
-        self.mc.overwrite(je_location - 1, chr(offset))
+        self.mc.patch_forward_jump(je_location)
         self.mc.force_frame_size(DEFAULT_FRAME_BYTES)
         #
         return jmp_location
@@ -2255,9 +2234,7 @@
                 self.mc.MOV_rm(eax.value, (eax.value, ofs))
 
     def _call_assembler_patch_jmp(self, jmp_location):
-        offset = self.mc.get_relative_pos() - jmp_location
-        assert 0 <= offset <= 127
-        self.mc.overwrite(jmp_location - 1, chr(offset))
+        self.mc.patch_forward_jump(jmp_location)
 
     # ------------------- END CALL ASSEMBLER -----------------------
 
@@ -2288,16 +2265,14 @@
         else:
             loc = addr_add_const(loc_base, descr.jit_wb_if_flag_byteofs)
         mc.TEST8(loc, imm(mask))
-        mc.J_il8(rx86.Conditions['Z'], 0) # patched later
-        jz_location = mc.get_relative_pos()
+        jz_location = mc.emit_forward_jump('Z')   # patched later
 
         # for cond_call_gc_wb_array, also add another fast path:
         # if GCFLAG_CARDS_SET, then we can just set one bit and be done
         if card_marking:
             # GCFLAG_CARDS_SET is in this byte at 0x80, so this fact can
-            # been checked by the status flags of the previous TEST8
-            mc.J_il8(rx86.Conditions['S'], 0) # patched later
-            js_location = mc.get_relative_pos()
+            # been checked by the sign flags of the previous TEST8
+            js_location = mc.emit_forward_jump('S')   # patched later
         else:
             js_location = 0
 
@@ -2326,13 +2301,10 @@
             # The helper ends again with a check of the flag in the object.
             # So here, we can simply write again a 'JNS', which will be
             # taken if GCFLAG_CARDS_SET is still not set.
-            mc.J_il8(rx86.Conditions['NS'], 0) # patched later
-            jns_location = mc.get_relative_pos()
+            jns_location = mc.emit_forward_jump('NS')   # patched later
             #
             # patch the JS above
-            offset = mc.get_relative_pos() - js_location
-            assert 0 < offset <= 127
-            mc.overwrite(js_location-1, chr(offset))
+            mc.patch_forward_jump(js_location)
             #
             # case GCFLAG_CARDS_SET: emit a few instructions to do
             # directly the card flag setting
@@ -2367,14 +2339,10 @@
                 raise AssertionError("index is neither RegLoc nor ImmedLoc")
             #
             # patch the JNS above
-            offset = mc.get_relative_pos() - jns_location
-            assert 0 < offset <= 127
-            mc.overwrite(jns_location-1, chr(offset))
+            mc.patch_forward_jump(jns_location)
 
         # patch the JZ above
-        offset = mc.get_relative_pos() - jz_location
-        assert 0 < offset <= 127
-        mc.overwrite(jz_location-1, chr(offset))
+        mc.patch_forward_jump(jz_location)
 
     def genop_discard_cond_call_gc_wb(self, op, arglocs):
         self._write_barrier_fastpath(self.mc, op.getdescr(), arglocs)
@@ -2407,9 +2375,8 @@
 
     def cond_call(self, gcmap, imm_func, arglocs, resloc=None):
         assert self.guard_success_cc >= 0
-        self.mc.J_il8(rx86.invert_condition(self.guard_success_cc), 0)
-                                                            # patched later
-        jmp_adr = self.mc.get_relative_pos()
+        j_location = self.mc.emit_forward_jump_cond(
+            rx86.invert_condition(self.guard_success_cc))
         self.guard_success_cc = rx86.cond_none
         #
         self.push_gcmap(self.mc, gcmap, store=True)
@@ -2459,26 +2426,21 @@
             v = gpr_reg_mgr_cls.all_reg_indexes[eax.value]
             self.mc.MOV_rb(eax.value, v * WORD + base_ofs)
         #
-        offset = self.mc.get_relative_pos() - jmp_adr
-        assert 0 < offset <= 127
-        self.mc.overwrite(jmp_adr-1, chr(offset))
+        self.mc.patch_forward_jump(j_location)
         # might be overridden again to skip over the following
         # guard_no_exception too
-        self.previous_cond_call_jcond = jmp_adr
+        self.previous_cond_call_jcond = j_location
 
     def malloc_cond(self, nursery_free_adr, nursery_top_adr, size, gcmap):
         assert size & (WORD-1) == 0     # must be correctly aligned
         self.mc.MOV(ecx, heap(nursery_free_adr))
         self.mc.LEA_rm(edx.value, (ecx.value, size))
         self.mc.CMP(edx, heap(nursery_top_adr))
-        self.mc.J_il8(rx86.Conditions['NA'], 0) # patched later
-        jmp_adr = self.mc.get_relative_pos()
+        jna_location = self.mc.emit_forward_jump('NA')   # patched later
         # save the gcmap
         self.push_gcmap(self.mc, gcmap, store=True)
         self.mc.CALL(imm(follow_jump(self.malloc_slowpath)))
-        offset = self.mc.get_relative_pos() - jmp_adr
-        assert 0 < offset <= 127
-        self.mc.overwrite(jmp_adr-1, chr(offset))
+        self.mc.patch_forward_jump(jna_location)
         self.mc.MOV(heap(nursery_free_adr), edx)
 
     def malloc_cond_varsize_frame(self, nursery_free_adr, nursery_top_adr,
@@ -2492,14 +2454,11 @@
         else:
             self.mc.LEA_ra(edx.value, (ecx.value, sizeloc.value, 0, 0))
         self.mc.CMP(edx, heap(nursery_top_adr))
-        self.mc.J_il8(rx86.Conditions['NA'], 0) # patched later
-        jmp_adr = self.mc.get_relative_pos()
+        jna_location = self.mc.emit_forward_jump('NA')   # patched later
         # save the gcmap
         self.push_gcmap(self.mc, gcmap, store=True)
         self.mc.CALL(imm(follow_jump(self.malloc_slowpath)))
-        offset = self.mc.get_relative_pos() - jmp_adr
-        assert 0 < offset <= 127
-        self.mc.overwrite(jmp_adr-1, chr(offset))
+        self.mc.patch_forward_jump(jna_location)
         self.mc.MOV(heap(nursery_free_adr), edx)
 
     def malloc_cond_varsize(self, kind, nursery_free_adr, nursery_top_adr,
@@ -2517,8 +2476,7 @@
             varsizeloc = edx
 
         self.mc.CMP(varsizeloc, imm(maxlength))
-        self.mc.J_il8(rx86.Conditions['A'], 0) # patched later
-        jmp_adr0 = self.mc.get_relative_pos()
+        ja_location = self.mc.emit_forward_jump('A')   # patched later
 
         self.mc.MOV(ecx, heap(nursery_free_adr))
         if valid_addressing_size(itemsize):
@@ -2542,12 +2500,9 @@
         # now edx contains the total size in bytes, rounded up to a multiple
         # of WORD, plus nursery_free_adr
         self.mc.CMP(edx, heap(nursery_top_adr))
-        self.mc.J_il8(rx86.Conditions['NA'], 0) # patched later
-        jmp_adr1 = self.mc.get_relative_pos()
+        jna_location = self.mc.emit_forward_jump('NA')   # patched later
         #
-        offset = self.mc.get_relative_pos() - jmp_adr0
-        assert 0 < offset <= 127
-        self.mc.overwrite(jmp_adr0-1, chr(offset))
+        self.mc.patch_forward_jump(ja_location)
         # save the gcmap
         self.push_gcmap(self.mc, gcmap, store=True)
         if kind == rewrite.FLAG_ARRAY:
@@ -2563,21 +2518,16 @@
                 addr = self.malloc_slowpath_unicode
             self.mc.MOV(edx, lengthloc)
         self.mc.CALL(imm(follow_jump(addr)))
-        self.mc.JMP_l8(0)      # jump to done, patched later
-        jmp_location = self.mc.get_relative_pos()
+        jmp_location = self.mc.emit_forward_jump_uncond()  # jump to later
         #
-        offset = self.mc.get_relative_pos() - jmp_adr1
-        assert 0 < offset <= 127
-        self.mc.overwrite(jmp_adr1-1, chr(offset))
+        self.mc.patch_forward_jump(jna_location)
         self.mc.force_frame_size(DEFAULT_FRAME_BYTES)
         # write down the tid, but not if it's the result of the CALL
         self.mc.MOV(mem(ecx, 0), imm(arraydescr.tid))
         # while we're at it, this line is not needed if we've done the CALL
         self.mc.MOV(heap(nursery_free_adr), edx)
         #
-        offset = self.mc.get_relative_pos() - jmp_location
-        assert 0 < offset <= 127
-        self.mc.overwrite(jmp_location - 1, chr(offset))
+        self.mc.patch_forward_jump(jmp_location)
 
     def store_force_descr(self, op, fail_locs, frame_depth):
         guard_token = self.implement_guard_recovery(op.opnum,
diff --git a/rpython/jit/backend/x86/callbuilder.py 
b/rpython/jit/backend/x86/callbuilder.py
--- a/rpython/jit/backend/x86/callbuilder.py
+++ b/rpython/jit/backend/x86/callbuilder.py
@@ -341,25 +341,20 @@
             # thread.  So here we check if the shadowstack pointer
             # is still the same as before we released the GIL (saved
             # in 'ebx'), and if not, we fall back to 'reacqgil_addr'.
-            mc.J_il8(rx86.Conditions['NE'], 0)
-            jne_location = mc.get_relative_pos()
+            jne_location = mc.emit_forward_jump('NE')
             # here, ecx (=old_value) is zero (so rpy_fastgil was in 'released'
             # state before the XCHG, but the XCHG acquired it by writing 1)
             rst = gcrootmap.get_root_stack_top_addr()
             mc = self.mc
             mc.CMP(ebx, heap(rst))
-            mc.J_il8(rx86.Conditions['E'], 0)
-            je_location = mc.get_relative_pos()
+            je_location = mc.emit_forward_jump('E')
             # revert the rpy_fastgil acquired above, so that the
             # general 'reacqgil_addr' below can acquire it again...
             mc.MOV(heap(fastgil), ecx)
             # patch the JNE above
-            offset = mc.get_relative_pos() - jne_location
-            assert 0 < offset <= 127
-            mc.overwrite(jne_location-1, chr(offset))
+            mc.patch_forward_jump(jne_location)
         else:
-            mc.J_il8(rx86.Conditions['E'], 0)
-            je_location = mc.get_relative_pos()
+            je_location = mc.emit_forward_jump('E')
         #
         # Yes, we need to call the reacqgil() function
         if not self.result_value_saved_early:
@@ -374,9 +369,7 @@
             self.restore_result_value(save_edx=False)
         #
         # patch the JE above
-        offset = mc.get_relative_pos() - je_location
-        assert 0 < offset <= 127
-        mc.overwrite(je_location-1, chr(offset))
+        mc.patch_forward_jump(je_location)
         #
         if restore_edx:
             mc.MOV_rs(edx.value, 12)   # restore this
diff --git a/rpython/jit/backend/x86/codebuf.py 
b/rpython/jit/backend/x86/codebuf.py
--- a/rpython/jit/backend/x86/codebuf.py
+++ b/rpython/jit/backend/x86/codebuf.py
@@ -1,12 +1,13 @@
 from rpython.rtyper.lltypesystem import lltype, rffi
 from rpython.rlib.rarithmetic import intmask
+from rpython.rlib.objectmodel import specialize
 from rpython.rlib.debug import debug_start, debug_print, debug_stop
 from rpython.rlib.debug import have_debug_prints
 from rpython.jit.backend.llsupport.asmmemmgr import BlockBuilderMixin
 from rpython.jit.backend.x86.rx86 import X86_32_CodeBuilder, X86_64_CodeBuilder
 from rpython.jit.backend.x86.regloc import LocationCodeBuilder
 from rpython.jit.backend.x86.arch import IS_X86_32, IS_X86_64, WORD
-from rpython.jit.backend.x86 import valgrind
+from rpython.jit.backend.x86 import rx86, valgrind
 
 # XXX: Seems nasty to change the superclass of MachineCodeBlockWrapper
 # like this
@@ -17,6 +18,9 @@
     codebuilder_cls = X86_64_CodeBuilder
     backend_name = 'x86_64'
 
+class ShortJumpTooFar(Exception):
+    pass
+
 
 class MachineCodeBlockWrapper(BlockBuilderMixin,
                               LocationCodeBuilder,
@@ -53,3 +57,22 @@
                 adr[0] = rffi.cast(rffi.INT, intmask(adr[0]) - p)
         valgrind.discard_translations(addr, self.get_relative_pos())
         self._dump(addr, "jit-backend-dump", backend_name)
+
+    @specialize.arg(1)
+    def emit_forward_jump(self, condition_string):
+        return self.emit_forward_jump_cond(rx86.Conditions[condition_string])
+
+    def emit_forward_jump_cond(self, cond):
+        self.J_il8(cond, 0)
+        return self.get_relative_pos()
+
+    def emit_forward_jump_uncond(self):
+        self.JMP_l8(0)
+        return self.get_relative_pos()
+
+    def patch_forward_jump(self, jcond_location):
+        offset = self.get_relative_pos() - jcond_location
+        assert offset >= 0
+        if offset > 127:
+            raise ShortJumpTooFar
+        self.overwrite(jcond_location-1, chr(offset))
diff --git a/rpython/rlib/rposix.py b/rpython/rlib/rposix.py
--- a/rpython/rlib/rposix.py
+++ b/rpython/rlib/rposix.py
@@ -464,28 +464,29 @@
             how = SEEK_END
     return handle_posix_error('lseek', c_lseek(fd, pos, how))
 
-c_pread = external('pread',
-                  [rffi.INT, rffi.VOIDP, rffi.SIZE_T , OFF_T], rffi.SSIZE_T,
-                  save_err=rffi.RFFI_SAVE_ERRNO)
-c_pwrite = external('pwrite',
-                   [rffi.INT, rffi.VOIDP, rffi.SIZE_T, OFF_T], rffi.SSIZE_T,
-                   save_err=rffi.RFFI_SAVE_ERRNO)
+if not _WIN32:
+    c_pread = external('pread',
+                      [rffi.INT, rffi.VOIDP, rffi.SIZE_T , OFF_T], 
rffi.SSIZE_T,
+                      save_err=rffi.RFFI_SAVE_ERRNO)
+    c_pwrite = external('pwrite',
+                       [rffi.INT, rffi.VOIDP, rffi.SIZE_T, OFF_T], 
rffi.SSIZE_T,
+                       save_err=rffi.RFFI_SAVE_ERRNO)
 
-@enforceargs(int, int, None)
-def pread(fd, count, offset):
-    if count < 0:
-        raise OSError(errno.EINVAL, None)
-    validate_fd(fd)
-    with rffi.scoped_alloc_buffer(count) as buf:
-        void_buf = rffi.cast(rffi.VOIDP, buf.raw)
-        return buf.str(handle_posix_error('pread', c_pread(fd, void_buf, 
count, offset)))
-        
-@enforceargs(int, None, None)
-def pwrite(fd, data, offset):
-    count = len(data)
-    validate_fd(fd)
-    with rffi.scoped_nonmovingbuffer(data) as buf:
-        return handle_posix_error('pwrite', c_pwrite(fd, buf, count, offset))
+    @enforceargs(int, int, None)
+    def pread(fd, count, offset):
+        if count < 0:
+            raise OSError(errno.EINVAL, None)
+        validate_fd(fd)
+        with rffi.scoped_alloc_buffer(count) as buf:
+            void_buf = rffi.cast(rffi.VOIDP, buf.raw)
+            return buf.str(handle_posix_error('pread', c_pread(fd, void_buf, 
count, offset)))
+            
+    @enforceargs(int, None, None)
+    def pwrite(fd, data, offset):
+        count = len(data)
+        validate_fd(fd)
+        with rffi.scoped_nonmovingbuffer(data) as buf:
+            return handle_posix_error('pwrite', c_pwrite(fd, buf, count, 
offset))
 
 c_ftruncate = external('ftruncate', [rffi.INT, rffi.LONGLONG], rffi.INT,
                        macro=_MACRO_ON_POSIX, save_err=rffi.RFFI_SAVE_ERRNO)
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to