Author: Alex Gaynor <alex.gay...@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): _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit