[pypy-svn] r78133 - in pypy/trunk/pypy/translator: . c c/src c/test
arigo at codespeak.net
arigo at codespeak.net
Wed Oct 20 15:54:18 CEST 2010
Author: arigo
Date: Wed Oct 20 15:54:16 2010
New Revision: 78133
Modified:
pypy/trunk/pypy/translator/c/funcgen.py
pypy/trunk/pypy/translator/c/src/stack.h
pypy/trunk/pypy/translator/c/test/test_genc.py
pypy/trunk/pypy/translator/c/test/test_standalone.py
pypy/trunk/pypy/translator/transform.py
Log:
(antocuni, arigo)
Hopefully fix lib-python/.../test_descr on 64-bit platforms. The issue
is that we can get a cycle of tail recursions (more easily on x86-64
than on x86-32), and in such cycles, the stack overflow detection does
not work as a way to interrupt the cycle. Thus we can get caught in
what seems like an infinite recursion (but is not in C).
Modified: pypy/trunk/pypy/translator/c/funcgen.py
==============================================================================
--- pypy/trunk/pypy/translator/c/funcgen.py (original)
+++ pypy/trunk/pypy/translator/c/funcgen.py Wed Oct 20 15:54:16 2010
@@ -427,7 +427,7 @@
r = self.expr(op.result)
return 'OP_CALL_ARGS((%s), %s);' % (', '.join(args), r)
- def generic_call(self, FUNC, fnexpr, args_v, v_result):
+ def generic_call(self, FUNC, fnexpr, args_v, v_result, targets=None):
args = []
assert len(args_v) == len(FUNC.TO.ARGS)
for v, ARGTYPE in zip(args_v, FUNC.TO.ARGS):
@@ -444,17 +444,23 @@
# skip assignment of 'void' return value
r = self.expr(v_result)
line = '%s = %s' % (r, line)
+ if targets:
+ for func in targets:
+ graph = getattr(func._obj, 'graph', None)
+ if getattr(graph, 'inhibit_tail_call', False):
+ line += '\nPYPY_INHIBIT_TAIL_CALL();'
+ break
return line
def OP_DIRECT_CALL(self, op):
fn = op.args[0]
return self.generic_call(fn.concretetype, self.expr(fn),
- op.args[1:], op.result)
+ op.args[1:], op.result, [fn.value])
def OP_INDIRECT_CALL(self, op):
fn = op.args[0]
return self.generic_call(fn.concretetype, self.expr(fn),
- op.args[1:-1], op.result)
+ op.args[1:-1], op.result, op.args[-1].value)
def OP_ADR_CALL(self, op):
ARGTYPES = [v.concretetype for v in op.args[1:]]
Modified: pypy/trunk/pypy/translator/c/src/stack.h
==============================================================================
--- pypy/trunk/pypy/translator/c/src/stack.h (original)
+++ pypy/trunk/pypy/translator/c/src/stack.h Wed Oct 20 15:54:16 2010
@@ -33,6 +33,12 @@
&& LL_stack_too_big_slowpath());
}
+#ifdef __GNUC__
+# define PYPY_INHIBIT_TAIL_CALL() asm("/* inhibit_tail_call */")
+#else
+# define PYPY_INHIBIT_TAIL_CALL() /* add hints for other compilers here */
+#endif
+
#ifndef PYPY_NOT_MAIN_FILE
#include <stdio.h>
Modified: pypy/trunk/pypy/translator/c/test/test_genc.py
==============================================================================
--- pypy/trunk/pypy/translator/c/test/test_genc.py (original)
+++ pypy/trunk/pypy/translator/c/test/test_genc.py Wed Oct 20 15:54:16 2010
@@ -478,3 +478,23 @@
t.bar = llhelper(FTPTR, a_f.make_func())
fn = compile(chooser, [bool])
assert fn(True)
+
+def test_inhibit_tail_call():
+ from pypy.rpython.lltypesystem import lltype
+ def foobar_fn(n):
+ return 42
+ foobar_fn._dont_inline_ = True
+ def main(n):
+ return foobar_fn(n)
+ #
+ t = Translation(main, [int], backend="c")
+ t.rtype()
+ t.context._graphof(foobar_fn).inhibit_tail_call = True
+ t.source_c()
+ lines = t.driver.cbuilder.c_source_filename.readlines()
+ for i, line in enumerate(lines):
+ if '= pypy_g_foobar_fn' in line:
+ break
+ else:
+ assert 0, "the call was not found in the C source"
+ assert 'PYPY_INHIBIT_TAIL_CALL();' in lines[i+1]
Modified: pypy/trunk/pypy/translator/c/test/test_standalone.py
==============================================================================
--- pypy/trunk/pypy/translator/c/test/test_standalone.py (original)
+++ pypy/trunk/pypy/translator/c/test/test_standalone.py Wed Oct 20 15:54:16 2010
@@ -16,11 +16,16 @@
class StandaloneTests(object):
config = None
- def compile(self, entry_point, debug=True, shared=False):
+ def compile(self, entry_point, debug=True, shared=False,
+ stackcheck=False):
t = TranslationContext(self.config)
t.buildannotator().build_types(entry_point, [s_list_of_strings])
t.buildrtyper().specialize()
+ if stackcheck:
+ from pypy.translator.transform import insert_ll_stackcheck
+ insert_ll_stackcheck(t)
+
t.config.translation.shared = shared
cbuilder = CStandaloneBuilder(t, entry_point, t.config)
@@ -630,6 +635,22 @@
else:
os.environ['CC'] = old_cc
+ def test_inhibit_tail_call(self):
+ # the point is to check that the f()->f() recursion stops
+ from pypy.rlib.rstackovf import StackOverflow
+ def f(n):
+ if n <= 0:
+ return 42
+ return f(n+1)
+ def entry_point(argv):
+ try:
+ return f(1)
+ except StackOverflow:
+ print 'hi!'
+ return 0
+ t, cbuilder = self.compile(entry_point, stackcheck=True)
+ out = cbuilder.cmdexec("")
+ assert out.strip() == "hi!"
class TestMaemo(TestStandalone):
def setup_class(cls):
Modified: pypy/trunk/pypy/translator/transform.py
==============================================================================
--- pypy/trunk/pypy/translator/transform.py (original)
+++ pypy/trunk/pypy/translator/transform.py Wed Oct 20 15:54:16 2010
@@ -221,15 +221,19 @@
stack_check_ptr_const = Constant(stack_check_ptr, lltype.typeOf(stack_check_ptr))
edges = set()
insert_in = set()
+ block2graph = {}
for caller in translator.graphs:
for block, callee in find_calls_from(translator, caller):
if getattr(getattr(callee, 'func', None),
'insert_stack_check_here', False):
insert_in.add(callee.startblock)
+ block2graph[callee.startblock] = callee
continue
if block is not caller.startblock:
edges.add((caller.startblock, block))
+ block2graph[caller.startblock] = caller
edges.add((block, callee.startblock))
+ block2graph[block] = caller
edgelist = [Edge(block1, block2) for (block1, block2) in edges]
edgedict = make_edge_dict(edgelist)
@@ -241,6 +245,10 @@
v.concretetype = lltype.Void
unwind_op = SpaceOperation('direct_call', [stack_check_ptr_const], v)
block.operations.insert(0, unwind_op)
+ # prevents cycles of tail calls from occurring -- such cycles would
+ # not consume any stack, so would turn into potentially infinite loops
+ graph = block2graph[block]
+ graph.inhibit_tail_call = True
return len(insert_in)
More information about the Pypy-commit
mailing list