[pypy-svn] r40594 - in pypy/branch/jit-virtual-world/pypy: interpreter module/pypyjit module/pypyjit/test

pedronis at codespeak.net pedronis at codespeak.net
Fri Mar 16 18:04:06 CET 2007


Author: pedronis
Date: Fri Mar 16 18:04:02 2007
New Revision: 40594

Modified:
   pypy/branch/jit-virtual-world/pypy/interpreter/pyopcode.py
   pypy/branch/jit-virtual-world/pypy/module/pypyjit/interp_jit.py
   pypy/branch/jit-virtual-world/pypy/module/pypyjit/test/test_jit_setup.py
Log:
(arigo, pedronis)

trying to improve the readability of jit changes to dispatch loop, we made the portal dispatch_jit a manual copy
which uses factored out helpers, the common logic is now factored out in PyFrame.handle_bytecode.
In the non timeshifted case dispatch_bytecode is still looping instead of doing one bytecode at a time.



Modified: pypy/branch/jit-virtual-world/pypy/interpreter/pyopcode.py
==============================================================================
--- pypy/branch/jit-virtual-world/pypy/interpreter/pyopcode.py	(original)
+++ pypy/branch/jit-virtual-world/pypy/interpreter/pyopcode.py	Fri Mar 16 18:04:02 2007
@@ -10,9 +10,9 @@
 from pypy.interpreter import gateway, function, eval
 from pypy.interpreter import pyframe, pytraceback
 from pypy.interpreter.argument import Arguments
-from pypy.interpreter.pycode import PyCode, CO_VARARGS, CO_VARKEYWORDS
+from pypy.interpreter.pycode import PyCode
 from pypy.tool.sourcetools import func_with_new_name
-from pypy.rlib.objectmodel import we_are_translated, hint
+from pypy.rlib.objectmodel import we_are_translated, hint, we_are_jitted
 from pypy.rlib.rarithmetic import r_uint, intmask
 from pypy.tool.stdlib_opcode import opcodedesc, HAVE_ARGUMENT
 from pypy.tool.stdlib_opcode import unrolling_opcode_descs
@@ -51,123 +51,49 @@
     ### opcode dispatch ###
 
     def dispatch(self, pycode, next_instr, ec):
-        if JITTING:
-            hint(None, global_merge_point=True)
-            pycode = hint(pycode, deepfreeze=True)
-            # *loads* of nonsense for now
-
-            fastlocals_w = [None] * pycode.co_nlocals
-
-            if next_instr == 0:
-                # first time we enter this function
-                depth = 0
-                self.blockstack = []
-
-                numargs = pycode.co_argcount
-                if pycode.co_flags & CO_VARARGS:     numargs += 1
-                if pycode.co_flags & CO_VARKEYWORDS: numargs += 1
-                while True:
-                    numargs -= 1
-                    if numargs < 0:
-                        break
-                    hint(numargs, concrete=True)
-                    w_obj = self.fastlocals_w[numargs]
-                    assert w_obj is not None
-                    fastlocals_w[numargs] = w_obj
-
-            else:
-                stuff = self.valuestackdepth
-                if len(self.blockstack):
-                    stuff |= (-sys.maxint-1)
-
-                stuff = hint(stuff, promote=True)
-                if stuff >= 0:
-                    # blockdepth == 0, common case
-                    self.blockstack = []
-                depth = stuff & sys.maxint
-
-                i = pycode.co_nlocals
-                while True:
-                    i -= 1
-                    if i < 0:
-                        break
-                    hint(i, concrete=True)
-                    w_obj = self.fastlocals_w[i]
-                    fastlocals_w[i] = w_obj
-
-            self.pycode = pycode
-            self.valuestackdepth = depth
-
-            entry_fastlocals_w = self.fastlocals_w
-            self.fastlocals_w = fastlocals_w
-
-            virtualstack_w = [None] * pycode.co_stacksize
-            while depth > 0:
-                depth -= 1
-                hint(depth, concrete=True)
-                virtualstack_w[depth] = self.valuestack_w[depth]
-            self.valuestack_w = virtualstack_w
-
         # For the sequel, force 'next_instr' to be unsigned for performance
         next_instr = r_uint(next_instr)
         co_code = pycode.co_code
 
         try:
-          while True:
-            hint(None, global_merge_point=True)
-            try:
-                self.last_instr = intmask(next_instr)
-                if not JITTING:
-                    ec.bytecode_trace(self)
-                    next_instr = r_uint(self.last_instr)
-                next_instr = self.dispatch_bytecode(co_code, next_instr, ec)
+            while True:
+                next_instr = self.handle_bytecode(co_code, next_instr, ec)
                 #XXX
                 #rstack.resume_point("dispatch", self, co_code, ec,
                 #                    returns=w_result)
-            except Return:
-                w_result = self.popvalue()
-                if JITTING:
-                    self.blockstack = None
-                    self.valuestack_w = None
-                return w_result
-            except Yield:
-                w_result = self.popvalue()
-                return w_result
-            except OperationError, operr:
-                next_instr = self.handle_operation_error(ec, operr)
-            except Reraise:
-                operr = self.last_exception
-                next_instr = self.handle_operation_error(ec, operr,
-                                                         attach_tb=False)
-            except KeyboardInterrupt:
-                next_instr = self.handle_asynchronous_error(ec,
-                    self.space.w_KeyboardInterrupt)
-            except MemoryError:
-                next_instr = self.handle_asynchronous_error(ec,
-                    self.space.w_MemoryError)
-            except RuntimeError, e:
-                if we_are_translated():
-                    # stack overflows should be the only kind of RuntimeErrors
-                    # in translated PyPy
-                    msg = "internal error (stack overflow?)"
-                else:
-                    msg = str(e)
-                next_instr = self.handle_asynchronous_error(ec,
-                    self.space.w_RuntimeError,
-                    self.space.wrap(msg))
-        finally:
-            if JITTING:
-                i = pycode.co_nlocals
-                while True:
-                    i -= 1
-                    if i < 0:
-                        break
-                    hint(i, concrete=True)
-                    entry_fastlocals_w[i] = self.fastlocals_w[i]
-
-                self.fastlocals_w = entry_fastlocals_w
-            
+        except ExitFrame:
+            return self.popvalue()
 
+    def handle_bytecode(self, co_code, next_instr, ec):
+        try:
+            next_instr = self.dispatch_bytecode(co_code, next_instr, ec)
+            #XXX
+            #rstack.resume_point("dispatch", self, co_code, ec,
+            #                    returns=w_result)
+        except OperationError, operr:
+            next_instr = self.handle_operation_error(ec, operr)
+        except Reraise:
+            operr = self.last_exception
+            next_instr = self.handle_operation_error(ec, operr,
+                                                     attach_tb=False)
+        except KeyboardInterrupt:
+            next_instr = self.handle_asynchronous_error(ec,
+                self.space.w_KeyboardInterrupt)
+        except MemoryError:
+            next_instr = self.handle_asynchronous_error(ec,
+                self.space.w_MemoryError)
+        except RuntimeError, e:
+            if we_are_translated():
+                # stack overflows should be the only kind of RuntimeErrors
+                # in translated PyPy
+                msg = "internal error (stack overflow?)"
+            else:
+                msg = str(e)
+            next_instr = self.handle_asynchronous_error(ec,
+                self.space.w_RuntimeError,
+                self.space.wrap(msg))
+        return next_instr
+        
     def handle_asynchronous_error(self, ec, w_type, w_value=None):
         # catch asynchronous exceptions and turn them
         # into OperationErrors
@@ -181,7 +107,8 @@
         if attach_tb:
             pytraceback.record_application_traceback(
                 self.space, operr, self, self.last_instr)
-            ec.exception_trace(self, operr)
+            if not we_are_jitted():
+                ec.exception_trace(self, operr)
 
         block = self.unrollstack(SApplicationException.kind)
         if block is None:
@@ -200,89 +127,96 @@
 
     def dispatch_bytecode(self, co_code, next_instr, ec):
         space = self.space
-        opcode = ord(co_code[next_instr])
-        next_instr += 1
-        if space.config.objspace.logbytecodes:
-            space.bytecodecounts[opcode] = space.bytecodecounts.get(opcode, 0) + 1
-
-        if opcode >= HAVE_ARGUMENT:
-            lo = ord(co_code[next_instr])
-            hi = ord(co_code[next_instr+1])
-            next_instr += 2
-            oparg = (hi << 8) | lo
-        else:
-            oparg = 0
-        hint(opcode, concrete=True)
-        hint(oparg, concrete=True)
-
-        while opcode == opcodedesc.EXTENDED_ARG.index:
+        while True:
+            self.last_instr = intmask(next_instr)
+            if not we_are_jitted():
+                ec.bytecode_trace(self)
+                next_instr = r_uint(self.last_instr)
             opcode = ord(co_code[next_instr])
-            if opcode < HAVE_ARGUMENT:
-                raise BytecodeCorruption
-            lo = ord(co_code[next_instr+1])
-            hi = ord(co_code[next_instr+2])
-            next_instr += 3
-            oparg = (oparg << 16) | (hi << 8) | lo
+            next_instr += 1
+            if space.config.objspace.logbytecodes:
+                space.bytecodecounts[opcode] = space.bytecodecounts.get(opcode, 0) + 1
+
+            if opcode >= HAVE_ARGUMENT:
+                lo = ord(co_code[next_instr])
+                hi = ord(co_code[next_instr+1])
+                next_instr += 2
+                oparg = (hi << 8) | lo
+            else:
+                oparg = 0
             hint(opcode, concrete=True)
             hint(oparg, concrete=True)
 
-        if opcode == opcodedesc.RETURN_VALUE.index:
-            w_returnvalue = self.popvalue()
-            block = self.unrollstack(SReturnValue.kind)
-            if block is None:
-                self.pushvalue(w_returnvalue)   # XXX ping pong
-                raise Return
-            else:
-                unroller = SReturnValue(w_returnvalue)
-                next_instr = block.handle(self, unroller)
-                return next_instr    # now inside a 'finally' block
-
-        if opcode == opcodedesc.YIELD_VALUE.index:
-            #self.last_instr = intmask(next_instr - 1) XXX clean up!
-            raise Yield
-
-        if opcode == opcodedesc.END_FINALLY.index:
-            unroller = self.end_finally()
-            if isinstance(unroller, SuspendedUnroller):
-                # go on unrolling the stack
-                block = self.unrollstack(unroller.kind)
+            while opcode == opcodedesc.EXTENDED_ARG.index:
+                opcode = ord(co_code[next_instr])
+                if opcode < HAVE_ARGUMENT:
+                    raise BytecodeCorruption
+                lo = ord(co_code[next_instr+1])
+                hi = ord(co_code[next_instr+2])
+                next_instr += 3
+                oparg = (oparg << 16) | (hi << 8) | lo
+                hint(opcode, concrete=True)
+                hint(oparg, concrete=True)
+
+            if opcode == opcodedesc.RETURN_VALUE.index:
+                w_returnvalue = self.popvalue()
+                block = self.unrollstack(SReturnValue.kind)
                 if block is None:
-                    w_result = unroller.nomoreblocks()
-                    self.pushvalue(w_result)
+                    self.pushvalue(w_returnvalue)   # XXX ping pong
                     raise Return
                 else:
+                    unroller = SReturnValue(w_returnvalue)
                     next_instr = block.handle(self, unroller)
-            return next_instr
+                    return next_instr    # now inside a 'finally' block
 
-        if we_are_translated():
-            for opdesc in unrolling_opcode_descs:
-                # static checks to skip this whole case if necessary
-                if not opdesc.is_enabled(space):
-                    continue
-                if not hasattr(pyframe.PyFrame, opdesc.methodname):
-                    continue   # e.g. for JUMP_FORWARD, implemented above
-
-                if opcode == opdesc.index:
-                    # dispatch to the opcode method
-                    meth = getattr(self, opdesc.methodname)
-                    res = meth(oparg, next_instr)
-                    if opdesc.index == opcodedesc.CALL_FUNCTION.index:
-                        rstack.resume_point("dispatch_call", self, co_code, next_instr, ec)
-                    # !! warning, for the annotator the next line is not
-                    # comparing an int and None - you can't do that.
-                    # Instead, it's constant-folded to either True or False
-                    if res is not None:
-                        next_instr = res
-                    break
-            else:
-                self.MISSING_OPCODE(oparg, next_instr)
+            if opcode == opcodedesc.YIELD_VALUE.index:
+                #self.last_instr = intmask(next_instr - 1) XXX clean up!
+                raise Yield
+
+            if opcode == opcodedesc.END_FINALLY.index:
+                unroller = self.end_finally()
+                if isinstance(unroller, SuspendedUnroller):
+                    # go on unrolling the stack
+                    block = self.unrollstack(unroller.kind)
+                    if block is None:
+                        w_result = unroller.nomoreblocks()
+                        self.pushvalue(w_result)
+                        raise Return
+                    else:
+                        next_instr = block.handle(self, unroller)
+                return next_instr
 
-        else:  # when we are not translated, a list lookup is much faster
-            methodname = opcode_method_names[opcode]
-            res = getattr(self, methodname)(oparg, next_instr)
-            if res is not None:
-                next_instr = res
-        return next_instr
+            if we_are_translated():
+                for opdesc in unrolling_opcode_descs:
+                    # static checks to skip this whole case if necessary
+                    if not opdesc.is_enabled(space):
+                        continue
+                    if not hasattr(pyframe.PyFrame, opdesc.methodname):
+                        continue   # e.g. for JUMP_FORWARD, implemented above
+
+                    if opcode == opdesc.index:
+                        # dispatch to the opcode method
+                        meth = getattr(self, opdesc.methodname)
+                        res = meth(oparg, next_instr)
+                        if opdesc.index == opcodedesc.CALL_FUNCTION.index:
+                            rstack.resume_point("dispatch_call", self, co_code, next_instr, ec)
+                        # !! warning, for the annotator the next line is not
+                        # comparing an int and None - you can't do that.
+                        # Instead, it's constant-folded to either True or False
+                        if res is not None:
+                            next_instr = res
+                        break
+                else:
+                    self.MISSING_OPCODE(oparg, next_instr)
+
+            else:  # when we are not translated, a list lookup is much faster
+                methodname = opcode_method_names[opcode]
+                res = getattr(self, methodname)(oparg, next_instr)
+                if res is not None:
+                    next_instr = res
+
+            if we_are_jitted():
+                return next_instr
 
     def unrollstack(self, unroller_kind):
         n = len(self.blockstack)
@@ -895,7 +829,7 @@
         
     def CALL_FUNCTION(f, oparg, *ignored):
         # XXX start of hack for performance
-        if (oparg >> 8) & 0xff == 0:
+        if not we_are_jitted() and (oparg >> 8) & 0xff == 0:
             # Only positional arguments
             nargs = oparg & 0xff
             w_function = f.peekvalue(nargs)
@@ -986,9 +920,12 @@
     """Signal an application-level OperationError that should not grow
     a new traceback entry nor trigger the trace hook."""
 
-class Return(Exception):
+class ExitFrame(Exception):
+    pass
+
+class Return(ExitFrame):
     """Obscure."""
-class Yield(Exception):
+class Yield(ExitFrame):
     """Obscure."""
 
 class BytecodeCorruption(Exception):

Modified: pypy/branch/jit-virtual-world/pypy/module/pypyjit/interp_jit.py
==============================================================================
--- pypy/branch/jit-virtual-world/pypy/module/pypyjit/interp_jit.py	(original)
+++ pypy/branch/jit-virtual-world/pypy/module/pypyjit/interp_jit.py	Fri Mar 16 18:04:02 2007
@@ -7,47 +7,120 @@
 pypy/jit/*
 """
 import py
+import sys
+from pypy.rlib.rarithmetic import r_uint, intmask
+from pypy.rlib.objectmodel import hint
 import pypy.interpreter.pyopcode   # for side-effects
-from pypy.interpreter.pycode import PyCode
+from pypy.interpreter.pycode import PyCode, CO_VARARGS, CO_VARKEYWORDS
 from pypy.interpreter.pyframe import PyFrame
-from pypy.tool.sourcetools import func_with_new_name
+from pypy.interpreter.pyopcode import Return, Yield
 
 
 PyCode.jit_enable = False     # new default attribute
 super_dispatch = PyFrame.dispatch
 
 
-def setup():
-    # make a copy of dispatch in which JITTING is True
-    # (hack hack!)
-    src2 = py.code.Source(PyFrame.dispatch)
-    hdr = src2[0].strip()
-    assert hdr == 'def dispatch(self, pycode, next_instr, ec):'
-    src2 = src2[1:].deindent()
-
-    src2 = src2.putaround(
-                  "def maker(JITTING):\n"
-                  "  def dispatch_jit(self, pycode, next_instr, ec):\n",
-                  "#\n" # for indentation :-(
-                  "  return dispatch_jit")
-    print src2
-    d = {}
-    exec src2.compile() in super_dispatch.func_globals, d
-    PyFrame.dispatch_jit = d['maker'](JITTING=True)
-
-    class __extend__(PyFrame):
-
-        def dispatch(self, pycode, next_instr, ec):
-            if pycode.jit_enable:
-                return self.dispatch_jit(pycode, next_instr, ec)
-            else:
-                return super_dispatch(self, pycode, next_instr, ec)
-
-        def CALL_FUNCTION(f, oparg, *ignored):
-            # XXX disable the call_valuestack hacks which are bad for the JIT
-            return f.call_function(oparg)
+class __extend__(PyFrame):
+
+    def dispatch(self, pycode, next_instr, ec):
+        if pycode.jit_enable:
+            return self.dispatch_jit(pycode, next_instr, ec)
+        else:
+            return super_dispatch(self, pycode, next_instr, ec)
+            
+    def dispatch_jit(self, pycode, next_instr, ec):
+        hint(None, global_merge_point=True)
+        pycode = hint(pycode, deepfreeze=True)
+
+        entry_fastlocals_w = self.jit_enter_frame(pycode, next_instr)
+
+        # For the sequel, force 'next_instr' to be unsigned for performance
+        next_instr = r_uint(next_instr)
+        co_code = pycode.co_code
+
+        try:
+            try:
+                while True:
+                    hint(None, global_merge_point=True)
+                    next_instr = self.handle_bytecode(co_code, next_instr, ec)
+            except Return:
+                w_result = self.popvalue()
+                self.blockstack = None
+                self.valuestack_w = None
+                return w_result
+            except Yield:
+                w_result = self.popvalue()
+                return w_result
+        finally:
+            self.jit_leave_frame(pycode, entry_fastlocals_w)
+
+    def jit_enter_frame(self, pycode, next_instr):
+        # *loads* of nonsense for now
+
+        fastlocals_w = [None] * pycode.co_nlocals
+
+        if next_instr == 0:
+            # first time we enter this function
+            depth = 0
+            self.blockstack = []
+
+            numargs = pycode.co_argcount
+            if pycode.co_flags & CO_VARARGS:     numargs += 1
+            if pycode.co_flags & CO_VARKEYWORDS: numargs += 1
+            while True:
+                numargs -= 1
+                if numargs < 0:
+                    break
+                hint(numargs, concrete=True)
+                w_obj = self.fastlocals_w[numargs]
+                assert w_obj is not None
+                fastlocals_w[numargs] = w_obj
+
+        else:
+            stuff = self.valuestackdepth
+            if len(self.blockstack):
+                stuff |= (-sys.maxint-1)
+
+            stuff = hint(stuff, promote=True)
+            if stuff >= 0:
+                # blockdepth == 0, common case
+                self.blockstack = []
+            depth = stuff & sys.maxint
+
+            i = pycode.co_nlocals
+            while True:
+                i -= 1
+                if i < 0:
+                    break
+                hint(i, concrete=True)
+                w_obj = self.fastlocals_w[i]
+                fastlocals_w[i] = w_obj
+
+        self.pycode = pycode
+        self.valuestackdepth = depth
+
+        entry_fastlocals_w = self.fastlocals_w
+        self.fastlocals_w = fastlocals_w
+
+        virtualstack_w = [None] * pycode.co_stacksize
+        while depth > 0:
+            depth -= 1
+            hint(depth, concrete=True)
+            virtualstack_w[depth] = self.valuestack_w[depth]
+        self.valuestack_w = virtualstack_w
+        return entry_fastlocals_w
+
+    def jit_leave_frame(self, pycode, entry_fastlocals_w):
+        i = pycode.co_nlocals
+        while True:
+            i -= 1
+            if i < 0:
+                break
+            hint(i, concrete=True)
+            entry_fastlocals_w[i] = self.fastlocals_w[i]
+
+        self.fastlocals_w = entry_fastlocals_w
 
-setup()
 
 PORTAL = PyFrame.dispatch_jit
 

Modified: pypy/branch/jit-virtual-world/pypy/module/pypyjit/test/test_jit_setup.py
==============================================================================
--- pypy/branch/jit-virtual-world/pypy/module/pypyjit/test/test_jit_setup.py	(original)
+++ pypy/branch/jit-virtual-world/pypy/module/pypyjit/test/test_jit_setup.py	Fri Mar 16 18:04:02 2007
@@ -6,7 +6,7 @@
         cls.space = space
 
     def test_setup(self):
-        # this just checks that setup() is doing its job correctly, and
+        # this just checks that the module is setting up things correctly, and
         # the resulting code makes sense on top of CPython.
         import pypyjit
 



More information about the Pypy-commit mailing list