[pypy-commit] pypy default: Merge jit-settrace.
alex_gaynor
noreply at buildbot.pypy.org
Sat Oct 26 00:36:45 CEST 2013
Author: Alex Gaynor <alex.gaynor at gmail.com>
Branch:
Changeset: r67622:6b62779684ac
Date: 2013-10-25 15:35 -0700
http://bitbucket.org/pypy/pypy/changeset/6b62779684ac/
Log: Merge jit-settrace.
This lets the JIT stay active when sys.settrace() has a tracefunc
enabled
diff --git a/pypy/interpreter/executioncontext.py b/pypy/interpreter/executioncontext.py
--- a/pypy/interpreter/executioncontext.py
+++ b/pypy/interpreter/executioncontext.py
@@ -76,7 +76,7 @@
frame_vref()
jit.virtual_ref_finish(frame_vref, frame)
- if self.w_tracefunc is not None and not frame.hide():
+ if self.gettrace() is not None and not frame.hide():
self.space.frame_trace_action.fire()
# ________________________________________________________________
@@ -115,14 +115,14 @@
def call_trace(self, frame):
"Trace the call of a function"
- if self.w_tracefunc is not None or self.profilefunc is not None:
+ if self.gettrace() is not None or self.profilefunc is not None:
self._trace(frame, 'call', self.space.w_None)
if self.profilefunc:
frame.is_being_profiled = True
def return_trace(self, frame, w_retval):
"Trace the return from a function"
- if self.w_tracefunc is not None:
+ if self.gettrace() is not None:
return_from_hidden = self._trace(frame, 'return', w_retval)
# special case: if we are returning from a hidden function,
# then maybe we have to fire() the action again; otherwise
@@ -152,7 +152,7 @@
def exception_trace(self, frame, operationerr):
"Trace function called upon OperationError."
operationerr.record_interpreter_traceback()
- if self.w_tracefunc is not None:
+ if self.gettrace() is not None:
self._trace(frame, 'exception', None, operationerr)
#operationerr.print_detailed_traceback(self.space)
@@ -181,7 +181,7 @@
self.space.frame_trace_action.fire()
def gettrace(self):
- return self.w_tracefunc
+ return jit.promote(self.w_tracefunc)
def setprofile(self, w_func):
"""Set the global trace function."""
@@ -234,7 +234,7 @@
# Tracing cases
if event == 'call':
- w_callback = self.w_tracefunc
+ w_callback = self.gettrace()
else:
w_callback = frame.w_f_trace
@@ -310,6 +310,9 @@
the GIL. And whether we have threads or not, it is forced to zero
whenever we fire any of the asynchronous actions.
"""
+
+ _immutable_fields_ = ["checkinterval_scaled?"]
+
def __init__(self):
self._periodic_actions = []
self._nonperiodic_actions = []
@@ -367,7 +370,7 @@
def _rebuild_action_dispatcher(self):
periodic_actions = unrolling_iterable(self._periodic_actions)
- @jit.dont_look_inside
+ @jit.unroll_safe
def action_dispatcher(ec, frame):
# periodic actions (first reset the bytecode counter)
self.reset_ticker(self.checkinterval_scaled)
@@ -454,6 +457,9 @@
def perform(self, executioncontext, frame):
if self.finalizers_lock_count > 0:
return
+ self._run_finalizers()
+
+ def _run_finalizers(self):
# Each call to perform() first grabs the self.dying_objects
# and replaces it with an empty list. We do this to try to
# avoid too deep recursions of the kind of __del__ being called
@@ -473,9 +479,10 @@
class FrameTraceAction(AsyncAction):
"""An action that calls the local trace functions (w_f_trace)."""
+ @jit.unroll_safe
def perform(self, executioncontext, frame):
if (frame.w_f_trace is None or executioncontext.is_tracing or
- executioncontext.w_tracefunc is None):
+ executioncontext.gettrace() is None):
return
code = frame.pycode
if frame.instr_lb <= frame.last_instr < frame.instr_ub:
diff --git a/pypy/interpreter/nestedscope.py b/pypy/interpreter/nestedscope.py
--- a/pypy/interpreter/nestedscope.py
+++ b/pypy/interpreter/nestedscope.py
@@ -127,7 +127,7 @@
self.space.wrap("bad cellvars"))
self.cells[:ncellvars] = cellvars
- @jit.dont_look_inside
+ @jit.unroll_safe
def fast2locals(self):
super_fast2locals(self)
# cellvars are values exported to inner scopes
@@ -146,7 +146,7 @@
w_name = self.space.wrap(name)
self.space.setitem(self.w_locals, w_name, w_value)
- @jit.dont_look_inside
+ @jit.unroll_safe
def locals2fast(self):
super_locals2fast(self)
freevarnames = self.pycode.co_cellvars + self.pycode.co_freevars
diff --git a/pypy/interpreter/pycode.py b/pypy/interpreter/pycode.py
--- a/pypy/interpreter/pycode.py
+++ b/pypy/interpreter/pycode.py
@@ -189,9 +189,8 @@
# speed hack
fresh_frame = jit.hint(frame, access_directly=True,
fresh_virtualizable=True)
- args_matched = args.parse_into_scope(None, fresh_frame.locals_stack_w,
- func.name,
- sig, func.defs_w)
+ args.parse_into_scope(None, fresh_frame.locals_stack_w, func.name,
+ sig, func.defs_w)
fresh_frame.init_cells()
return frame.run()
@@ -202,9 +201,8 @@
# speed hack
fresh_frame = jit.hint(frame, access_directly=True,
fresh_virtualizable=True)
- args_matched = args.parse_into_scope(w_obj, fresh_frame.locals_stack_w,
- func.name,
- sig, func.defs_w)
+ args.parse_into_scope(w_obj, fresh_frame.locals_stack_w, func.name,
+ sig, func.defs_w)
fresh_frame.init_cells()
return frame.run()
diff --git a/pypy/interpreter/pyframe.py b/pypy/interpreter/pyframe.py
--- a/pypy/interpreter/pyframe.py
+++ b/pypy/interpreter/pyframe.py
@@ -8,7 +8,7 @@
from rpython.rlib.rarithmetic import intmask, r_uint
from rpython.tool.pairtype import extendabletype
-from pypy.interpreter import eval, pycode, pytraceback
+from pypy.interpreter import pycode, pytraceback
from pypy.interpreter.argument import Arguments
from pypy.interpreter.baseobjspace import W_Root
from pypy.interpreter.error import OperationError, operationerrfmt
@@ -443,12 +443,7 @@
def getcode(self):
return hint(self.pycode, promote=True)
- @jit.dont_look_inside
- def getfastscope(self):
- "Get the fast locals as a list."
- return self.locals_stack_w
-
- @jit.dont_look_inside
+ @jit.look_inside_iff(lambda self, scope_w: jit.isvirtual(scope_w))
def setfastscope(self, scope_w):
"""Initialize the fast locals from a list of values,
where the order is according to self.pycode.signature()."""
@@ -475,15 +470,15 @@
self.w_locals = w_locals
self.locals2fast()
+ @jit.unroll_safe
def fast2locals(self):
# Copy values from the fastlocals to self.w_locals
if self.w_locals is None:
self.w_locals = self.space.newdict()
varnames = self.getcode().getvarnames()
- fastscope_w = self.getfastscope()
- for i in range(min(len(varnames), self.getfastscopelength())):
+ for i in range(min(len(varnames), self.getcode().co_nlocals)):
name = varnames[i]
- w_value = fastscope_w[i]
+ w_value = self.locals_stack_w[i]
w_name = self.space.wrap(name)
if w_value is not None:
self.space.setitem(self.w_locals, w_name, w_value)
@@ -494,11 +489,12 @@
if not e.match(self.space, self.space.w_KeyError):
raise
+ @jit.unroll_safe
def locals2fast(self):
# Copy values from self.w_locals to the fastlocals
assert self.w_locals is not None
varnames = self.getcode().getvarnames()
- numlocals = self.getfastscopelength()
+ numlocals = self.getcode().co_nlocals
new_fastlocals_w = [None] * numlocals
@@ -519,9 +515,6 @@
This is overridden in nestedscope.py"""
pass
- def getfastscopelength(self):
- return self.pycode.co_nlocals
-
def getclosure(self):
return None
diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py
--- a/pypy/module/pypyjit/interp_jit.py
+++ b/pypy/module/pypyjit/interp_jit.py
@@ -32,14 +32,20 @@
name = opcode_method_names[ord(bytecode.co_code[next_instr])]
return '%s #%d %s' % (bytecode.get_repr(), next_instr, name)
-def get_jitcell_at(next_instr, is_being_profiled, bytecode):
+def make_greenkey_dict_key(next_instr, is_being_profiled):
# use only uints as keys in the jit_cells dict, rather than
# a tuple (next_instr, is_being_profiled)
- key = (next_instr << 1) | r_uint(intmask(is_being_profiled))
+ return (
+ (next_instr << 1) |
+ r_uint(intmask(is_being_profiled))
+ )
+
+def get_jitcell_at(next_instr, is_being_profiled, bytecode):
+ key = make_greenkey_dict_key(next_instr, is_being_profiled)
return bytecode.jit_cells.get(key, None)
def set_jitcell_at(newcell, next_instr, is_being_profiled, bytecode):
- key = (next_instr << 1) | r_uint(intmask(is_being_profiled))
+ key = make_greenkey_dict_key(next_instr, is_being_profiled)
bytecode.jit_cells[key] = newcell
diff --git a/pypy/module/pypyjit/test_pypy_c/test_call.py b/pypy/module/pypyjit/test_pypy_c/test_call.py
--- a/pypy/module/pypyjit/test_pypy_c/test_call.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_call.py
@@ -67,7 +67,7 @@
# LOAD_GLOBAL of OFFSET
ops = entry_bridge.ops_by_id('cond', opcode='LOAD_GLOBAL')
assert log.opnames(ops) == ["guard_value",
- "getfield_gc", "guard_value",
+ "guard_value",
"getfield_gc", "guard_value",
"guard_not_invalidated"]
ops = entry_bridge.ops_by_id('add', opcode='LOAD_GLOBAL')
@@ -81,7 +81,7 @@
p39 = getfield_gc(p38, descr=<FieldP pypy.interpreter.executioncontext.ExecutionContext.inst_topframeref .*>)
i40 = force_token()
p41 = getfield_gc(p38, descr=<FieldP pypy.interpreter.executioncontext.ExecutionContext.inst_w_tracefunc .*>)
- guard_isnull(p41, descr=...)
+ guard_value(p41, ConstPtr(ptr42), descr=...)
i42 = getfield_gc(p38, descr=<FieldU pypy.interpreter.executioncontext.ExecutionContext.inst_profilefunc .*>)
i43 = int_is_zero(i42)
guard_true(i43, descr=...)
@@ -424,33 +424,32 @@
""", [])
loop, = log.loops_by_id('call', is_entry_bridge=True)
assert loop.match("""
- guard_value(i6, 1, descr=...)
- guard_nonnull_class(p8, ConstClass(W_IntObject), descr=...)
- guard_value(i4, 0, descr=...)
- guard_value(p3, ConstPtr(ptr14), descr=...)
- i15 = getfield_gc_pure(p8, descr=<FieldS pypy.objspace.std.intobject.W_IntObject.inst_intval .*>)
- i17 = int_lt(i15, 5000)
- guard_true(i17, descr=...)
- guard_value(p18, ConstPtr(ptr19), descr=...)
- p20 = getfield_gc(p18, descr=<FieldP pypy.objspace.std.dictmultiobject.W_DictMultiObject.inst_strategy .*>)
- guard_value(p20, ConstPtr(ptr21), descr=...)
+ guard_value(i4, 1, descr=...)
+ guard_nonnull_class(p12, ConstClass(W_IntObject), descr=...)
+ guard_value(i8, 0, descr=...)
+ guard_value(p2, ConstPtr(ptr21), descr=...)
+ i22 = getfield_gc_pure(p12, descr=<FieldS pypy.objspace.std.intobject.W_IntObject.inst_intval .*>)
+ i24 = int_lt(i22, 5000)
+ guard_true(i24, descr=...)
+ guard_value(p7, ConstPtr(ptr25), descr=...)
+ p26 = getfield_gc(p7, descr=<FieldP pypy.objspace.std.dictmultiobject.W_DictMultiObject.inst_strategy .*>)
+ guard_value(p26, ConstPtr(ptr27), descr=...)
guard_not_invalidated(descr=...)
- # most importantly, there is no getarrayitem_gc here
- p23 = call(ConstClass(getexecutioncontext), descr=<Callr . EF=1>)
- p24 = getfield_gc(p23, descr=<FieldP pypy.interpreter.executioncontext.ExecutionContext.inst_topframeref .*>)
- i25 = force_token()
- p26 = getfield_gc(p23, descr=<FieldP pypy.interpreter.executioncontext.ExecutionContext.inst_w_tracefunc .*>)
- guard_isnull(p26, descr=...)
- i27 = getfield_gc(p23, descr=<FieldU pypy.interpreter.executioncontext.ExecutionContext.inst_profilefunc .*>)
- i28 = int_is_zero(i27)
- guard_true(i28, descr=...)
- p30 = getfield_gc(ConstPtr(ptr29), descr=<FieldP pypy.interpreter.nestedscope.Cell.inst_w_value .*>)
- guard_nonnull_class(p30, ConstClass(W_IntObject), descr=...)
- i32 = getfield_gc_pure(p30, descr=<FieldS pypy.objspace.std.intobject.W_IntObject.inst_intval .*>)
- i33 = int_add_ovf(i15, i32)
+ p29 = call(ConstClass(getexecutioncontext), descr=<Callr 8 EF=1>)
+ p30 = getfield_gc(p29, descr=<FieldP pypy.interpreter.executioncontext.ExecutionContext.inst_topframeref .*>)
+ p31 = force_token()
+ p32 = getfield_gc(p29, descr=<FieldP pypy.interpreter.executioncontext.ExecutionContext.inst_w_tracefunc .*>)
+ guard_value(p32, ConstPtr(ptr33), descr=...)
+ i34 = getfield_gc(p29, descr=<FieldU pypy.interpreter.executioncontext.ExecutionContext.inst_profilefunc .*>)
+ i35 = int_is_zero(i34)
+ guard_true(i35, descr=...)
+ p37 = getfield_gc(ConstPtr(ptr36), descr=<FieldP pypy.interpreter.nestedscope.Cell.inst_w_value .*>)
+ guard_nonnull_class(p37, ConstClass(W_IntObject), descr=...)
+ i39 = getfield_gc_pure(p37, descr=<FieldS pypy.objspace.std.intobject.W_IntObject.inst_intval .*>)
+ i40 = int_add_ovf(i22, i39)
guard_no_overflow(descr=...)
+ guard_not_invalidated(descr=...)
--TICK--
- p39 = same_as(...) # Should be killed by backend
""")
def test_local_closure_is_virtual(self):
diff --git a/pypy/module/pypyjit/test_pypy_c/test_min_max.py b/pypy/module/pypyjit/test_pypy_c/test_min_max.py
--- a/pypy/module/pypyjit/test_pypy_c/test_min_max.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_min_max.py
@@ -1,8 +1,7 @@
-import py
from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC
+
class TestMinMax(BaseTestPyPyC):
-
def test_min_max(self):
def main():
i=0
@@ -24,7 +23,6 @@
--TICK--
jump(..., descr=...)
""")
-
def test_silly_max(self):
def main():
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
@@ -408,3 +408,20 @@
log = self.run(main, [300])
loop, = log.loops_by_id("long_op")
assert len(loop.ops_by_id("long_op")) == 0
+
+ def test_settrace(self):
+ def main(n):
+ import sys
+ sys.settrace(lambda *args, **kwargs: None)
+
+ def f():
+ return 1
+
+ while n:
+ n -= f()
+
+ log = self.run(main, [300])
+ loops = log.loops_by_filename(self.filepath)
+ # the following assertion fails if the loop was cancelled due
+ # to "abort: vable escape"
+ assert len(loops) == 1
diff --git a/pypy/module/pypyjit/test_pypy_c/test_thread.py b/pypy/module/pypyjit/test_pypy_c/test_thread.py
--- a/pypy/module/pypyjit/test_pypy_c/test_thread.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_thread.py
@@ -60,27 +60,27 @@
assert log.result == main(500)
loop, = log.loops_by_filename(self.filepath)
assert loop.match("""
- i55 = int_gt(i43, 0)
- guard_true(i55, descr=...)
- p56 = force_token()
- setfield_gc(p0, p56, descr=<FieldP pypy.interpreter.pyframe.PyFrame.vable_token .*>)
- i57 = call_release_gil(..., i36, 1, descr=<Calli 4 ii EF=6>)
+ i56 = int_gt(i44, 0)
+ guard_true(i56, descr=...)
+ p57 = force_token()
+ setfield_gc(p0, p57, descr=<FieldP pypy.interpreter.pyframe.PyFrame.vable_token 8>)
+ i58 = call_release_gil(..., i37, 1, descr=<Calli 4 ii EF=6>)
guard_not_forced(descr=...)
guard_no_exception(descr=...)
- i58 = int_is_true(i57)
- guard_true(i58, descr=...)
- i59 = int_sub(i43, 1)
+ i59 = int_is_true(i58)
+ guard_true(i59, descr=...)
+ i60 = int_sub(i44, 1)
guard_not_invalidated(descr=...)
- p61 = force_token()
- setfield_gc(p0, p61, descr=<FieldP pypy.interpreter.pyframe.PyFrame.vable_token .*>)
- i62 = call_release_gil(..., i36, 0, descr=<Calli 4 ii EF=6>)
+ p62 = force_token()
+ setfield_gc(p0, p62, descr=<FieldP pypy.interpreter.pyframe.PyFrame.vable_token 8>)
+ i63 = call_release_gil(..., i37, 0, descr=<Calli 4 ii EF=6>)
guard_not_forced(descr=...)
guard_no_exception(descr=...)
- i63 = int_is_true(i62)
- guard_false(i63, descr=...)
- p64 = force_token()
- setfield_gc(p0, p64, descr=<FieldP pypy.interpreter.pyframe.PyFrame.vable_token .*>)
- call_release_gil(..., i36, descr=<Callv 0 i EF=6>)
+ i64 = int_is_true(i63)
+ guard_false(i64, descr=...)
+ p65 = force_token()
+ setfield_gc(p0, p65, descr=<FieldP pypy.interpreter.pyframe.PyFrame.vable_token 8>)
+ call_release_gil(..., i37, descr=<Callv 0 i EF=6>)
guard_not_forced(descr=...)
guard_no_exception(descr=...)
guard_not_invalidated(descr=...)
diff --git a/pypy/module/signal/interp_signal.py b/pypy/module/signal/interp_signal.py
--- a/pypy/module/signal/interp_signal.py
+++ b/pypy/module/signal/interp_signal.py
@@ -75,11 +75,15 @@
# and there is a signal pending: we force the ticker to
# -1, which should ensure perform() is called quickly.
+ def perform(self, executioncontext, frame):
+ self._poll_for_signals()
+
@jit.dont_look_inside
- def perform(self, executioncontext, frame):
+ def _poll_for_signals(self):
# Poll for the next signal, if any
n = self.pending_signal
- if n < 0: n = pypysig_poll()
+ if n < 0:
+ n = pypysig_poll()
while n >= 0:
if self.space.threadlocals.signals_enabled():
# If we are in the main thread, report the signal now,
@@ -87,7 +91,8 @@
self.pending_signal = -1
report_signal(self.space, n)
n = self.pending_signal
- if n < 0: n = pypysig_poll()
+ if n < 0:
+ n = pypysig_poll()
else:
# Otherwise, arrange for perform() to be called again
# after we switch to the main thread.
diff --git a/pypy/tool/pypyjit_demo.py b/pypy/tool/pypyjit_demo.py
--- a/pypy/tool/pypyjit_demo.py
+++ b/pypy/tool/pypyjit_demo.py
@@ -1,22 +1,8 @@
+def f():
+ i = 0
+ while i < 1303:
+ i += 1
+ return i
-def g(i):
- k = 0
- while k < 3:
- k += 1
- return i + 1
-def f(x):
- for i in range(10000):
- t = (1, 2, i)
- i = g(i)
- x == t
-
-
-
-try:
- f((1, 2, 3))
-
-except Exception, e:
- print "Exception: ", type(e)
- print e
-
+f()
More information about the pypy-commit
mailing list