[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