[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