[pypy-svn] r63726 - in pypy/branch/pyjitpl5-simplify/pypy/jit/metainterp: . test

arigo at codespeak.net arigo at codespeak.net
Mon Apr 6 17:24:45 CEST 2009


Author: arigo
Date: Mon Apr  6 17:24:44 2009
New Revision: 63726

Added:
   pypy/branch/pyjitpl5-simplify/pypy/jit/metainterp/test/test_recursive.py   (contents, props changed)
Modified:
   pypy/branch/pyjitpl5-simplify/pypy/jit/metainterp/codewriter.py
   pypy/branch/pyjitpl5-simplify/pypy/jit/metainterp/history.py
   pypy/branch/pyjitpl5-simplify/pypy/jit/metainterp/policy.py
   pypy/branch/pyjitpl5-simplify/pypy/jit/metainterp/pyjitpl.py
   pypy/branch/pyjitpl5-simplify/pypy/jit/metainterp/test/test_basic.py
   pypy/branch/pyjitpl5-simplify/pypy/jit/metainterp/warmspot.py
Log:
Recursive calls, first step.  I suspect the next issue is that
cpu.execute_operations() must change the value of the FAIL boxes,
which confuses metainterps currently deeper in the stack.


Modified: pypy/branch/pyjitpl5-simplify/pypy/jit/metainterp/codewriter.py
==============================================================================
--- pypy/branch/pyjitpl5-simplify/pypy/jit/metainterp/codewriter.py	(original)
+++ pypy/branch/pyjitpl5-simplify/pypy/jit/metainterp/codewriter.py	Mon Apr  6 17:24:44 2009
@@ -716,10 +716,6 @@
 ##                    self.emit('guard_len', self.var_position(arg),
 ##                              self.get_position(descr))
 
-    #def serialize_op_direct_call(self, op):
-    #    color = support.guess_call_kind(self.codewriter.hannotator, op)
-    #    return getattr(self, 'handle_%s_call' % color)(op)
-
     def serialize_op_direct_call(self, op):
         color = self.codewriter.policy.guess_call_kind(op)
         return getattr(self, 'handle_%s_call' % color)(op)
@@ -744,6 +740,8 @@
         self.emit_varargs([op.args[0]] + non_void_args)
         self.register_var(op.result)
 
+    handle_recursive_call = handle_residual_call     # for now
+
     def handle_builtin_call(self, op):
         oopspec_name, args = support.decode_builtin_call(op)
         argtypes = [v.concretetype for v in args]

Modified: pypy/branch/pyjitpl5-simplify/pypy/jit/metainterp/history.py
==============================================================================
--- pypy/branch/pyjitpl5-simplify/pypy/jit/metainterp/history.py	(original)
+++ pypy/branch/pyjitpl5-simplify/pypy/jit/metainterp/history.py	Mon Apr  6 17:24:44 2009
@@ -433,12 +433,14 @@
         raise NotImplementedError
 
 class History(RunningMatcher):
+    extratext = ''
     def record(self, opnum, argboxes, resbox, descr=None):
         op = ResOperation(opnum, argboxes, resbox, descr)
         self.operations.append(op)
         return op
 
 class BlackHole(RunningMatcher):
+    extratext = ' (BlackHole)'
     def record(self, opnum, argboxes, resbox, descr=None):
         return None
 

Modified: pypy/branch/pyjitpl5-simplify/pypy/jit/metainterp/policy.py
==============================================================================
--- pypy/branch/pyjitpl5-simplify/pypy/jit/metainterp/policy.py	(original)
+++ pypy/branch/pyjitpl5-simplify/pypy/jit/metainterp/policy.py	Mon Apr  6 17:24:44 2009
@@ -36,9 +36,13 @@
 
     def guess_call_kind(self, op):
         if op.opname == 'direct_call':
-            if getattr(op.args[0].value._obj, 'graph', None) is None:
+            funcobj = op.args[0].value._obj
+            if (hasattr(funcobj, '_callable') and
+                getattr(funcobj._callable, '_recursive_portal_call_', False)):
+                return 'recursive'
+            if getattr(funcobj, 'graph', None) is None:
                 return 'residual'
-            targetgraph = op.args[0].value._obj.graph
+            targetgraph = funcobj.graph
             if (hasattr(targetgraph, 'func') and
                 hasattr(targetgraph.func, 'oopspec')):
                 return 'builtin'

Modified: pypy/branch/pyjitpl5-simplify/pypy/jit/metainterp/pyjitpl.py
==============================================================================
--- pypy/branch/pyjitpl5-simplify/pypy/jit/metainterp/pyjitpl.py	(original)
+++ pypy/branch/pyjitpl5-simplify/pypy/jit/metainterp/pyjitpl.py	Mon Apr  6 17:24:44 2009
@@ -691,16 +691,10 @@
 
     @specialize.arg(1)
     def execute_with_exc(self, opnum, argboxes, descr=None):
-        cpu = self.metainterp.cpu
-        history.check_descr(descr)
-        resbox = executor.execute(cpu, opnum, argboxes, descr)
+        self.execute(opnum, argboxes, descr)
         if not we_are_translated():
             self.metainterp._debug_history.append(['call',
                                                   argboxes[0], argboxes[1:]])
-        # record the operation in the history
-        self.metainterp.history.record(opnum, argboxes, resbox, descr)
-        if resbox is not None:
-            self.make_result_box(resbox)
         return self.metainterp.handle_exception()
 
 # ____________________________________________________________
@@ -798,6 +792,9 @@
         self.current_merge_points = None
         self.resumekey = None
 
+    def set_blackhole_mode(self):
+        self.history = history.BlackHole(self.cpu)
+
     def _all_constants(self, boxes):
         for box in boxes:
             if not isinstance(box, Const):
@@ -806,6 +803,7 @@
 
     @specialize.arg(1)
     def execute_and_record(self, opnum, argboxes, descr=None):
+        old_framestack = self.framestack
         # execute the operation first
         history.check_descr(descr)
         resbox = executor.execute(self.cpu, opnum, argboxes, descr)
@@ -821,6 +819,13 @@
                 resbox = resbox.nonconstbox()    # ensure it is a Box
         else:
             assert resbox is None or isinstance(resbox, Box)
+            if opnum == rop.CALL:
+                # with executor.execute(rop.CALL), there is a risk of recursion
+                if self.framestack is not old_framestack:
+                    if not we_are_translated():
+                        history.log.info('recursion detected')
+                    self.framestack = old_framestack
+                    self.set_blackhole_mode()
         # record the operation if not constant-folded away
         if not canfold:
             self.history.record(opnum, argboxes, resbox, descr)
@@ -829,23 +834,19 @@
     def _interpret(self):
         # Execute the frames forward until we raise a DoneWithThisFrame,
         # a ContinueRunningNormally, or a GenerateMergePoint exception.
-        if isinstance(self.history, history.BlackHole):
-            text = ' (BlackHole)'
-        else:
-            text = ''
         if not we_are_translated():
-            history.log.event('ENTER' + text)
+            history.log.event('ENTER' + self.history.extratext)
             self.stats.enter_count += 1
         else:
-            debug_print('~~~ ENTER', text)
+            debug_print('~~~ ENTER', self.history.extratext)
         try:
             while True:
                 self.framestack[-1].run_one_step()
         finally:
             if not we_are_translated():
-                history.log.event('LEAVE' + text)
+                history.log.event('LEAVE' + self.history.extratext)
             else:
-                debug_print('~~~ LEAVE', text)
+                debug_print('~~~ LEAVE', self.history.extratext)
 
     def interpret(self):
         if we_are_translated():
@@ -1075,9 +1076,7 @@
                 self.history.operations.append(suboperations[i])
             self.extra_rebuild_operations = extra
         else:
-            self.history = history.BlackHole(self.cpu)
-            # the BlackHole is invalid because it doesn't start with
-            # guard_failure.key.guard_op.suboperations, but that's fine
+            self.set_blackhole_mode()
         self.rebuild_state_after_failure(resumedescr.resume_info,
                                          guard_failure.args)
 

Modified: pypy/branch/pyjitpl5-simplify/pypy/jit/metainterp/test/test_basic.py
==============================================================================
--- pypy/branch/pyjitpl5-simplify/pypy/jit/metainterp/test/test_basic.py	(original)
+++ pypy/branch/pyjitpl5-simplify/pypy/jit/metainterp/test/test_basic.py	Mon Apr  6 17:24:44 2009
@@ -41,6 +41,8 @@
         assert get_stats().compiled_count <= count
     def check_enter_count(self, count):
         assert get_stats().enter_count == count
+    def check_enter_count_at_most(self, count):
+        assert get_stats().enter_count <= count
     def check_jumps(self, maxcount):
         assert get_stats().exec_jumps <= maxcount
 

Added: pypy/branch/pyjitpl5-simplify/pypy/jit/metainterp/test/test_recursive.py
==============================================================================
--- (empty file)
+++ pypy/branch/pyjitpl5-simplify/pypy/jit/metainterp/test/test_recursive.py	Mon Apr  6 17:24:44 2009
@@ -0,0 +1,53 @@
+import py
+from pypy.rlib.jit import JitDriver
+from pypy.jit.metainterp.test.test_basic import LLJitMixin
+
+
+class RecursiveTests:
+
+    def test_simple_recursion(self):
+        myjitdriver = JitDriver(greens=[], reds=['n', 'm'])
+        def f(n):
+            m = n - 2
+            while True:
+                myjitdriver.jit_merge_point(n=n, m=m)
+                n -= 1
+                if m == n:
+                    return main(n) * 2
+                myjitdriver.can_enter_jit(n=n, m=m)
+        def main(n):
+            if n > 0:
+                return f(n+1)
+            else:
+                return 1
+        res = self.meta_interp(main, [20])
+        assert res == main(20)
+
+    def test_recursion_three_times(self):
+        py.test.skip("in-progress")
+        myjitdriver = JitDriver(greens=[], reds=['n', 'm', 'total'])
+        def f(n):
+            m = n - 3
+            total = 0
+            while True:
+                myjitdriver.jit_merge_point(n=n, m=m, total=total)
+                n -= 1
+                total += main(n)
+                if m == n:
+                    return total + 5
+                myjitdriver.can_enter_jit(n=n, m=m, total=total)
+        def main(n):
+            if n > 0:
+                return f(n)
+            else:
+                return 1
+        print
+        for i in range(1, 11):
+            print '%3d %9d' % (i, f(i))
+        res = self.meta_interp(main, [10])
+        assert res == main(10)
+        self.check_enter_count_at_most(6)
+
+
+class TestLLtype(RecursiveTests, LLJitMixin):
+    pass

Modified: pypy/branch/pyjitpl5-simplify/pypy/jit/metainterp/warmspot.py
==============================================================================
--- pypy/branch/pyjitpl5-simplify/pypy/jit/metainterp/warmspot.py	(original)
+++ pypy/branch/pyjitpl5-simplify/pypy/jit/metainterp/warmspot.py	Mon Apr  6 17:24:44 2009
@@ -107,10 +107,10 @@
         self.translator = translator
         self.build_meta_interp(**kwds)
         self.make_args_specification()
+        self.rewrite_jit_merge_point()
         self.metainterp.generate_bytecode(policy)
         self.make_enter_function()
         self.rewrite_can_enter_jit()
-        self.rewrite_jit_merge_point()
         self.metainterp.num_green_args = self.num_green_args
         self.metainterp.state = self.state
 
@@ -319,6 +319,7 @@
                     else:
                         value = cast_base_ptr_to_instance(Exception, value)
                         raise Exception, value
+        ll_portal_runner._recursive_portal_call_ = True
 
         portal_runner_ptr = self.helper_func(lltype.Ptr(PORTALFUNC),
                                              ll_portal_runner)



More information about the Pypy-commit mailing list