[pypy-commit] pypy default: merged upstream

alex_gaynor noreply at buildbot.pypy.org
Mon May 4 02:13:03 CEST 2015


Author: Alex Gaynor <alex.gaynor at gmail.com>
Branch: 
Changeset: r77022:d61c5b8833ca
Date: 2015-05-03 20:12 -0400
http://bitbucket.org/pypy/pypy/changeset/d61c5b8833ca/

Log:	merged upstream

diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst
--- a/pypy/doc/whatsnew-head.rst
+++ b/pypy/doc/whatsnew-head.rst
@@ -71,3 +71,6 @@
 .. branch: vmprof2
 Add backend support for vmprof - a lightweight statistical profiler -
 to linux64, see client at https://vmprof.readthedocs.org
+
+.. branch: jit_hint_docs
+Add more detail to @jit.elidable and @jit.promote in rpython/rlib/jit.py
diff --git a/pypy/interpreter/pyframe.py b/pypy/interpreter/pyframe.py
--- a/pypy/interpreter/pyframe.py
+++ b/pypy/interpreter/pyframe.py
@@ -49,14 +49,35 @@
     last_instr               = -1
     last_exception           = None
     f_backref                = jit.vref_None
+    # For tracing
     w_f_trace                = None
-    # For tracing
     instr_lb                 = 0
     instr_ub                 = 0
     instr_prev_plus_one      = 0
+    # end of tracing
+    
     is_being_profiled        = False
     escaped                  = False  # see mark_as_escaped()
 
+    w_globals = None
+    w_locals = None # dict containing locals, if forced or necessary
+    pycode = None # code object executed by that frame
+    locals_stack_w = None # the list of all locals and valuestack
+    valuestackdepth = 0 # number of items on valuestack
+    lastblock = None
+    # default to False
+    f_lineno = 0 # current lineno
+    cells = None # cells
+
+    # other fields:
+    
+    # builtin - builtin cache, only if honor__builtins__ is True,
+
+    # there is also self.space which is removed by the annotator
+
+    # additionally JIT uses vable_token field that is representing
+    # frame current virtualizable state as seen by the JIT
+
     def __init__(self, space, code, w_globals, outer_func):
         if not we_are_translated():
             assert type(self) == space.FrameClass, (
@@ -65,11 +86,9 @@
         assert isinstance(code, pycode.PyCode)
         self.space = space
         self.w_globals = w_globals
-        self.w_locals = None
         self.pycode = code
         self.locals_stack_w = [None] * (code.co_nlocals + code.co_stacksize)
         self.valuestackdepth = code.co_nlocals
-        self.lastblock = None
         make_sure_not_resized(self.locals_stack_w)
         check_nonneg(self.valuestackdepth)
         #
diff --git a/pypy/module/_vmprof/interp_vmprof.py b/pypy/module/_vmprof/interp_vmprof.py
--- a/pypy/module/_vmprof/interp_vmprof.py
+++ b/pypy/module/_vmprof/interp_vmprof.py
@@ -27,7 +27,7 @@
     include_dirs = [SRC],
     includes = ['vmprof.h', 'trampoline.h'],
     separate_module_files = [SRC.join('trampoline.asmgcc.s')],
-    link_files = ['-Wl,-Bstatic', '-lunwind', '-Wl,-Bdynamic'],
+    link_files = ['-Wl,-Bstatic', '-lunwind', '-llzma','-Wl,-Bdynamic'],
     
     post_include_bits=["""
         void pypy_vmprof_init(void);
diff --git a/pypy/module/_vmprof/test/test_direct.py b/pypy/module/_vmprof/test/test_direct.py
--- a/pypy/module/_vmprof/test/test_direct.py
+++ b/pypy/module/_vmprof/test/test_direct.py
@@ -1,5 +1,9 @@
 
-import cffi, py
+import py
+try:
+    import cffi
+except ImportError:
+    py.test.skip('cffi required')
 
 srcdir = py.path.local(__file__).join("..", "..", "src")
 
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
@@ -65,9 +65,7 @@
         assert loop.match("""
             i7 = int_gt(i4, 1)
             guard_true(i7, descr=...)
-            p9 = call(ConstClass(fromint), i4, descr=...)
-            guard_no_exception(descr=...)
-            p11 = call(ConstClass(rbigint.mul), p5, p9, descr=...)
+            p11 = call(ConstClass(rbigint.int_mul), p5, i4, descr=...)
             guard_no_exception(descr=...)
             i13 = int_sub(i4, 1)
             --TICK--
diff --git a/pypy/objspace/std/complexobject.py b/pypy/objspace/std/complexobject.py
--- a/pypy/objspace/std/complexobject.py
+++ b/pypy/objspace/std/complexobject.py
@@ -270,7 +270,7 @@
         imag = space.float_w(space.getattr(self, space.wrap("imag")))
         real_b = rbigint.fromrarith_int(float2longlong(real))
         imag_b = rbigint.fromrarith_int(r_ulonglong(float2longlong(imag)))
-        val = real_b.lshift(64).or_(imag_b).lshift(3).or_(rbigint.fromint(tag))
+        val = real_b.lshift(64).or_(imag_b).lshift(3).int_or_(tag)
         return space.newlong_from_rbigint(val)
 
     def int(self, space):
diff --git a/pypy/objspace/std/floatobject.py b/pypy/objspace/std/floatobject.py
--- a/pypy/objspace/std/floatobject.py
+++ b/pypy/objspace/std/floatobject.py
@@ -185,7 +185,7 @@
         from pypy.objspace.std.util import IDTAG_FLOAT as tag
         val = float2longlong(space.float_w(self))
         b = rbigint.fromrarith_int(val)
-        b = b.lshift(3).or_(rbigint.fromint(tag))
+        b = b.lshift(3).int_or_(tag)
         return space.newlong_from_rbigint(b)
 
     def __repr__(self):
diff --git a/pypy/objspace/std/intobject.py b/pypy/objspace/std/intobject.py
--- a/pypy/objspace/std/intobject.py
+++ b/pypy/objspace/std/intobject.py
@@ -46,7 +46,7 @@
         if self.user_overridden_class:
             return None
         b = space.bigint_w(self)
-        b = b.lshift(3).or_(rbigint.fromint(IDTAG_INT))
+        b = b.lshift(3).int_or_(IDTAG_INT)
         return space.newlong_from_rbigint(b)
 
     def int(self, space):
diff --git a/pypy/objspace/std/longobject.py b/pypy/objspace/std/longobject.py
--- a/pypy/objspace/std/longobject.py
+++ b/pypy/objspace/std/longobject.py
@@ -45,7 +45,7 @@
         if self.user_overridden_class:
             return None
         b = space.bigint_w(self)
-        b = b.lshift(3).or_(rbigint.fromint(IDTAG_LONG))
+        b = b.lshift(3).int_or_(IDTAG_LONG)
         return space.newlong_from_rbigint(b)
 
     def unwrap(self, space):
@@ -350,8 +350,13 @@
 
     def _make_descr_cmp(opname):
         op = getattr(rbigint, opname)
-        @delegate_other
+        intop = getattr(rbigint, "int_" + opname)
+
         def descr_impl(self, space, w_other):
+            if isinstance(w_other, W_AbstractIntObject):
+                return space.newbool(intop(self.num, w_other.int_w(space)))
+            elif not isinstance(w_other, W_AbstractLongObject):
+                return space.w_NotImplemented
             return space.newbool(op(self.num, w_other.asbigint()))
         return func_with_new_name(descr_impl, "descr_" + opname)
 
@@ -362,7 +367,7 @@
     descr_gt = _make_descr_cmp('gt')
     descr_ge = _make_descr_cmp('ge')
 
-    def _make_generic_descr_binop(opname):
+    def _make_generic_descr_binop_noncommutative(opname):
         methname = opname + '_' if opname in ('and', 'or') else opname
         descr_rname = 'descr_r' + opname
         op = getattr(rbigint, methname)
@@ -372,33 +377,65 @@
         def descr_binop(self, space, w_other):
             return W_LongObject(op(self.num, w_other.asbigint()))
 
-        if opname in COMMUTATIVE_OPS:
-            @func_renamer(descr_rname)
-            def descr_rbinop(self, space, w_other):
-                return descr_binop(self, space, w_other)
-        else:
-            @func_renamer(descr_rname)
-            @delegate_other
-            def descr_rbinop(self, space, w_other):
-                return W_LongObject(op(w_other.asbigint(), self.num))
+        @func_renamer(descr_rname)
+        @delegate_other
+        def descr_rbinop(self, space, w_other):
+            return W_LongObject(op(w_other.asbigint(), self.num))
 
         return descr_binop, descr_rbinop
 
+    def _make_generic_descr_binop(opname):
+        if opname not in COMMUTATIVE_OPS:
+            raise Exception("Not supported")
+            
+        methname = opname + '_' if opname in ('and', 'or') else opname
+        descr_rname = 'descr_r' + opname
+        op = getattr(rbigint, methname)
+        intop = getattr(rbigint, "int_" + methname)
+        
+        @func_renamer('descr_' + opname)
+        def descr_binop(self, space, w_other):
+            if isinstance(w_other, W_AbstractIntObject):
+                return W_LongObject(intop(self.num, w_other.int_w(space)))
+            elif not isinstance(w_other, W_AbstractLongObject):
+                return space.w_NotImplemented
+
+            return W_LongObject(op(self.num, w_other.asbigint()))
+
+        @func_renamer(descr_rname)
+        def descr_rbinop(self, space, w_other):
+            if isinstance(w_other, W_AbstractIntObject):
+                return W_LongObject(intop(self.num, w_other.int_w(space)))
+            elif not isinstance(w_other, W_AbstractLongObject):
+                return space.w_NotImplemented
+
+            return W_LongObject(op(w_other.asbigint(), self.num))
+
+        return descr_binop, descr_rbinop
+        
     descr_add, descr_radd = _make_generic_descr_binop('add')
-    descr_sub, descr_rsub = _make_generic_descr_binop('sub')
+    descr_sub, descr_rsub = _make_generic_descr_binop_noncommutative('sub')
     descr_mul, descr_rmul = _make_generic_descr_binop('mul')
     descr_and, descr_rand = _make_generic_descr_binop('and')
     descr_or, descr_ror = _make_generic_descr_binop('or')
     descr_xor, descr_rxor = _make_generic_descr_binop('xor')
 
-    def _make_descr_binop(func):
+    def _make_descr_binop(func, int_func=None):
         opname = func.__name__[1:]
 
-        @delegate_other
-        @func_renamer('descr_' + opname)
-        def descr_binop(self, space, w_other):
-            return func(self, space, w_other)
-
+        if int_func:
+            @func_renamer('descr_' + opname)
+            def descr_binop(self, space, w_other):
+                if isinstance(w_other, W_AbstractIntObject):
+                    return int_func(self, space, w_other.int_w(space))
+                elif not isinstance(w_other, W_AbstractLongObject):
+                    return space.w_NotImplemented
+                return func(self, space, w_other)
+        else:
+            @delegate_other
+            @func_renamer('descr_' + opname)
+            def descr_binop(self, space, w_other):
+                return func(self, space, w_other)
         @delegate_other
         @func_renamer('descr_r' + opname)
         def descr_rbinop(self, space, w_other):
@@ -417,7 +454,13 @@
         except OverflowError:   # b too big
             raise oefmt(space.w_OverflowError, "shift count too large")
         return W_LongObject(self.num.lshift(shift))
-    descr_lshift, descr_rlshift = _make_descr_binop(_lshift)
+        
+    def _int_lshift(self, space, w_other):
+        if w_other < 0:
+            raise oefmt(space.w_ValueError, "negative shift count")
+        return W_LongObject(self.num.lshift(w_other))
+        
+    descr_lshift, descr_rlshift = _make_descr_binop(_lshift, _int_lshift)
 
     def _rshift(self, space, w_other):
         if w_other.asbigint().sign < 0:
@@ -427,8 +470,22 @@
         except OverflowError:   # b too big # XXX maybe just return 0L instead?
             raise oefmt(space.w_OverflowError, "shift count too large")
         return newlong(space, self.num.rshift(shift))
-    descr_rshift, descr_rrshift = _make_descr_binop(_rshift)
+        
+    def _int_rshift(self, space, w_other):
+        if w_other < 0:
+            raise oefmt(space.w_ValueError, "negative shift count")
 
+        return newlong(space, self.num.rshift(w_other))
+    descr_rshift, descr_rrshift = _make_descr_binop(_rshift, _int_rshift)
+
+    def _floordiv(self, space, w_other):
+        try:
+            z = self.num.floordiv(w_other.asbigint())
+        except ZeroDivisionError:
+            raise oefmt(space.w_ZeroDivisionError,
+                        "long division or modulo by zero")
+        return newlong(space, z)
+        
     def _floordiv(self, space, w_other):
         try:
             z = self.num.floordiv(w_other.asbigint())
@@ -448,7 +505,15 @@
             raise oefmt(space.w_ZeroDivisionError,
                         "long division or modulo by zero")
         return newlong(space, z)
-    descr_mod, descr_rmod = _make_descr_binop(_mod)
+        
+    def _int_mod(self, space, w_other):
+        try:
+            z = self.num.int_mod(w_other)
+        except ZeroDivisionError:
+            raise oefmt(space.w_ZeroDivisionError,
+                        "long division or modulo by zero")
+        return newlong(space, z)
+    descr_mod, descr_rmod = _make_descr_binop(_mod, _int_mod)
 
     def _divmod(self, space, w_other):
         try:
diff --git a/rpython/jit/backend/llsupport/llerrno.py b/rpython/jit/backend/llsupport/llerrno.py
--- a/rpython/jit/backend/llsupport/llerrno.py
+++ b/rpython/jit/backend/llsupport/llerrno.py
@@ -40,6 +40,13 @@
     assert nerrno >= 0
     cpu._debug_errno_container[5] = nerrno
 
+def get_debug_saved_altlasterror(cpu):
+    return cpu._debug_errno_container[6]
+
+def set_debug_saved_altlasterror(cpu, nerrno):
+    assert nerrno >= 0
+    cpu._debug_errno_container[6] = nerrno
+
 def get_rpy_lasterror_offset(cpu):
     if cpu.translate_support_code:
         from rpython.rlib import rthread
diff --git a/rpython/jit/backend/test/runner_test.py b/rpython/jit/backend/test/runner_test.py
--- a/rpython/jit/backend/test/runner_test.py
+++ b/rpython/jit/backend/test/runner_test.py
@@ -3106,15 +3106,22 @@
             self.cpu.compile_loop(inputargs, ops, looptoken)
             #
             llerrno.set_debug_saved_lasterror(self.cpu, 24)
+            llerrno.set_debug_saved_altlasterror(self.cpu, 25)
             deadframe = self.cpu.execute_token(looptoken, 9, 8, 7, 6, 5, 4, 3)
             original_result = self.cpu.get_int_value(deadframe, 0)
             result = llerrno.get_debug_saved_lasterror(self.cpu)
-            print 'saveerr =', saveerr, ': got result =', result
+            altresult = llerrno.get_debug_saved_altlasterror(self.cpu)
+            print 'saveerr =', saveerr, ': got result =', result,
+            print 'and altresult =', altresult
             #
-            if saveerr == rffi.RFFI_SAVE_LASTERROR:
-                assert result == 42      # from the C code
+            if saveerr & rffi.RFFI_SAVE_LASTERROR:
+                # one from the C code, the other not touched
+                if saveerr & rffi.RFFI_ALT_ERRNO:
+                    assert (result, altresult) == (24, 42)
+                else:
+                    assert (result, altresult) == (42, 25)
             else:
-                assert result == 24      # not touched
+                assert (result, altresult) == (24, 25)      # not touched
             assert original_result == 3456789
 
     def test_call_release_gil_readsaved_lasterror(self):
@@ -3169,11 +3176,17 @@
             self.cpu.compile_loop(inputargs, ops, looptoken)
             #
             llerrno.set_debug_saved_lasterror(self.cpu, 24)
+            llerrno.set_debug_saved_altlasterror(self.cpu, 25)
             deadframe = self.cpu.execute_token(looptoken, 9, 8, 7, 6, 5, 4, 3)
             result = self.cpu.get_int_value(deadframe, 0)
             assert llerrno.get_debug_saved_lasterror(self.cpu) == 24
+            assert llerrno.get_debug_saved_altlasterror(self.cpu) == 25
             #
-            assert result == 24 + 345678900
+            if saveerr & rffi.RFFI_ALT_ERRNO:
+                expected_lasterror = 25
+            else:
+                expected_lasterror = 24
+            assert result == expected_lasterror + 345678900
 
     def test_call_release_gil_err_all(self):
         from rpython.translator.tool.cbuild import ExternalCompilationInfo
@@ -3226,9 +3239,8 @@
                                                           types.slong)
         #
         for saveerr in [rffi.RFFI_ERR_ALL,
-                        rffi.RFFI_ERR_ALL | rffi.RFFI_ALT_ERRNO, 
+                        rffi.RFFI_ERR_ALL | rffi.RFFI_ALT_ERRNO,
                        ]:
-            use_alt_errno = saveerr & rffi.RFFI_ALT_ERRNO
             faildescr = BasicFailDescr(1)
             inputargs = [BoxInt() for i in range(7)]
             i1 = BoxInt()
@@ -3244,19 +3256,34 @@
             looptoken = JitCellToken()
             self.cpu.compile_loop(inputargs, ops, looptoken)
             #
-            if use_alt_errno:
-                llerrno.set_debug_saved_alterrno(self.cpu, 8)
-            else:
-                llerrno.set_debug_saved_errno(self.cpu, 8)
+            llerrno.set_debug_saved_errno(self.cpu, 8)
+            llerrno.set_debug_saved_alterrno(self.cpu, 5)
             llerrno.set_debug_saved_lasterror(self.cpu, 9)
+            llerrno.set_debug_saved_altlasterror(self.cpu, 4)
             deadframe = self.cpu.execute_token(looptoken, 1, 2, 3, 4, 5, 6, 7)
             result = self.cpu.get_int_value(deadframe, 0)
-            assert llerrno.get_debug_saved_errno(self.cpu) == 42
+            got_errno = llerrno.get_debug_saved_errno(self.cpu)
+            got_alter = llerrno.get_debug_saved_alterrno(self.cpu)
+            if saveerr & rffi.RFFI_ALT_ERRNO:
+                assert (got_errno, got_alter) == (8, 42)
+            else:
+                assert (got_errno, got_alter) == (42, 5)
             if sys.platform != 'win32':
-                assert result == 765432108
+                if saveerr & rffi.RFFI_ALT_ERRNO:
+                    assert result == 765432105
+                else:
+                    assert result == 765432108
             else:
-                assert llerrno.get_debug_saved_lasterror(self.cpu) == 43
-                assert result == 765432198
+                if saveerr & rffi.RFFI_ALT_ERRNO:
+                    assert result == 765432145
+                else:
+                    assert result == 765432198
+                got_lasterror = llerrno.get_debug_saved_lasterror(self.cpu)
+                got_altlaster = llerrno.get_debug_saved_altlasterror(self.cpu)
+                if saveerr & rffi.RFFI_ALT_ERRNO:
+                    assert (got_lasterror, got_altlaster) == (9, 43)
+                else:
+                    assert (got_lasterror, got_altlaster) == (43, 4)
 
     def test_guard_not_invalidated(self):
         cpu = self.cpu
diff --git a/rpython/jit/backend/x86/callbuilder.py b/rpython/jit/backend/x86/callbuilder.py
--- a/rpython/jit/backend/x86/callbuilder.py
+++ b/rpython/jit/backend/x86/callbuilder.py
@@ -221,6 +221,7 @@
             mc.CALL(imm(follow_jump(SetLastError_addr)))
             # restore the stack position without assuming a particular
             # calling convention of _SetLastError()
+            self.mc.stack_frame_size_delta(-WORD)
             self.mc.MOV(esp, self.saved_stack_position_reg)
 
         if save_err & rffi.RFFI_READSAVED_ERRNO:
diff --git a/rpython/rlib/jit.py b/rpython/rlib/jit.py
--- a/rpython/rlib/jit.py
+++ b/rpython/rlib/jit.py
@@ -34,6 +34,26 @@
     side effect, but those side effects are idempotent (ie caching).
     If a particular call to this function ends up raising an exception, then it
     is handled like a normal function call (this decorator is ignored).
+
+    Note also that this optimisation will only take effect if the arguments
+    to the function are proven constant. By this we mean each argument
+    is either:
+
+      1) a constant from the RPython source code (e.g. "x = 2")
+      2) easily shown to be constant by the tracer
+      3) a promoted variable (see @jit.promote)
+
+    Examples of condition 2:
+
+      * i1 = int_eq(i0, 0), guard_true(i1)
+      * i1 = getfield_pc_pure(<constant>, "immutable_field")
+
+    In both cases, the tracer will deduce that i1 is constant.
+
+    Failing the above conditions, the function is not traced into (as if the
+    function were decorated with @jit.dont_look_inside). Generally speaking,
+    it is a bad idea to liberally sprinkle @jit.elidable without a concrete
+    need.
     """
     if DEBUG_ELIDABLE_FUNCTIONS:
         cache = {}
@@ -78,6 +98,29 @@
 
 @specialize.argtype(0)
 def promote(x):
+    """
+    Promotes a variable in a trace to a constant.
+
+    When a variable is promoted, a guard is inserted that assumes the value
+    of the variable is constant. In other words, the value of the variable
+    is checked to be the same as it was at trace collection time.  Once the
+    variable is assumed constant, more aggressive constant folding may be
+    possible.
+
+    If however, the guard fails frequently, a bridge will be generated
+    this time assuming the constancy of the variable under its new value.
+    This optimisation should be used carefully, as in extreme cases, where
+    the promoted variable is not very constant at all, code explosion can
+    occur. In turn this leads to poor performance.
+
+    Overpromotion is characterised by a cascade of bridges branching from
+    very similar guard_value opcodes, each guarding the same variable under
+    a different value.
+
+    Note that promoting a string with @jit.promote will promote by pointer.
+    To promote a string by value, see @jit.promote_string.
+
+    """
     return hint(x, promote=True)
 
 def promote_string(x):


More information about the pypy-commit mailing list