[pypy-commit] pypy default: merge

fijal noreply at buildbot.pypy.org
Fri Mar 30 20:21:29 CEST 2012


Author: Maciej Fijalkowski <fijall at gmail.com>
Branch: 
Changeset: r54103:4198f84765dd
Date: 2012-03-30 20:21 +0200
http://bitbucket.org/pypy/pypy/changeset/4198f84765dd/

Log:	merge

diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -296,6 +296,7 @@
         self.check_signal_action = None   # changed by the signal module
         self.user_del_action = UserDelAction(self)
         self.frame_trace_action = FrameTraceAction(self)
+        self._code_of_sys_exc_info = None
 
         from pypy.interpreter.pycode import cpython_magic, default_magic
         self.our_magic = default_magic
diff --git a/pypy/interpreter/executioncontext.py b/pypy/interpreter/executioncontext.py
--- a/pypy/interpreter/executioncontext.py
+++ b/pypy/interpreter/executioncontext.py
@@ -154,6 +154,7 @@
         #operationerr.print_detailed_traceback(self.space)
 
     def _convert_exc(self, operr):
+        # Only for the flow object space
         return operr
 
     def sys_exc_info(self): # attn: the result is not the wrapped sys.exc_info() !!!
diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py
--- a/pypy/interpreter/function.py
+++ b/pypy/interpreter/function.py
@@ -113,6 +113,12 @@
         from pypy.interpreter.pycode import PyCode
 
         code = self.getcode() # hook for the jit
+        #
+        if (jit.we_are_jitted() and code is self.space._code_of_sys_exc_info
+                                and nargs == 0):
+            from pypy.module.sys.vm import exc_info_direct
+            return exc_info_direct(self.space, frame)
+        #
         fast_natural_arity = code.fast_natural_arity
         if nargs == fast_natural_arity:
             if nargs == 0:
diff --git a/pypy/interpreter/gateway.py b/pypy/interpreter/gateway.py
--- a/pypy/interpreter/gateway.py
+++ b/pypy/interpreter/gateway.py
@@ -874,6 +874,12 @@
             fn.add_to_table()
         if gateway.as_classmethod:
             fn = ClassMethod(space.wrap(fn))
+        #
+        from pypy.module.sys.vm import exc_info
+        if code._bltin is exc_info:
+            assert space._code_of_sys_exc_info is None
+            space._code_of_sys_exc_info = code
+        #
         return fn
 
 
diff --git a/pypy/module/array/interp_array.py b/pypy/module/array/interp_array.py
--- a/pypy/module/array/interp_array.py
+++ b/pypy/module/array/interp_array.py
@@ -11,7 +11,7 @@
 from pypy.objspace.std.register_all import register_all
 from pypy.rlib.rarithmetic import ovfcheck
 from pypy.rlib.unroll import unrolling_iterable
-from pypy.rlib.objectmodel import specialize
+from pypy.rlib.objectmodel import specialize, keepalive_until_here
 from pypy.rpython.lltypesystem import lltype, rffi
 
 
@@ -145,18 +145,24 @@
 unroll_typecodes = unrolling_iterable(types.keys())
 
 class ArrayBuffer(RWBuffer):
-    def __init__(self, data, bytes):
-        self.data = data
-        self.len = bytes
+    def __init__(self, array):
+        self.array = array
 
     def getlength(self):
-        return self.len
+        return self.array.len * self.array.itemsize
 
     def getitem(self, index):
-        return self.data[index]
+        array = self.array
+        data = array._charbuf_start()
+        char = data[index]
+        array._charbuf_stop()
+        return char
 
     def setitem(self, index, char):
-        self.data[index] = char
+        array = self.array
+        data = array._charbuf_start()
+        data[index] = char
+        array._charbuf_stop()
 
 
 def make_array(mytype):
@@ -278,9 +284,10 @@
             oldlen = self.len
             new = len(s) / mytype.bytes
             self.setlen(oldlen + new)
-            cbuf = self.charbuf()
+            cbuf = self._charbuf_start()
             for i in range(len(s)):
                 cbuf[oldlen * mytype.bytes + i] = s[i]
+            self._charbuf_stop()
 
         def fromlist(self, w_lst):
             s = self.len
@@ -310,8 +317,11 @@
             else:
                 self.fromsequence(w_iterable)
 
-        def charbuf(self):
-            return  rffi.cast(rffi.CCHARP, self.buffer)
+        def _charbuf_start(self):
+            return rffi.cast(rffi.CCHARP, self.buffer)
+
+        def _charbuf_stop(self):
+            keepalive_until_here(self)
 
         def w_getitem(self, space, idx):
             item = self.buffer[idx]
@@ -530,8 +540,10 @@
         self.fromstring(space.str_w(w_s))
 
     def array_tostring__Array(space, self):
-        cbuf = self.charbuf()
-        return self.space.wrap(rffi.charpsize2str(cbuf, self.len * mytype.bytes))
+        cbuf = self._charbuf_start()
+        s = rffi.charpsize2str(cbuf, self.len * mytype.bytes)
+        self._charbuf_stop()
+        return self.space.wrap(s)
 
     def array_fromfile__Array_ANY_ANY(space, self, w_f, w_n):
         if not isinstance(w_f, W_File):
@@ -613,8 +625,7 @@
     # Misc methods
 
     def buffer__Array(space, self):
-        b = ArrayBuffer(self.charbuf(), self.len * mytype.bytes)
-        return space.wrap(b)
+        return space.wrap(ArrayBuffer(self))
 
     def array_buffer_info__Array(space, self):
         w_ptr = space.wrap(rffi.cast(lltype.Unsigned, self.buffer))
@@ -649,7 +660,7 @@
             raise OperationError(space.w_RuntimeError, space.wrap(msg))
         if self.len == 0:
             return
-        bytes = self.charbuf()
+        bytes = self._charbuf_start()
         tmp = [bytes[0]] * mytype.bytes
         for start in range(0, self.len * mytype.bytes, mytype.bytes):
             stop = start + mytype.bytes - 1
@@ -657,6 +668,7 @@
                 tmp[i] = bytes[start + i]
             for i in range(mytype.bytes):
                 bytes[stop - i] = tmp[i]
+        self._charbuf_stop()
 
     def repr__Array(space, self):
         if self.len == 0:
diff --git a/pypy/module/array/test/test_array.py b/pypy/module/array/test/test_array.py
--- a/pypy/module/array/test/test_array.py
+++ b/pypy/module/array/test/test_array.py
@@ -433,7 +433,25 @@
         a = self.array('h', 'Hi')
         buf = buffer(a)
         assert buf[1] == 'i'
-        #raises(TypeError, buf.__setitem__, 1, 'o')
+
+    def test_buffer_write(self):
+        a = self.array('c', 'hello')
+        buf = buffer(a)
+        print repr(buf)
+        try:
+            buf[3] = 'L'
+        except TypeError:
+            skip("buffer(array) returns a read-only buffer on CPython")
+        assert a.tostring() == 'helLo'
+
+    def test_buffer_keepalive(self):
+        buf = buffer(self.array('c', 'text'))
+        assert buf[2] == 'x'
+        #
+        a = self.array('c', 'foobarbaz')
+        buf = buffer(a)
+        a.fromstring('some extra text')
+        assert buf[:] == 'foobarbazsome extra text'
 
     def test_list_methods(self):
         assert repr(self.array('i')) == "array('i')"
diff --git a/pypy/module/cpyext/bufferobject.py b/pypy/module/cpyext/bufferobject.py
--- a/pypy/module/cpyext/bufferobject.py
+++ b/pypy/module/cpyext/bufferobject.py
@@ -4,6 +4,8 @@
     PyObjectFields, PyObject)
 from pypy.module.cpyext.pyobject import make_typedescr, Py_DecRef
 from pypy.interpreter.buffer import Buffer, StringBuffer, SubBuffer
+from pypy.interpreter.error import OperationError
+from pypy.module.array.interp_array import ArrayBuffer
 
 
 PyBufferObjectStruct = lltype.ForwardReference()
@@ -43,10 +45,15 @@
 
     if isinstance(w_obj, StringBuffer):
         py_buf.c_b_base = rffi.cast(PyObject, 0) # space.wrap(w_obj.value)
-        py_buf.c_b_ptr = rffi.cast(rffi.VOIDP, rffi.str2charp(w_obj.as_str()))
+        py_buf.c_b_ptr = rffi.cast(rffi.VOIDP, rffi.str2charp(w_obj.value))
+        py_buf.c_b_size = w_obj.getlength()
+    elif isinstance(w_obj, ArrayBuffer):
+        py_buf.c_b_base = rffi.cast(PyObject, 0) # space.wrap(w_obj.value)
+        py_buf.c_b_ptr = rffi.cast(rffi.VOIDP, w_obj.data)
         py_buf.c_b_size = w_obj.getlength()
     else:
-        raise Exception("Fail fail fail fail fail")
+        raise OperationError(space.w_NotImplementedError, space.wrap(
+            "buffer flavor not supported"))
 
 
 def buffer_realize(space, py_obj):
diff --git a/pypy/module/cpyext/test/test_bufferobject.py b/pypy/module/cpyext/test/test_bufferobject.py
--- a/pypy/module/cpyext/test/test_bufferobject.py
+++ b/pypy/module/cpyext/test/test_bufferobject.py
@@ -48,3 +48,17 @@
             ])
         b = module.buffer_new()
         raises(AttributeError, getattr, b, 'x')
+
+    def test_array_buffer(self):
+        module = self.import_extension('foo', [
+            ("roundtrip", "METH_O",
+             """
+                 PyBufferObject *buf = (PyBufferObject *)args;
+                 return PyString_FromStringAndSize(buf->b_ptr, buf->b_size);
+             """),
+            ])
+        import array
+        a = array.array('c', 'text')
+        b = buffer(a)
+        assert module.roundtrip(b) == 'text'
+        
diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py
--- a/pypy/module/micronumpy/__init__.py
+++ b/pypy/module/micronumpy/__init__.py
@@ -99,6 +99,8 @@
         ("exp2", "exp2"),
         ("expm1", "expm1"),
         ("fabs", "fabs"),
+        ("fmax", "fmax"),
+        ("fmin", "fmin"),
         ("fmod", "fmod"),
         ("floor", "floor"),
         ("ceil", "ceil"),
@@ -122,12 +124,14 @@
         ("sinh", "sinh"),
         ("subtract", "subtract"),
         ('sqrt', 'sqrt'),
+        ('square', 'square'),
         ("tan", "tan"),
         ("tanh", "tanh"),
         ('bitwise_and', 'bitwise_and'),
         ('bitwise_or', 'bitwise_or'),
         ('bitwise_xor', 'bitwise_xor'),
         ('bitwise_not', 'invert'),
+        ('invert', 'invert'),
         ('isnan', 'isnan'),
         ('isinf', 'isinf'),
         ('isneginf', 'isneginf'),
diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py
--- a/pypy/module/micronumpy/interp_ufuncs.py
+++ b/pypy/module/micronumpy/interp_ufuncs.py
@@ -541,6 +541,8 @@
             ("reciprocal", "reciprocal", 1),
 
             ("fabs", "fabs", 1, {"promote_to_float": True}),
+            ("fmax", "fmax", 2, {"promote_to_float": True}),
+            ("fmin", "fmin", 2, {"promote_to_float": True}),
             ("fmod", "fmod", 2, {"promote_to_float": True}),
             ("floor", "floor", 1, {"promote_to_float": True}),
             ("ceil", "ceil", 1, {"promote_to_float": True}),
@@ -549,6 +551,7 @@
             ("expm1", "expm1", 1, {"promote_to_float": True}),
 
             ('sqrt', 'sqrt', 1, {'promote_to_float': True}),
+            ('square', 'square', 1, {'promote_to_float': True}),
 
             ("sin", "sin", 1, {"promote_to_float": True}),
             ("cos", "cos", 1, {"promote_to_float": True}),
diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py
--- a/pypy/module/micronumpy/test/test_ufuncs.py
+++ b/pypy/module/micronumpy/test/test_ufuncs.py
@@ -135,6 +135,38 @@
         assert fabs(float('-inf')) == float('inf')
         assert isnan(fabs(float('nan')))
 
+    def test_fmax(self):
+        from _numpypy import fmax
+        import math
+
+        nnan, nan, inf, ninf = float('-nan'), float('nan'), float('inf'), float('-inf')
+
+        a = [ninf, -5, 0, 5, inf]
+        assert (fmax(a, [ninf]*5) == a).all()
+        assert (fmax(a, [inf]*5) == [inf]*5).all()
+        assert (fmax(a, [1]*5) == [1, 1, 1, 5, inf]).all()
+        assert math.isnan(fmax(nan, 0))
+        assert math.isnan(fmax(0, nan))
+        assert math.isnan(fmax(nan, nan))
+        # The numpy docs specify that the FIRST NaN should be used if both are NaN
+        assert math.copysign(1.0, fmax(nnan, nan)) == -1.0
+
+    def test_fmin(self):
+        from _numpypy import fmin
+        import math
+
+        nnan, nan, inf, ninf = float('-nan'), float('nan'), float('inf'), float('-inf')
+
+        a = [ninf, -5, 0, 5, inf]
+        assert (fmin(a, [ninf]*5) == [ninf]*5).all()
+        assert (fmin(a, [inf]*5) == a).all()
+        assert (fmin(a, [1]*5) == [ninf, -5, 0, 1, 1]).all()
+        assert math.isnan(fmin(nan, 0))
+        assert math.isnan(fmin(0, nan))
+        assert math.isnan(fmin(nan, nan))
+        # The numpy docs specify that the FIRST NaN should be used if both are NaN
+        assert math.copysign(1.0, fmin(nnan, nan)) == -1.0
+
     def test_fmod(self):
         from _numpypy import fmod
         import math
@@ -455,6 +487,19 @@
         assert math.isnan(sqrt(-1))
         assert math.isnan(sqrt(nan))
 
+    def test_square(self):
+        import math
+        from _numpypy import square
+
+        nan, inf, ninf = float("nan"), float("inf"), float("-inf")
+
+        assert math.isnan(square(nan))
+        assert math.isinf(square(inf))
+        assert math.isinf(square(ninf))
+        assert square(ninf) > 0
+        assert [square(x) for x in range(-5, 5)] == [x*x for x in range(-5, 5)]
+        assert math.isinf(square(1e300))
+
     def test_radians(self):
         import math
         from _numpypy import radians, array
@@ -546,10 +591,11 @@
         raises(TypeError, 'array([1.0]) & 1')
 
     def test_unary_bitops(self):
-        from _numpypy import bitwise_not, array
+        from _numpypy import bitwise_not, invert, array
         a = array([1, 2, 3, 4])
         assert (~a == [-2, -3, -4, -5]).all()
         assert (bitwise_not(a) == ~a).all()
+        assert (invert(a) == ~a).all()
 
     def test_comparisons(self):
         import operator
diff --git a/pypy/module/micronumpy/types.py b/pypy/module/micronumpy/types.py
--- a/pypy/module/micronumpy/types.py
+++ b/pypy/module/micronumpy/types.py
@@ -631,6 +631,22 @@
         return math.fabs(v)
 
     @simple_binary_op
+    def fmax(self, v1, v2):
+        if math.isnan(v1):
+            return v1
+        elif math.isnan(v2):
+            return v2
+        return max(v1, v2)
+
+    @simple_binary_op
+    def fmin(self, v1, v2):
+        if math.isnan(v1):
+            return v1
+        elif math.isnan(v2):
+            return v2
+        return min(v1, v2)
+
+    @simple_binary_op
     def fmod(self, v1, v2):
         try:
             return math.fmod(v1, v2)
@@ -741,6 +757,10 @@
         except ValueError:
             return rfloat.NAN
 
+    @simple_unary_op
+    def square(self, v):
+        return v*v
+
     @raw_unary_op
     def isnan(self, v):
         return rfloat.isnan(v)
diff --git a/pypy/module/pypyjit/test_pypy_c/test_misc.py b/pypy/module/pypyjit/test_pypy_c/test_misc.py
--- a/pypy/module/pypyjit/test_pypy_c/test_misc.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_misc.py
@@ -351,3 +351,23 @@
         # the following assertion fails if the loop was cancelled due
         # to "abort: vable escape"
         assert len(log.loops_by_id("eval")) == 1
+
+    def test_sys_exc_info(self):
+        def main():
+            i = 1
+            lst = [i]
+            while i < 1000:
+                try:
+                    return lst[i]
+                except:
+                    e = sys.exc_info()[1]    # ID: exc_info
+                    if not isinstance(e, IndexError):
+                        raise
+                i += 1
+            return 42
+
+        log = self.run(main)
+        assert log.result == 42
+        # the following assertion fails if the loop was cancelled due
+        # to "abort: vable escape"
+        assert len(log.loops_by_id("exc_info")) == 1
diff --git a/pypy/module/sys/test/test_sysmodule.py b/pypy/module/sys/test/test_sysmodule.py
--- a/pypy/module/sys/test/test_sysmodule.py
+++ b/pypy/module/sys/test/test_sysmodule.py
@@ -595,3 +595,121 @@
         assert len(frames) == 1
         _, other_frame = frames.popitem()
         assert other_frame.f_code.co_name in ('other_thread', '?')
+
+
+class AppTestSysExcInfoDirect:
+
+    def setup_method(self, meth):
+        self.seen = []
+        from pypy.module.sys import vm
+        def exc_info_with_tb(*args):
+            self.seen.append("n")     # not optimized
+            return self.old[0](*args)
+        def exc_info_without_tb(*args):
+            self.seen.append("y")     # optimized
+            return self.old[1](*args)
+        self.old = [vm.exc_info_with_tb, vm.exc_info_without_tb]
+        vm.exc_info_with_tb = exc_info_with_tb
+        vm.exc_info_without_tb = exc_info_without_tb
+        #
+        from pypy.rlib import jit
+        self.old2 = [jit.we_are_jitted]
+        jit.we_are_jitted = lambda: True
+
+    def teardown_method(self, meth):
+        from pypy.module.sys import vm
+        from pypy.rlib import jit
+        vm.exc_info_with_tb = self.old[0]
+        vm.exc_info_without_tb = self.old[1]
+        jit.we_are_jitted = self.old2[0]
+        #
+        assert ''.join(self.seen) == meth.expected
+
+    def test_returns_none(self):
+        import sys
+        assert sys.exc_info() == (None, None, None)
+        assert sys.exc_info()[0] is None
+        assert sys.exc_info()[1] is None
+        assert sys.exc_info()[2] is None
+        assert sys.exc_info()[:2] == (None, None)
+        assert sys.exc_info()[:3] == (None, None, None)
+        assert sys.exc_info()[0:2] == (None, None)
+        assert sys.exc_info()[2:4] == (None,)
+    test_returns_none.expected = 'nnnnnnnn'
+
+    def test_returns_subscr(self):
+        import sys
+        e = KeyError("boom")
+        try:
+            raise e
+        except:
+            assert sys.exc_info()[0] is KeyError  # y
+            assert sys.exc_info()[1] is e         # y
+            assert sys.exc_info()[2] is not None  # n
+            assert sys.exc_info()[-3] is KeyError # y
+            assert sys.exc_info()[-2] is e        # y
+            assert sys.exc_info()[-1] is not None # n
+    test_returns_subscr.expected = 'yynyyn'
+
+    def test_returns_slice_2(self):
+        import sys
+        e = KeyError("boom")
+        try:
+            raise e
+        except:
+            foo = sys.exc_info()                  # n
+            assert sys.exc_info()[:0] == ()       # y
+            assert sys.exc_info()[:1] == foo[:1]  # y
+            assert sys.exc_info()[:2] == foo[:2]  # y
+            assert sys.exc_info()[:3] == foo      # n
+            assert sys.exc_info()[:4] == foo      # n
+            assert sys.exc_info()[:-1] == foo[:2] # y
+            assert sys.exc_info()[:-2] == foo[:1] # y
+            assert sys.exc_info()[:-3] == ()      # y
+    test_returns_slice_2.expected = 'nyyynnyyy'
+
+    def test_returns_slice_3(self):
+        import sys
+        e = KeyError("boom")
+        try:
+            raise e
+        except:
+            foo = sys.exc_info()                   # n
+            assert sys.exc_info()[2:2] == ()       # y
+            assert sys.exc_info()[0:1] == foo[:1]  # y
+            assert sys.exc_info()[1:2] == foo[1:2] # y
+            assert sys.exc_info()[0:3] == foo      # n
+            assert sys.exc_info()[2:4] == foo[2:]  # n
+            assert sys.exc_info()[0:-1] == foo[:2] # y
+            assert sys.exc_info()[0:-2] == foo[:1] # y
+            assert sys.exc_info()[5:-3] == ()      # y
+    test_returns_slice_3.expected = 'nyyynnyyy'
+
+    def test_strange_invocation(self):
+        import sys
+        e = KeyError("boom")
+        try:
+            raise e
+        except:
+            a = []; k = {}
+            assert sys.exc_info(*a)[:0] == ()
+            assert sys.exc_info(**k)[:0] == ()
+    test_strange_invocation.expected = 'nn'
+
+    def test_call_in_subfunction(self):
+        import sys
+        def g():
+            # this case is not optimized, because we need to search the
+            # frame chain.  it's probably not worth the complications
+            return sys.exc_info()[1]
+        e = KeyError("boom")
+        try:
+            raise e
+        except:
+            assert g() is e
+    test_call_in_subfunction.expected = 'n'
+
+
+class AppTestSysExcInfoDirectCallMethod(AppTestSysExcInfoDirect):
+    def setup_class(cls):
+        cls.space = gettestobjspace(**{"objspace.opcodes.CALL_METHOD": True})
diff --git a/pypy/module/sys/vm.py b/pypy/module/sys/vm.py
--- a/pypy/module/sys/vm.py
+++ b/pypy/module/sys/vm.py
@@ -89,6 +89,9 @@
     """Return the (type, value, traceback) of the most recent exception
 caught by an except clause in the current stack frame or in an older stack
 frame."""
+    return exc_info_with_tb(space)    # indirection for the tests
+
+def exc_info_with_tb(space):
     operror = space.getexecutioncontext().sys_exc_info()
     if operror is None:
         return space.newtuple([space.w_None,space.w_None,space.w_None])
@@ -96,6 +99,59 @@
         return space.newtuple([operror.w_type, operror.get_w_value(space),
                                space.wrap(operror.get_traceback())])
 
+def exc_info_without_tb(space, frame):
+    operror = frame.last_exception
+    return space.newtuple([operror.w_type, operror.get_w_value(space),
+                           space.w_None])
+
+def exc_info_direct(space, frame):
+    from pypy.tool import stdlib_opcode
+    # In order to make the JIT happy, we try to return (exc, val, None)
+    # instead of (exc, val, tb).  We can do that only if we recognize
+    # the following pattern in the bytecode:
+    #       CALL_FUNCTION/CALL_METHOD         <-- invoking me
+    #       LOAD_CONST 0, 1, -2 or -3
+    #       BINARY_SUBSCR
+    # or:
+    #       CALL_FUNCTION/CALL_METHOD
+    #       LOAD_CONST <=2
+    #       SLICE_2
+    # or:
+    #       CALL_FUNCTION/CALL_METHOD
+    #       LOAD_CONST any integer
+    #       LOAD_CONST <=2
+    #       SLICE_3
+    need_all_three_args = True
+    co = frame.getcode().co_code
+    p = frame.last_instr
+    if (ord(co[p]) == stdlib_opcode.CALL_FUNCTION or
+        ord(co[p]) == stdlib_opcode.CALL_METHOD):
+        if ord(co[p+3]) == stdlib_opcode.LOAD_CONST:
+            lo = ord(co[p+4])
+            hi = ord(co[p+5])
+            w_constant = frame.getconstant_w((hi * 256) | lo)
+            if space.isinstance_w(w_constant, space.w_int):
+                constant = space.int_w(w_constant)
+                if ord(co[p+6]) == stdlib_opcode.BINARY_SUBSCR:
+                    if -3 <= constant <= 1 and constant != -1:
+                        need_all_three_args = False
+                elif ord(co[p+6]) == stdlib_opcode.SLICE+2:
+                    if constant <= 2:
+                        need_all_three_args = False
+                elif (ord(co[p+6]) == stdlib_opcode.LOAD_CONST and
+                      ord(co[p+9]) == stdlib_opcode.SLICE+3):
+                    lo = ord(co[p+7])
+                    hi = ord(co[p+8])
+                    w_constant = frame.getconstant_w((hi * 256) | lo)
+                    if space.isinstance_w(w_constant, space.w_int):
+                        if space.int_w(w_constant) <= 2:
+                            need_all_three_args = False
+    #
+    if need_all_three_args or frame.last_exception is None or frame.hide():
+        return exc_info_with_tb(space)
+    else:
+        return exc_info_without_tb(space, frame)
+
 def exc_clear(space):
     """Clear global information on the current exception.  Subsequent calls
 to exc_info() will return (None,None,None) until another exception is
diff --git a/pypy/tool/clean_old_branches.py b/pypy/tool/clean_old_branches.py
--- a/pypy/tool/clean_old_branches.py
+++ b/pypy/tool/clean_old_branches.py
@@ -38,7 +38,7 @@
 closed_heads.reverse()
 
 for head, branch in closed_heads:
-    print '\t', branch
+    print '\t', head, '\t', branch
 print
 print 'The branches listed above will be merged to "closed-branches".'
 print 'You need to run this script in a clean working copy where you'


More information about the pypy-commit mailing list