Author: Jasper.Schulz <jasper.b.sch...@gmail.com> Branch: reorder-map-attributes Changeset: r82172:835464e0677c Date: 2016-02-11 15:55 +0000 http://bitbucket.org/pypy/pypy/changeset/835464e0677c/
Log: (cfbolz, jbs): turned revursive algorithm into iterative one to eliminate stack overflow diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py --- a/pypy/objspace/std/mapdict.py +++ b/pypy/objspace/std/mapdict.py @@ -160,15 +160,9 @@ if self.cache_attrs is not None: return self.cache_attrs.get(key, None) return None - - @jit.look_inside_iff(lambda self, obj, name, index, w_value: - jit.isconstant(self) and - jit.isconstant(name) and - jit.isconstant(index)) + def add_attr(self, obj, name, index, w_value): - reordered = self._try_reorder_and_add(obj, name, index, w_value) - if reordered == NOT_REORDERED: - self._add_attr_without_reordering(obj, name, index, w_value) + self._reorder_and_add(obj, name, index, w_value) if not jit.we_are_jitted(): oldattr = self attr = obj._get_mapdict_map() @@ -181,6 +175,7 @@ attr = self._get_new_attr(name, index) attr._switch_map_and_write_storage(obj, w_value) + @jit.unroll_safe def _switch_map_and_write_storage(self, obj, w_value): if self.length() > obj._mapdict_storage_length(): # note that self.size_estimate() is always at least self.length() @@ -194,27 +189,51 @@ obj._set_mapdict_map(self) obj._mapdict_write_storage(self.storageindex, w_value) - def _try_reorder_and_add(self, obj, name, index, w_value): - attr = self._get_cache_attr(name, index) - if attr is not None: - attr._switch_map_and_write_storage(obj, w_value) - return JUST_REORDERED + @jit.look_inside_iff(lambda self, obj, name, index, w_value: + jit.isconstant(self) and + jit.isconstant(name) and + jit.isconstant(index)) + def _reorder_and_add(self, obj, name, index, w_value): + stack = [] + while True: + current = self + localstack = [] + while True: + attr = current._get_cache_attr(name, index) + if attr is None: + # if not found in all ancestors + if not isinstance(current, PlainAttribute): + self._add_attr_without_reordering(obj, name, index, w_value) + break - elif isinstance(self, PlainAttribute): - w_self_value = obj._mapdict_read_storage(self.storageindex) - reordered = self.back._try_reorder_and_add(obj, name, index, w_value) - if reordered == JUST_REORDERED: - obj._get_mapdict_map()._add_attr_without_reordering( - obj, self.name, self.index, w_self_value) - elif reordered == SOMEWHERE_REORDERED: - obj._get_mapdict_map().add_attr(obj, self.name, self.index, w_self_value) - else: - assert reordered == NOT_REORDERED - return NOT_REORDERED - return SOMEWHERE_REORDERED - else: - # we are terminator - return NOT_REORDERED + # if not found try parent + else: + w_self_value = obj._mapdict_read_storage(current.storageindex) + localstack.append((current, w_self_value)) + current = current.back + else: + attr._switch_map_and_write_storage(obj, w_value) + stack.extend(localstack) + break + + if not stack: + return + + # add the first attribute of the stack without reordering + # to prevent an endless loop + next_map, w_value = stack.pop() + obj._get_mapdict_map()._add_attr_without_reordering( + obj, next_map.name, next_map.index, w_value) + + if not stack: + return + + # readd all other values from the stack (with reordering) + # the last element of the stack will be the new current + next_map, w_value = stack.pop() + name = next_map.name + index = next_map.index + self = obj._get_mapdict_map() def materialize_r_dict(self, space, obj, dict_w): raise NotImplementedError("abstract base class") diff --git a/pypy/objspace/std/test/test_mapdict.py b/pypy/objspace/std/test/test_mapdict.py --- a/pypy/objspace/std/test/test_mapdict.py +++ b/pypy/objspace/std/test/test_mapdict.py @@ -171,6 +171,12 @@ assert obj.map is obj5.map assert obj.map is obj6.map +def test_bug_stack_overflow_insert_attributes(): + cls = Class() + obj = cls.instantiate() + + for i in range(1000): + obj.setdictvalue(space, str(i), i) def test_insert_different_orders_perm(): from itertools import permutations _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit