Author: Armin Rigo <[email protected]>
Branch: py3.5
Changeset: r91998:2ae11d0d2965
Date: 2017-07-31 14:13 +0200
http://bitbucket.org/pypy/pypy/changeset/2ae11d0d2965/
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
@@ -5,6 +5,14 @@
.. this is a revision shortly after release-pypy2.7-v5.8.0
.. startrev: 558bd00b3dd8
+In previous versions of PyPy, ``instance.method`` would return always
+the same bound method object, when gotten out of the same instance (as
+far as ``is`` and ``id()`` can tell). CPython doesn't do that. Now
+PyPy, like CPython, returns a different bound method object every time.
+For ``type.method``, PyPy2 still returns always the same *unbound*
+method object; CPython does it for built-in types but not for
+user-defined types.
+
.. branch: cffi-complex
.. branch: cffi-char16-char32
diff --git a/pypy/objspace/std/bytesobject.py b/pypy/objspace/std/bytesobject.py
--- a/pypy/objspace/std/bytesobject.py
+++ b/pypy/objspace/std/bytesobject.py
@@ -2,8 +2,7 @@
from rpython.rlib import jit
from rpython.rlib.objectmodel import (
- compute_hash, compute_unique_id, import_from_mixin, newlist_hint,
- resizelist_hint)
+ compute_hash, compute_unique_id, import_from_mixin)
from rpython.rlib.rstring import StringBuilder
from pypy.interpreter.baseobjspace import W_Root
@@ -751,14 +750,40 @@
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', 'builder'],
+ 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 ''.join(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)
+ builder = StringBuilder(length_hint)
+ #
+ _from_byte_sequence_loop(space, w_iter, builder)
+ #
+ return builder.build()
+
+def _from_byte_sequence_loop(space, w_iter, builder):
+ w_type = space.type(w_iter)
+ while True:
+ _byteseq_jitdriver.jit_merge_point(w_type=w_type,
+ w_iter=w_iter,
+ builder=builder)
+ try:
+ w_item = space.next(w_iter)
+ except OperationError as e:
+ if not e.match(space, space.w_StopIteration):
+ raise
+ break
+ builder.append(space.byte_w(w_item))
W_BytesObject.typedef = TypeDef(
"bytes", None, None, "read",
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
@@ -466,6 +466,13 @@
raises(TypeError, b.extend, [object()])
raises(TypeError, b.extend, "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''
diff --git a/rpython/memory/gc/incminimark.py b/rpython/memory/gc/incminimark.py
--- a/rpython/memory/gc/incminimark.py
+++ b/rpython/memory/gc/incminimark.py
@@ -2308,6 +2308,7 @@
ll_assert(not (self.probably_young_objects_with_finalizers
.non_empty()),
"probably_young_objects_with_finalizers should be empty")
+ self.kept_alive_by_finalizer = r_uint(0)
if self.old_objects_with_finalizers.non_empty():
self.deal_with_objects_with_finalizers()
elif self.old_objects_with_weakrefs.non_empty():
@@ -2380,6 +2381,9 @@
# we currently have -- but no more than 'max_delta' more than
# we currently have.
total_memory_used = float(self.get_total_memory_used())
+ total_memory_used -= float(self.kept_alive_by_finalizer)
+ if total_memory_used < 0:
+ total_memory_used = 0
bounded = self.set_major_threshold_from(
min(total_memory_used * self.major_collection_threshold,
total_memory_used + self.max_delta),
@@ -2418,7 +2422,7 @@
self.execute_finalizers()
#END FINALIZING
else:
- pass #XXX which exception to raise here. Should be unreachable.
+ ll_assert(False, "bogus gc_state")
debug_print("stopping, now in gc state: ", GC_STATES[self.gc_state])
debug_stop("gc-collect-step")
@@ -2784,8 +2788,17 @@
def _bump_finalization_state_from_0_to_1(self, obj):
ll_assert(self._finalization_state(obj) == 0,
"unexpected finalization state != 0")
+ size_gc_header = self.gcheaderbuilder.size_gc_header
+ totalsize = size_gc_header + self.get_size(obj)
hdr = self.header(obj)
hdr.tid |= GCFLAG_FINALIZATION_ORDERING
+ # A bit hackish, but we will not count these objects as "alive"
+ # for the purpose of computing when the next major GC should
+ # occur. This is done for issue #2590: without this, if we
+ # allocate mostly objects with finalizers, the
+ # next_major_collection_threshold grows forever and actual
+ # memory usage is not bounded.
+ self.kept_alive_by_finalizer += raw_malloc_usage(totalsize)
def _recursively_bump_finalization_state_from_2_to_3(self, obj):
ll_assert(self._finalization_state(obj) == 2,
diff --git a/rpython/memory/gc/minimark.py b/rpython/memory/gc/minimark.py
--- a/rpython/memory/gc/minimark.py
+++ b/rpython/memory/gc/minimark.py
@@ -1636,6 +1636,7 @@
# with a finalizer and all objects reachable from there (and also
# moves some objects from 'objects_with_finalizers' to
# 'run_finalizers').
+ self.kept_alive_by_finalizer = r_uint(0)
if self.old_objects_with_finalizers.non_empty():
self.deal_with_objects_with_finalizers()
#
@@ -1678,6 +1679,9 @@
# we currently have -- but no more than 'max_delta' more than
# we currently have.
total_memory_used = float(self.get_total_memory_used())
+ total_memory_used -= float(self.kept_alive_by_finalizer)
+ if total_memory_used < 0:
+ total_memory_used = 0
bounded = self.set_major_threshold_from(
min(total_memory_used * self.major_collection_threshold,
total_memory_used + self.max_delta),
@@ -1999,8 +2003,11 @@
def _bump_finalization_state_from_0_to_1(self, obj):
ll_assert(self._finalization_state(obj) == 0,
"unexpected finalization state != 0")
+ size_gc_header = self.gcheaderbuilder.size_gc_header
+ totalsize = size_gc_header + self.get_size(obj)
hdr = self.header(obj)
hdr.tid |= GCFLAG_FINALIZATION_ORDERING
+ self.kept_alive_by_finalizer += raw_malloc_usage(totalsize)
def _recursively_bump_finalization_state_from_2_to_3(self, obj):
ll_assert(self._finalization_state(obj) == 2,
diff --git a/rpython/memory/test/test_minimark_gc.py
b/rpython/memory/test/test_minimark_gc.py
--- a/rpython/memory/test/test_minimark_gc.py
+++ b/rpython/memory/test/test_minimark_gc.py
@@ -1,3 +1,4 @@
+from rpython.rlib import rgc
from rpython.rlib.rarithmetic import LONG_BIT
from rpython.memory.test import test_semispace_gc
@@ -9,3 +10,39 @@
GC_CAN_SHRINK_BIG_ARRAY = False
GC_CAN_MALLOC_NONMOVABLE = True
BUT_HOW_BIG_IS_A_BIG_STRING = 11*WORD
+
+ def test_bounded_memory_when_allocating_with_finalizers(self):
+ # Issue #2590: when allocating a lot of objects with a finalizer
+ # and little else, the bounds in the (inc)minimark GC are not
+ # set up reasonably and the total memory usage grows without
+ # limit.
+ class B(object):
+ pass
+ b = B()
+ b.num_deleted = 0
+ class A(object):
+ def __init__(self):
+ fq.register_finalizer(self)
+ class FQ(rgc.FinalizerQueue):
+ Class = A
+ def finalizer_trigger(self):
+ while True:
+ a = self.next_dead()
+ if a is None:
+ break
+ b.num_deleted += 1
+ fq = FQ()
+ def f(x, y):
+ i = 0
+ alive_max = 0
+ while i < x:
+ i += 1
+ a = A()
+ a.x = a.y = a.z = i
+ #print i - b.num_deleted, b.num_deleted
+ alive = i - b.num_deleted
+ assert alive >= 0
+ alive_max = max(alive_max, alive)
+ return alive_max
+ res = self.interpret(f, [1000, 0])
+ assert res < 100
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit