1. Pypy
  2. Untitled project
  3. pypy

Commits

Philip Jenvey  committed 3856e33

avoid triggering the now lazy __context__ setup 'up front' (when grabbing it
from the current frame) when breaking __context__ chain cycles, for now. this
is a trade-off: we won't break some cycles in obscure situations for the sake
of not paying a cost in probably more situations

  • Participants
  • Parent commits 53a145f
  • Branches py3k

Comments (0)

Files changed (2)

File pypy/interpreter/error.py

View file
             # normalize w_value so setup_context can check for cycles
             self.normalize_exception(space)
             w_value = self.get_w_value(space)
-            w_context = setup_context(space, w_value,
-                                      last_exception.get_w_value(space))
+            w_last = last_exception.get_w_value(space)
+            w_context = setup_context(space, w_value, w_last, lazy=True)
             space.setattr(w_value, space.wrap('__context__'), w_context)
 
 
-def setup_context(space, w_exc, w_last):
+def setup_context(space, w_exc, w_last, lazy=False):
     """Determine the __context__ for w_exc from w_last and break
     reference cycles in the __context__ chain.
     """
+    from pypy.module.exceptions.interp_exceptions import W_BaseException
     if space.is_w(w_exc, w_last):
         w_last = space.w_None
     # w_last may also be space.w_None if from ClearedOpErr
         # O(chain length) but context chains are usually very short.
         w_obj = w_last
         while True:
-            # XXX: __context__ becomes not so lazy when we're forced to
-            # access it here! Could this be defered till later? Or at
-            # least limit the check to W_BaseException.w_context
-            # (avoiding W_BaseException._setup_context)
-            w_context = space.getattr(w_obj, space.wrap('__context__'))
-            if space.is_w(w_context, space.w_None):
+            assert isinstance(w_obj, W_BaseException)
+            if lazy:
+                w_context = w_obj.w_context
+            else:
+                # triggers W_BaseException._setup_context
+                w_context = space.getattr(w_obj, space.wrap('__context__'))
+            if space.is_none(w_context):
                 break
             if space.is_w(w_context, w_exc):
-                space.setattr(w_obj, space.wrap('__context__'), space.w_None)
+                w_obj.w_context = space.w_None
                 break
             w_obj = w_context
     return w_last

File pypy/interpreter/test/test_raise.py

View file
         except:
             func1()
 
+    @py.test.mark.xfail(reason="A somewhat contrived case that may burden the "
+                        "JIT to fully support")
+    def test_frame_spanning_cycle_broken(self):
+        context = IndexError()
+        def func():
+            try:
+                1/0
+            except Exception as e1:
+                try:
+                    raise context
+                except Exception as e2:
+                    assert e2.__context__ is e1
+                    # XXX:
+                    assert e1.__context__ is None
+            else:
+                fail('No exception raised')
+        try:
+            raise context
+        except:
+            func()
+
 
 class AppTestTraceback: