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

mjacob pypy.commits at gmail.com
Mon Mar 19 12:07:25 EDT 2018


Author: Manuel Jacob <me at manueljacob.de>
Branch: py3.5
Changeset: r94004:fcbdf6d13402
Date: 2018-03-19 16:55 +0100
http://bitbucket.org/pypy/pypy/changeset/fcbdf6d13402/

Log:	hg merge default

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
@@ -52,3 +52,13 @@
 .. branch: refactor-slots
 
 Refactor cpyext slots.
+
+
+.. branch: call-loopinvariant-into-bridges
+
+Speed up branchy code that does a lot of function inlining by saving one call
+to read the TLS in most bridges.
+
+.. branch: rpython-sprint
+
+Refactor in rpython signatures
diff --git a/pypy/module/posix/test/test_posix2.py b/pypy/module/posix/test/test_posix2.py
--- a/pypy/module/posix/test/test_posix2.py
+++ b/pypy/module/posix/test/test_posix2.py
@@ -1403,6 +1403,7 @@
             if len(e.value.args) > 2:
                 assert e.value.args[2] == "\\foo\\bar\\baz"
 
+    @py.test.mark.skipif("sys.platform != 'win32'")
     def test_rename(self):
         os = self.posix
         fname = self.path2 + 'rename.txt'
diff --git a/pypy/module/unicodedata/test/test_hyp.py b/pypy/module/unicodedata/test/test_hyp.py
--- a/pypy/module/unicodedata/test/test_hyp.py
+++ b/pypy/module/unicodedata/test/test_hyp.py
@@ -1,6 +1,7 @@
+import sys
 import pytest
 try:
-    from hypothesis import given, strategies as st, example, settings
+    from hypothesis import given, strategies as st, example, settings, assume
 except ImportError:
     pytest.skip("hypothesis required")
 
@@ -40,9 +41,14 @@
 
 @pytest.mark.parametrize('NF1, NF2, NF3', compositions)
 @example(s=u'---\uafb8\u11a7---')  # issue 2289
- at example(s=u'\ufacf')
 @settings(max_examples=1000)
 @given(s=st.text())
 def test_composition(s, space, NF1, NF2, NF3):
+    # 'chr(0xfacf) normalizes to chr(0x2284a), which is too big')
+    assume(not (s == u'\ufacf' and sys.maxunicode == 65535))
     norm1, norm2, norm3 = [make_normalization(space, form) for form in [NF1, NF2, NF3]]
     assert norm2(norm1(s)) == norm3(s)
+
+if sys.maxunicode != 65535:
+    # conditionally generate the example via an unwrapped decorator    
+    test_composition = example(s=u'\ufacf')(test_composition)
diff --git a/rpython/annotator/signature.py b/rpython/annotator/signature.py
--- a/rpython/annotator/signature.py
+++ b/rpython/annotator/signature.py
@@ -14,16 +14,16 @@
 
 def _annotation_key(t):
     from rpython.rtyper import extregistry
-    if type(t) is list:
+    if isinstance(t, list):
         assert len(t) == 1
         return ('list', _annotation_key(t[0]))
-    elif type(t) is dict:
+    elif isinstance(t, dict):
         assert len(t.keys()) == 1
         return ('dict', _annotation_key(t.items()[0]))
     elif isinstance(t, tuple):
         return tuple([_annotation_key(i) for i in t])
     elif extregistry.is_registered(t):
-        # XXX should it really be always different?
+        # XXX do we want to do something in this case?
         return t
     return t
 
@@ -38,24 +38,36 @@
             return t
     return _compute_annotation(t, bookkeeper)
 
+
+def _validate_annotation_size(t):
+    try:
+        _ = iter(t)
+    except TypeError:  # if it's not an iterable, just return
+        return t       # (size does not matter)
+    if isinstance(t, tuple):  # we accept tuples with any length, because
+        return t              # their in-memory representation is predictable
+    if len(t) > 1:
+        raise TypeError("Cannot specify multiple types in a %s (try using tuple)", type(t))
+
+
 def _compute_annotation(t, bookkeeper=None):
     from rpython.rtyper.lltypesystem import lltype
     from rpython.rtyper.llannotation import lltype_to_annotation
+    _validate_annotation_size(t)
     if isinstance(t, SomeObject):
         return t
     elif isinstance(t, lltype.LowLevelType):
         return lltype_to_annotation(t)
     elif isinstance(t, list):
-        assert len(t) == 1, "We do not support type joining in list"
-        listdef = ListDef(bookkeeper, annotation(t[0]), mutated=True, resized=True)
-        return SomeList(listdef)
+        return SomeList(
+                ListDef(bookkeeper, annotation(t[0]),
+                        mutated=True, resized=True))
     elif isinstance(t, tuple):
         return SomeTuple(tuple([annotation(i) for i in t]))
     elif isinstance(t, dict):
-        assert len(t) == 1, "We do not support type joining in dict"
-        result = SomeDict(DictDef(bookkeeper, annotation(t.keys()[0]),
-                                annotation(t.values()[0])))
-        return result
+        return SomeDict(
+                DictDef(bookkeeper,
+                        annotation(t.keys()[0]), annotation(t.values()[0])))
     elif type(t) is types.NoneType:
         return s_None
     elif extregistry.is_registered(t):
@@ -84,13 +96,12 @@
     elif t is types.NoneType:
         return s_None
     elif bookkeeper and extregistry.is_registered_type(t):
-        entry = extregistry.lookup_type(t)
-        return entry.compute_annotation_bk(bookkeeper)
+        return (extregistry.lookup_type(t)
+                .compute_annotation_bk(bookkeeper))
     elif t is type:
         return SomeType()
     elif bookkeeper and not hasattr(t, '_freeze_'):
-        classdef = bookkeeper.getuniqueclassdef(t)
-        return SomeInstance(classdef)
+        return SomeInstance(bookkeeper.getuniqueclassdef(t))
     else:
         raise AssertionError("annotationoftype(%r)" % (t,))
 
diff --git a/rpython/jit/metainterp/optimizeopt/bridgeopt.py b/rpython/jit/metainterp/optimizeopt/bridgeopt.py
--- a/rpython/jit/metainterp/optimizeopt/bridgeopt.py
+++ b/rpython/jit/metainterp/optimizeopt/bridgeopt.py
@@ -17,11 +17,17 @@
 # <length>
 # (<box1> <descr> <box2>) length times, if getfield(box1, descr) == box2
 #                         both boxes should be in the liveboxes
+#                         (or constants)
 #
 # <length>
 # (<box1> <index> <descr> <box2>) length times, if getarrayitem_gc(box1, index, descr) == box2
 #                                 both boxes should be in the liveboxes
+#                                 (or constants)
 #
+# ---- call_loopinvariant knowledge
+# <length>
+# (<const> <box2>) length times, if call_loopinvariant(const) == box2
+#                  box2 should be in liveboxes
 # ----
 
 
@@ -55,11 +61,11 @@
     return box
 
 def serialize_optimizer_knowledge(optimizer, numb_state, liveboxes, liveboxes_from_env, memo):
+    from rpython.jit.metainterp.history import ConstInt
     available_boxes = {}
     for box in liveboxes:
         if box is not None and box in liveboxes_from_env:
             available_boxes[box] = None
-    metainterp_sd = optimizer.metainterp_sd
 
     # class knowledge is stored as bits, true meaning the class is known, false
     # means unknown. on deserializing we look at the bits, and read the runtime
@@ -106,7 +112,19 @@
         numb_state.append_int(0)
         numb_state.append_int(0)
 
+    if optimizer.optrewrite:
+        tuples_loopinvariant = optimizer.optrewrite.serialize_optrewrite(
+                available_boxes)
+        numb_state.append_int(len(tuples_loopinvariant))
+        for constarg0, box in tuples_loopinvariant:
+            numb_state.append_short(
+                    tag_box(ConstInt(constarg0), liveboxes_from_env, memo))
+            numb_state.append_short(tag_box(box, liveboxes_from_env, memo))
+    else:
+        numb_state.append_int(0)
+
 def deserialize_optimizer_knowledge(optimizer, resumestorage, frontend_boxes, liveboxes):
