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

Reply via email to