[pypy-commit] pypy py3k: avoid triggering the now lazy __context__ setup 'up front' (when grabbing it
pjenvey
noreply at buildbot.pypy.org
Wed Jun 18 23:06:33 CEST 2014
Author: Philip Jenvey <pjenvey at underboss.org>
Branch: py3k
Changeset: r72098:3856e33d85ad
Date: 2014-06-18 13:09 -0700
http://bitbucket.org/pypy/pypy/changeset/3856e33d85ad/
Log: 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
diff --git a/pypy/interpreter/error.py b/pypy/interpreter/error.py
--- a/pypy/interpreter/error.py
+++ b/pypy/interpreter/error.py
@@ -332,15 +332,16 @@
# 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
@@ -349,15 +350,16 @@
# 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
diff --git a/pypy/interpreter/test/test_raise.py b/pypy/interpreter/test/test_raise.py
--- a/pypy/interpreter/test/test_raise.py
+++ b/pypy/interpreter/test/test_raise.py
@@ -385,6 +385,27 @@
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:
More information about the pypy-commit
mailing list