[pypy-commit] pypy default: Fix for b43a6e2c0ea1: can't very reasonably use appexec() here,

arigo pypy.commits at gmail.com
Mon Jul 31 05:41:11 EDT 2017


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r91996:abb9f6f4b003
Date: 2017-07-31 09:40 +0200
http://bitbucket.org/pypy/pypy/changeset/abb9f6f4b003/

Log:	Fix for b43a6e2c0ea1: can't very reasonably use appexec() here,
	because it would create a single jit loop. If the logic is called
	with various types in the same program, we get a longer and longer
	jit loop keeping previous results alive.

	Fixed the same way than listobject.py's _do_extend_from_iterable.

diff --git a/pypy/objspace/std/bytearrayobject.py b/pypy/objspace/std/bytearrayobject.py
--- a/pypy/objspace/std/bytearrayobject.py
+++ b/pypy/objspace/std/bytearrayobject.py
@@ -569,14 +569,43 @@
         return list(buf.as_str())
     return _from_byte_sequence(space, w_source)
 
+def _get_printable_location(w_type):
+    return ('bytearray_from_byte_sequence [w_type=%s]' %
+            w_type.getname(w_type.space))
+
+_byteseq_jitdriver = jit.JitDriver(
+    name='bytearray_from_byte_sequence',
+    greens=['w_type'],
+    reds=['w_iter', 'data'],
+    get_printable_location=_get_printable_location)
+
 def _from_byte_sequence(space, w_source):
     # Split off in a separate function for the JIT's benefit
-    w_result = space.appexec([w_source], """(seq):
-        result = bytearray()
-        for i in seq:
-            result.append(i)
-        return result""")
-    return w_result.getdata()
+    # and add a jitdriver with the type of w_iter as the green key
+    w_iter = space.iter(w_source)
+    length_hint = space.length_hint(w_source, 0)
+    data = newlist_hint(length_hint)
+    #
+    _from_byte_sequence_loop(space, w_iter, data)
+    #
+    extended = len(data)
+    if extended < length_hint:
+        resizelist_hint(data, extended)
+    return data
+
+def _from_byte_sequence_loop(space, w_iter, data):
+    w_type = space.type(w_iter)
+    while True:
+        _byteseq_jitdriver.jit_merge_point(w_type=w_type,
+                                           w_iter=w_iter,
+                                           data=data)
+        try:
+            w_item = space.next(w_iter)
+        except OperationError as e:
+            if not e.match(space, space.w_StopIteration):
+                raise
+            break
+        data.append(space.byte_w(w_item))
 
 
 def _hex_digit_to_int(d):
diff --git a/pypy/objspace/std/test/test_bytearrayobject.py b/pypy/objspace/std/test/test_bytearrayobject.py
--- a/pypy/objspace/std/test/test_bytearrayobject.py
+++ b/pypy/objspace/std/test/test_bytearrayobject.py
@@ -448,6 +448,13 @@
         raises(TypeError, b.extend, [object()])
         raises(TypeError, b.extend, u"unicode")
 
+    def test_extend_calls_len_or_lengthhint(self):
+        class BadLen(object):
+            def __iter__(self): return iter(range(10))
+            def __len__(self): raise RuntimeError('hello')
+        b = bytearray()
+        raises(RuntimeError, b.extend, BadLen())
+
     def test_setitem_from_front(self):
         b = bytearray(b'abcdefghij')
         b[:2] = b''


More information about the pypy-commit mailing list