[pypy-commit] pypy optresult: Add and use a helper module that delays recursive calls, to turn them
arigo
noreply at buildbot.pypy.org
Fri Jun 5 10:51:24 CEST 2015
Author: Armin Rigo <arigo at tunes.org>
Branch: optresult
Changeset: r77890:b3cb86b784a3
Date: 2015-06-05 10:36 +0200
http://bitbucket.org/pypy/pypy/changeset/b3cb86b784a3/
Log: Add and use a helper module that delays recursive calls, to turn
them non-recursive.
diff --git a/rpython/annotator/bookkeeper.py b/rpython/annotator/bookkeeper.py
--- a/rpython/annotator/bookkeeper.py
+++ b/rpython/annotator/bookkeeper.py
@@ -21,6 +21,7 @@
from rpython.annotator.argument import simple_args
from rpython.rlib.objectmodel import r_dict, r_ordereddict, Symbolic
from rpython.tool.algo.unionfind import UnionFind
+from rpython.tool.flattenrec import FlattenRecursion
from rpython.rtyper import extregistry
@@ -426,6 +427,8 @@
self.methoddescs[key] = result
return result
+ _see_mutable_flattenrec = FlattenRecursion()
+
def see_mutable(self, x):
key = (x.__class__, x)
if key in self.seen_mutable:
@@ -434,8 +437,11 @@
self.seen_mutable[key] = True
self.event('mutable', x)
source = InstanceSource(self, x)
- for attr in source.all_instance_attributes():
- clsdef.add_source_for_attribute(attr, source) # can trigger reflowing
+ def delayed():
+ for attr in source.all_instance_attributes():
+ clsdef.add_source_for_attribute(attr, source)
+ # ^^^ can trigger reflowing
+ self._see_mutable_flattenrec(delayed)
def valueoftype(self, t):
return annotationoftype(t, self)
diff --git a/rpython/rtyper/rclass.py b/rpython/rtyper/rclass.py
--- a/rpython/rtyper/rclass.py
+++ b/rpython/rtyper/rclass.py
@@ -7,6 +7,7 @@
from rpython.rlib.objectmodel import UnboxedValue
from rpython.tool.pairtype import pairtype, pair
from rpython.tool.identity_dict import identity_dict
+from rpython.tool.flattenrec import FlattenRecursion
from rpython.rtyper.extregistry import ExtRegistryEntry
from rpython.rtyper.error import TyperError
from rpython.rtyper.lltypesystem import lltype
@@ -767,11 +768,14 @@
self.initialize_prebuilt_data(Ellipsis, self.classdef, result)
return result
+ _initialize_data_flattenrec = FlattenRecursion()
+
def initialize_prebuilt_instance(self, value, classdef, result):
# must fill in the hash cache before the other ones
# (see test_circular_hash_initialization)
self.initialize_prebuilt_hash(value, result)
- self.initialize_prebuilt_data(value, classdef, result)
+ self._initialize_data_flattenrec(self.initialize_prebuilt_data,
+ value, classdef, result)
def get_ll_hash_function(self):
return ll_inst_hash
diff --git a/rpython/rtyper/test/test_rclass.py b/rpython/rtyper/test/test_rclass.py
--- a/rpython/rtyper/test/test_rclass.py
+++ b/rpython/rtyper/test/test_rclass.py
@@ -1279,3 +1279,16 @@
return cls[k](a, b).b
assert self.interpret(f, [1, 4, 7]) == 7
+
+ def test_flatten_convert_const(self):
+ # check that we can convert_const() a chain of more than 1000
+ # instances
+ class A(object):
+ def __init__(self, next):
+ self.next = next
+ a = None
+ for i in range(1500):
+ a = A(a)
+ def f():
+ return a.next.next.next.next is not None
+ assert self.interpret(f, []) == True
diff --git a/rpython/tool/flattenrec.py b/rpython/tool/flattenrec.py
new file mode 100644
--- /dev/null
+++ b/rpython/tool/flattenrec.py
@@ -0,0 +1,25 @@
+"""
+A general way to flatten deeply recursive algorithms by delaying some
+parts until later.
+"""
+
+
+class FlattenRecursion(object):
+
+ def __init__(self):
+ self.later = None
+
+ def __call__(self, func, *args, **kwds):
+ """Call func(*args, **kwds), either now, or, if we're recursing,
+ then the call will be done later by the first level.
+ """
+ if self.later is not None:
+ self.later.append((func, args, kwds))
+ else:
+ self.later = lst = []
+ try:
+ func(*args, **kwds)
+ for func, args, kwds in lst:
+ func(*args, **kwds)
+ finally:
+ self.later = None
diff --git a/rpython/tool/test/test_flattenrec.py b/rpython/tool/test/test_flattenrec.py
new file mode 100644
--- /dev/null
+++ b/rpython/tool/test/test_flattenrec.py
@@ -0,0 +1,13 @@
+from rpython.tool.flattenrec import FlattenRecursion
+
+def test_flattenrec():
+ r = FlattenRecursion()
+ seen = set()
+
+ def rec(n):
+ if n > 0:
+ r(rec, n-1)
+ seen.add(n)
+
+ rec(10000)
+ assert seen == set(range(10001))
More information about the pypy-commit
mailing list