[pypy-commit] pypy default: Fixed sys.settrace() of the pypy interpreter when under the JIT.
alex_gaynor
noreply at buildbot.pypy.org
Wed Oct 30 23:08:49 CET 2013
Author: Alex Gaynor <alex.gaynor at gmail.com>
Branch:
Changeset: r67754:2a993c608319
Date: 2013-10-30 15:08 -0700
http://bitbucket.org/pypy/pypy/changeset/2a993c608319/
Log: Fixed sys.settrace() of the pypy interpreter when under the JIT.
Properly run the tracefunction at every bytecode.
diff --git a/README.rst b/README.rst
--- a/README.rst
+++ b/README.rst
@@ -1,5 +1,5 @@
=====================================
-PyPy: Python in Python Implementation
+PyPy: Python in Python Implementation
=====================================
Welcome to PyPy!
@@ -26,9 +26,11 @@
Building
========
-build with::
+build with:
- rpython/bin/rpython -Ojit pypy/goal/targetpypystandalone.py
+.. code-block:: console
+
+ $ rpython/bin/rpython -Ojit pypy/goal/targetpypystandalone.py
This ends up with ``pypy-c`` binary in the main pypy directory. We suggest
to use virtualenv with the resulting pypy-c as the interpreter, you can
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -10,7 +10,7 @@
from rpython.rlib.rarithmetic import r_uint
from pypy.interpreter.executioncontext import (ExecutionContext, ActionFlag,
- UserDelAction, FrameTraceAction)
+ UserDelAction)
from pypy.interpreter.error import (OperationError, operationerrfmt,
new_exception_class)
from pypy.interpreter.argument import Arguments
@@ -330,7 +330,6 @@
self.actionflag = ActionFlag() # changed by the signal module
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
diff --git a/pypy/interpreter/executioncontext.py b/pypy/interpreter/executioncontext.py
--- a/pypy/interpreter/executioncontext.py
+++ b/pypy/interpreter/executioncontext.py
@@ -27,13 +27,10 @@
def __init__(self, space):
self.space = space
self.topframeref = jit.vref_None
- # tracing: space.frame_trace_action.fire() must be called to ensure
- # that tracing occurs whenever self.w_tracefunc or self.is_tracing
- # is modified.
- self.w_tracefunc = None # if not None, no JIT
+ self.w_tracefunc = None
self.is_tracing = 0
self.compiler = space.createcompiler()
- self.profilefunc = None # if not None, no JIT
+ self.profilefunc = None
self.w_profilefuncarg = None
def gettopframe(self):
@@ -76,9 +73,6 @@
frame_vref()
jit.virtual_ref_finish(frame_vref, frame)
- if self.gettrace() is not None and not frame.hide():
- self.space.frame_trace_action.fire()
-
# ________________________________________________________________
def c_call_trace(self, frame, w_func, args=None):
@@ -123,25 +117,77 @@
def return_trace(self, frame, w_retval):
"Trace the return from a function"
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
- # it will not be called. See test_trace_hidden_prints.
- if return_from_hidden:
- self.space.frame_trace_action.fire()
+ self._trace(frame, 'return', w_retval)
def bytecode_trace(self, frame, decr_by=TICK_COUNTER_STEP):
"Trace function called before each bytecode."
# this is split into a fast path and a slower path that is
# not invoked every time bytecode_trace() is.
+ self.bytecode_only_trace(frame)
actionflag = self.space.actionflag
if actionflag.decrement_ticker(decr_by) < 0:
actionflag.action_dispatcher(self, frame) # slow path
bytecode_trace._always_inline_ = True
+ def bytecode_only_trace(self, frame):
+ """
+ Like bytecode_trace() but doesn't invoke any other events besides the
+ trace function.
+ """
+ if (frame.w_f_trace is None or self.is_tracing or
+ self.gettrace() is None):
+ return
+ self.run_trace_func(frame)
+ bytecode_only_trace._always_inline_ = True
+
+ @jit.unroll_safe
+ def run_trace_func(self, frame):
+ code = frame.pycode
+ if frame.instr_lb <= frame.last_instr < frame.instr_ub:
+ if frame.last_instr < frame.instr_prev_plus_one:
+ # We jumped backwards in the same line.
+ self._trace(frame, 'line', self.space.w_None)
+ else:
+ size = len(code.co_lnotab) / 2
+ addr = 0
+ line = code.co_firstlineno
+ p = 0
+ lineno = code.co_lnotab
+ while size > 0:
+ c = ord(lineno[p])
+ if (addr + c) > frame.last_instr:
+ break
+ addr += c
+ if c:
+ frame.instr_lb = addr
+
+ line += ord(lineno[p + 1])
+ p += 2
+ size -= 1
+
+ if size > 0:
+ while True:
+ size -= 1
+ if size < 0:
+ break
+ addr += ord(lineno[p])
+ if ord(lineno[p + 1]):
+ break
+ p += 2
+ frame.instr_ub = addr
+ else:
+ frame.instr_ub = sys.maxint
+
+ if frame.instr_lb == frame.last_instr: # At start of line!
+ frame.f_lineno = line
+ self._trace(frame, 'line', self.space.w_None)
+
+ frame.instr_prev_plus_one = frame.last_instr + 1
+
def bytecode_trace_after_exception(self, frame):
"Like bytecode_trace(), but without increasing the ticker."
actionflag = self.space.actionflag
+ self.bytecode_only_trace(frame)
if actionflag.get_ticker() < 0:
actionflag.action_dispatcher(self, frame) # slow path
bytecode_trace_after_exception._always_inline_ = 'try'
@@ -178,7 +224,9 @@
else:
self.force_all_frames()
self.w_tracefunc = w_func
- self.space.frame_trace_action.fire()
+ # Increase the JIT's trace_limit when we have a tracefunc, it
+ # generates a ton of extra ops.
+ jit.set_param(None, 'trace_limit', 10000)
def gettrace(self):
return jit.promote(self.w_tracefunc)
@@ -221,14 +269,13 @@
is_tracing = self.is_tracing
self.is_tracing = 0
try:
- self.space.frame_trace_action.fire()
return self.space.call(w_func, w_args)
finally:
self.is_tracing = is_tracing
def _trace(self, frame, event, w_arg, operr=None):
if self.is_tracing or frame.hide():
- return True
+ return
space = self.space
@@ -260,7 +307,6 @@
finally:
self.is_tracing -= 1
frame.locals2fast()
- space.frame_trace_action.fire()
# Profile cases
if self.profilefunc is not None:
@@ -269,7 +315,7 @@
event == 'c_call' or
event == 'c_return' or
event == 'c_exception'):
- return False
+ return
last_exception = frame.last_exception
if event == 'leaveframe':
@@ -289,7 +335,6 @@
finally:
frame.last_exception = last_exception
self.is_tracing -= 1
- return False
def checksignals(self):
"""Similar to PyErr_CheckSignals(). If called in the main thread,
@@ -475,54 +520,3 @@
except OperationError, e:
e.write_unraisable(space, descrname, w_obj)
e.clear(space) # break up reference cycles
-
-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.gettrace() is None):
- return
- code = frame.pycode
- if frame.instr_lb <= frame.last_instr < frame.instr_ub:
- if frame.last_instr < frame.instr_prev_plus_one:
- # We jumped backwards in the same line.
- executioncontext._trace(frame, 'line', self.space.w_None)
- else:
- size = len(code.co_lnotab) / 2
- addr = 0
- line = code.co_firstlineno
- p = 0
- lineno = code.co_lnotab
- while size > 0:
- c = ord(lineno[p])
- if (addr + c) > frame.last_instr:
- break
- addr += c
- if c:
- frame.instr_lb = addr
-
- line += ord(lineno[p + 1])
- p += 2
- size -= 1
-
- if size > 0:
- while True:
- size -= 1
- if size < 0:
- break
- addr += ord(lineno[p])
- if ord(lineno[p + 1]):
- break
- p += 2
- frame.instr_ub = addr
- else:
- frame.instr_ub = sys.maxint
-
- if frame.instr_lb == frame.last_instr: # At start of line!
- frame.f_lineno = line
- executioncontext._trace(frame, 'line', self.space.w_None)
-
- frame.instr_prev_plus_one = frame.last_instr + 1
- self.space.frame_trace_action.fire() # continue tracing
diff --git a/pypy/interpreter/pyframe.py b/pypy/interpreter/pyframe.py
--- a/pypy/interpreter/pyframe.py
+++ b/pypy/interpreter/pyframe.py
@@ -464,8 +464,6 @@
new_frame.instr_prev_plus_one = space.int_w(w_instr_prev_plus_one)
self._setcellvars(cellvars)
- # XXX what if the frame is in another thread??
- space.frame_trace_action.fire()
def hide(self):
return self.pycode.hidden_applevel
@@ -759,7 +757,6 @@
else:
self.w_f_trace = w_trace
self.f_lineno = self.get_last_lineno()
- space.frame_trace_action.fire()
def fdel_f_trace(self, space):
self.w_f_trace = None
diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py
--- a/pypy/interpreter/pyopcode.py
+++ b/pypy/interpreter/pyopcode.py
@@ -144,9 +144,11 @@
def dispatch_bytecode(self, co_code, next_instr, ec):
while True:
self.last_instr = intmask(next_instr)
- if not jit.we_are_jitted():
+ if jit.we_are_jitted():
+ ec.bytecode_only_trace(self)
+ else:
ec.bytecode_trace(self)
- next_instr = r_uint(self.last_instr)
+ next_instr = r_uint(self.last_instr)
opcode = ord(co_code[next_instr])
next_instr += 1
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
@@ -425,6 +425,7 @@
loop, = log.loops_by_id('call', is_entry_bridge=True)
assert loop.match("""
guard_value(i4, 1, descr=...)
+ guard_isnull(p5, descr=...)
guard_nonnull_class(p12, ConstClass(W_IntObject), descr=...)
guard_value(i8, 0, descr=...)
guard_value(p2, ConstPtr(ptr21), descr=...)
More information about the pypy-commit
mailing list