+    from rpython.jit.metainterp.history import ConstInt
     reader = resumecode.Reader(resumestorage.rd_numb)
     assert len(frontend_boxes) == len(liveboxes)
     metainterp_sd = optimizer.metainterp_sd
@@ -131,8 +149,6 @@
             optimizer.make_constant_class(box, cls)
 
     # heap knowledge
-    if not optimizer.optheap:
-        return
     length = reader.next_item()
     result_struct = []
     for i in range(length):
@@ -154,4 +170,19 @@
         tagged = reader.next_item()
         box2 = decode_box(resumestorage, tagged, liveboxes, metainterp_sd.cpu)
         result_array.append((box1, index, descr, box2))
-    optimizer.optheap.deserialize_optheap(result_struct, result_array)
+    if optimizer.optheap:
+        optimizer.optheap.deserialize_optheap(result_struct, result_array)
+
+    # call_loopinvariant knowledge
+    length = reader.next_item()
+    result_loopinvariant = []
+    for i in range(length):
+        tagged1 = reader.next_item()
+        const = decode_box(resumestorage, tagged1, liveboxes, metainterp_sd.cpu)
+        assert isinstance(const, ConstInt)
+        i = const.getint()
+        tagged2 = reader.next_item()
+        box = decode_box(resumestorage, tagged2, liveboxes, metainterp_sd.cpu)
+        result_loopinvariant.append((i, box))
+    if optimizer.optrewrite:
+        optimizer.optrewrite.deserialize_optrewrite(result_loopinvariant)
diff --git a/rpython/jit/metainterp/optimizeopt/rewrite.py b/rpython/jit/metainterp/optimizeopt/rewrite.py
--- a/rpython/jit/metainterp/optimizeopt/rewrite.py
+++ b/rpython/jit/metainterp/optimizeopt/rewrite.py
@@ -877,6 +877,18 @@
     optimize_SAME_AS_R = optimize_SAME_AS_I
     optimize_SAME_AS_F = optimize_SAME_AS_I
 
+    def serialize_optrewrite(self, available_boxes):
+        res = []
+        for i, box in self.loop_invariant_results.iteritems():
+            box = self.get_box_replacement(box)
+            if box in available_boxes:
+                res.append((i, box))
+        return res
+
+    def deserialize_optrewrite(self, tups):
+        for i, box in tups:
+            self.loop_invariant_results[i] = box
+
 dispatch_opt = make_dispatcher_method(OptRewrite, 'optimize_',
                                       default=OptRewrite.emit)
 optimize_guards = _findall(OptRewrite, 'optimize_', 'GUARD')
diff --git a/rpython/jit/metainterp/test/test_bridgeopt.py b/rpython/jit/metainterp/test/test_bridgeopt.py
--- a/rpython/jit/metainterp/test/test_bridgeopt.py
+++ b/rpython/jit/metainterp/test/test_bridgeopt.py
@@ -1,6 +1,9 @@
 # tests that check that information is fed from the optimizer into the bridges
 
+import pytest
+
 import math
+
 from rpython.rlib import jit
 from rpython.jit.metainterp.test.support import LLJitMixin
 from rpython.jit.metainterp.optimizeopt.bridgeopt import serialize_optimizer_knowledge
@@ -27,6 +30,7 @@
 class FakeOptimizer(object):
     metainterp_sd = None
     optheap = None
+    optrewrite = None
 
     def __init__(self, dct={}, cpu=None):
         self.dct = dct
@@ -61,7 +65,8 @@
 
     serialize_optimizer_knowledge(optimizer, numb_state, liveboxes, {}, None)
 
-    assert unpack_numbering(numb_state.create_numbering()) == [1, 0b010000, 0, 0]
+    assert unpack_numbering(numb_state.create_numbering()) == [
+            1, 0b010000, 0, 0, 0]
 
     rbox1 = InputArgRef()
     rbox2 = InputArgRef()
@@ -100,7 +105,7 @@
 
     serialize_optimizer_knowledge(optimizer, numb_state, liveboxes, {}, None)
 
-    assert len(numb_state.create_numbering().code) == 3 + math.ceil(len(refboxes) / 6.0)
+    assert len(numb_state.create_numbering().code) == 4 + math.ceil(len(refboxes) / 6.0)
 
     dct = {box: cls
               for box, known_class in boxes_known_classes
@@ -321,3 +326,74 @@
         self.check_trace_count(3)
         self.check_resops(guard_value=1)
         self.check_resops(getarrayitem_gc_i=5)
+
+    def test_bridge_call_loopinvariant(self):
+        class A(object):
+            pass
+        class B(object):
+            pass
+
+        aholder = B()
+        aholder.a = A()
+
+        @jit.loop_invariant
+        def get():
+            return aholder.a
+
+        myjitdriver = jit.JitDriver(greens=[], reds=['y', 'res', 'n'])
+        def f(x, y, n):
+            if x == 10001121:
+                aholder.a = A()
+            if x:
+                get().x = 1
+            else:
+                get().x = 2
+            res = 0
+            while y > 0:
+                myjitdriver.jit_merge_point(y=y, n=n, res=res)
+                a = get()
+                a = get()
+                res += a.x
+                if y > n:
+                    res += 1
+                res += get().x + a.x
+                y -= 1
+            return res
+        res = self.meta_interp(f, [6, 32, 16])
+        self.check_trace_count(3)
+        self.check_resops(call_r=1)
+
+    @pytest.mark.xfail()
+    def test_bridge_call_loopinvariant_2(self):
+        class A(object):
+            pass
+        class B(object):
+            pass
+
+        aholder = B()
+        aholder.a = A()
+
+        @jit.loop_invariant
+        def get():
+            return aholder.a
+
+        myjitdriver = jit.JitDriver(greens=[], reds=['y', 'res', 'n'])
+        def f(x, y, n):
+            if x == 10001121:
+                aholder.a = A()
+            if x:
+                get().x = 1
+            else:
+                get().x = 2
+            res = 0
+            while y > 0:
+                myjitdriver.jit_merge_point(y=y, n=n, res=res)
+                if y > n:
+                    res += get().x
+                    res += 1
+                res += get().x
+                y -= 1
+            return res
+        res = self.meta_interp(f, [6, 32, 16])
+        self.check_trace_count(3)
+        self.check_resops(call_r=1)
diff --git a/rpython/jit/metainterp/test/test_resume.py b/rpython/jit/metainterp/test/test_resume.py
--- a/rpython/jit/metainterp/test/test_resume.py
+++ b/rpython/jit/metainterp/test/test_resume.py
@@ -40,7 +40,7 @@
 
 class FakeOptimizer(object):
     metainterp_sd = None
-    optheap = None
+    optheap = optrewrite = None
 
     def __init__(self, trace=None):
         self.trace = trace
diff --git a/rpython/rlib/rstruct/nativefmttable.py b/rpython/rlib/rstruct/nativefmttable.py
--- a/rpython/rlib/rstruct/nativefmttable.py
+++ b/rpython/rlib/rstruct/nativefmttable.py
@@ -130,6 +130,13 @@
 sizeof_double = native_fmttable['d']['size']
 sizeof_float  = native_fmttable['f']['size']
 
+# Copy CPython's behavior of using short's size and alignment for half-floats.
+native_fmttable['e'] = {'size': native_fmttable['h']['size'],
+                        'alignment': native_fmttable['h']['alignment'],
+                        'pack': std.pack_halffloat,
+                        'unpack': std.unpack_halffloat,
+                       }
+
 # ____________________________________________________________
 #
 # A PyPy extension: accepts the 'u' format character in native mode,
diff --git a/rpython/rlib/rstruct/test/test_pack.py b/rpython/rlib/rstruct/test/test_pack.py
--- a/rpython/rlib/rstruct/test/test_pack.py
+++ b/rpython/rlib/rstruct/test/test_pack.py
@@ -139,9 +139,6 @@
         self.check('d', 123.456789)
 
     def test_pack_halffloat(self):
-        if self.fmttable is nativefmttable.native_fmttable:
-            # Host Python cannot handle half floats.
-            return
         size = 2
         wbuf = MutableStringBuffer(size)
         self.mypack_into('e', wbuf, 6.5e+04)


More information about the pypy-commit mailing list