Author: Jasper.Schulz <[email protected]>
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
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit