Author: Armin Rigo <[email protected]>
Branch: invalidate-virtualrefs
Changeset: r44554:973208656591
Date: 2011-05-27 16:52 +0200
http://bitbucket.org/pypy/pypy/changeset/973208656591/
Log: A quick hack as a workaround for the current (hard) issue: introduce
"stack-critical code", enabled with a pair of macros from
rlib.rstack. When running such a "stack-critical" piece of code,
StackOverflows are never raised. Used to protect key pieces of the
reconstruction of data from a guard failure, where it is essential
that vrefinfo.continue_tracing() is called on all virtualrefs.
diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py
--- a/pypy/jit/metainterp/pyjitpl.py
+++ b/pypy/jit/metainterp/pyjitpl.py
@@ -4,7 +4,7 @@
from pypy.rlib.unroll import unrolling_iterable
from pypy.rlib.debug import debug_start, debug_stop, debug_print
from pypy.rlib.debug import make_sure_not_resized
-from pypy.rlib import nonconst
+from pypy.rlib import nonconst, rstack
from pypy.jit.metainterp import history, compile, resume
from pypy.jit.metainterp.history import Const, ConstInt, ConstPtr, ConstFloat
@@ -2054,10 +2054,16 @@
def initialize_state_from_guard_failure(self, resumedescr):
# guard failure: rebuild a complete MIFrame stack
- self.in_recursion = -1 # always one portal around
- self.history = history.History()
- inputargs_and_holes = self.rebuild_state_after_failure(resumedescr)
- self.history.inputargs = [box for box in inputargs_and_holes if box]
+ # This is stack-critical code: it must not be interrupted by
StackOverflow,
+ # otherwise the jit_virtual_refs are left in a dangling state.
+ rstack._stack_criticalcode_start()
+ try:
+ self.in_recursion = -1 # always one portal around
+ self.history = history.History()
+ inputargs_and_holes = self.rebuild_state_after_failure(resumedescr)
+ self.history.inputargs = [box for box in inputargs_and_holes if
box]
+ finally:
+ rstack._stack_criticalcode_stop()
def initialize_virtualizable(self, original_boxes):
vinfo = self.jitdriver_sd.virtualizable_info
diff --git a/pypy/jit/metainterp/resume.py b/pypy/jit/metainterp/resume.py
--- a/pypy/jit/metainterp/resume.py
+++ b/pypy/jit/metainterp/resume.py
@@ -6,7 +6,7 @@
from pypy.jit.metainterp import jitprof
from pypy.jit.codewriter.effectinfo import EffectInfo
from pypy.rpython.lltypesystem import lltype, llmemory, rffi, rstr
-from pypy.rlib import rarithmetic
+from pypy.rlib import rarithmetic, rstack
from pypy.rlib.objectmodel import we_are_translated, specialize
from pypy.rlib.debug import have_debug_prints, ll_assert
from pypy.rlib.debug import debug_start, debug_stop, debug_print
@@ -978,12 +978,18 @@
def blackhole_from_resumedata(blackholeinterpbuilder, jitdriver_sd, storage,
all_virtuals=None):
- resumereader = ResumeDataDirectReader(blackholeinterpbuilder.metainterp_sd,
- storage, all_virtuals)
- vinfo = jitdriver_sd.virtualizable_info
- ginfo = jitdriver_sd.greenfield_info
- vrefinfo = blackholeinterpbuilder.metainterp_sd.virtualref_info
- resumereader.consume_vref_and_vable(vrefinfo, vinfo, ginfo)
+ # The initialization is stack-critical code: it must not be interrupted by
+ # StackOverflow, otherwise the jit_virtual_refs are left in a dangling
state.
+ rstack._stack_criticalcode_start()
+ try:
+ resumereader =
ResumeDataDirectReader(blackholeinterpbuilder.metainterp_sd,
+ storage, all_virtuals)
+ vinfo = jitdriver_sd.virtualizable_info
+ ginfo = jitdriver_sd.greenfield_info
+ vrefinfo = blackholeinterpbuilder.metainterp_sd.virtualref_info
+ resumereader.consume_vref_and_vable(vrefinfo, vinfo, ginfo)
+ finally:
+ rstack._stack_criticalcode_stop()
#
# First get a chain of blackhole interpreters whose length is given
# by the depth of rd_frame_info_list. The first one we get must be
diff --git a/pypy/rlib/rstack.py b/pypy/rlib/rstack.py
--- a/pypy/rlib/rstack.py
+++ b/pypy/rlib/rstack.py
@@ -56,6 +56,12 @@
_stack_get_end_adr = llexternal('LL_stack_get_end_adr', [], lltype.Signed)
_stack_get_length_adr= llexternal('LL_stack_get_length_adr',[], lltype.Signed)
+# the following is also used by the JIT: "critical code" paths are paths in
+# which we should not raise StackOverflow at all, but just ignore the stack
limit
+_stack_criticalcode_start = llexternal('LL_stack_criticalcode_start', [],
+ lltype.Void, lambda: None)
+_stack_criticalcode_stop = llexternal('LL_stack_criticalcode_stop', [],
+ lltype.Void, lambda: None)
def stack_check():
if not we_are_translated():
diff --git a/pypy/translator/c/src/stack.h b/pypy/translator/c/src/stack.h
--- a/pypy/translator/c/src/stack.h
+++ b/pypy/translator/c/src/stack.h
@@ -13,6 +13,7 @@
extern char *_LLstacktoobig_stack_end;
extern long _LLstacktoobig_stack_length;
+extern char _LLstacktoobig_report_error;
void LL_stack_unwind(void);
char LL_stack_too_big_slowpath(long); /* returns 0 (ok) or 1 (too big) */
@@ -24,6 +25,9 @@
#define LL_stack_get_end_adr() ((long)&_LLstacktoobig_stack_end) /* JIT */
#define LL_stack_get_length_adr() ((long)&_LLstacktoobig_stack_length)/* JIT */
+#define LL_stack_criticalcode_start() (_LLstacktoobig_report_error = 0)
+#define LL_stack_criticalcode_stop() (_LLstacktoobig_report_error = 1)
+
#ifdef __GNUC__
# define PYPY_INHIBIT_TAIL_CALL() asm("/* inhibit_tail_call */")
@@ -39,6 +43,7 @@
stack that grows downward here. */
char *_LLstacktoobig_stack_end = NULL;
long _LLstacktoobig_stack_length = MAX_STACK_SIZE;
+char _LLstacktoobig_report_error = 1;
static RPyThreadStaticTLS end_tls_key;
void LL_stack_set_length_fraction(double fraction)
@@ -86,8 +91,9 @@
/* stack underflowed: the initial estimation of
the stack base must be revised */
}
- else
- return 1; /* stack overflow (probably) */
+ else { /* stack overflow (probably) */
+ return _LLstacktoobig_report_error;
+ }
}
/* update the stack base pointer to the current value */
diff --git a/pypy/translator/c/test/test_standalone.py
b/pypy/translator/c/test/test_standalone.py
--- a/pypy/translator/c/test/test_standalone.py
+++ b/pypy/translator/c/test/test_standalone.py
@@ -727,6 +727,40 @@
assert counts[0.1] > counts[0.4] / 7
assert counts[0.4] > counts[1.0] / 4
+ def test_stack_criticalcode(self):
+ # check for pypy.rlib.rstack._stack_criticalcode_start/stop()
+ from pypy.rlib.rstack import _stack_criticalcode_start
+ from pypy.rlib.rstack import _stack_criticalcode_stop
+ from pypy.rlib.rstackovf import StackOverflow
+ class A:
+ pass
+ glob = A()
+ def f(n):
+ if n <= 0:
+ return 42
+ try:
+ return f(n+1)
+ except StackOverflow:
+ if glob.caught:
+ print 'Oups! already caught!'
+ glob.caught = True
+ _stack_criticalcode_start()
+ critical(100) # recurse another 100 times here
+ _stack_criticalcode_stop()
+ return 789
+ def critical(n):
+ if n > 0:
+ n = critical(n - 1)
+ return n - 42
+ def entry_point(argv):
+ glob.caught = False
+ print f(1)
+ return 0
+ t, cbuilder = self.compile(entry_point, stackcheck=True)
+ out = cbuilder.cmdexec('')
+ assert out.strip() == '789'
+
+
class TestMaemo(TestStandalone):
def setup_class(cls):
py.test.skip("TestMaemo: tests skipped for now")
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit