[pypy-svn] r37681 - in pypy/branch/jit-virtual-world/pypy: annotation interpreter module/pypyjit module/pypyjit/test objspace/flow

arigo at codespeak.net arigo at codespeak.net
Wed Jan 31 18:36:34 CET 2007


Author: arigo
Date: Wed Jan 31 18:36:27 2007
New Revision: 37681

Added:
   pypy/branch/jit-virtual-world/pypy/module/pypyjit/test/   (props changed)
   pypy/branch/jit-virtual-world/pypy/module/pypyjit/test/test_jit_setup.py   (contents, props changed)
Modified:
   pypy/branch/jit-virtual-world/pypy/annotation/binaryop.py
   pypy/branch/jit-virtual-world/pypy/interpreter/eval.py
   pypy/branch/jit-virtual-world/pypy/interpreter/pyframe.py
   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/objspace/flow/flowcontext.py
Log:
Work in progress.  Modified the dispatch() header in a JIT-friendly and
overwhelmingly obscure way.  Exposes a bug avoid Void fields in
virtualizables.


Modified: pypy/branch/jit-virtual-world/pypy/annotation/binaryop.py
==============================================================================
--- pypy/branch/jit-virtual-world/pypy/annotation/binaryop.py	(original)
+++ pypy/branch/jit-virtual-world/pypy/annotation/binaryop.py	Wed Jan 31 18:36:27 2007
@@ -266,7 +266,7 @@
 
     def and_((int1, int2)):
         knowntype = rarithmetic.compute_restype(int1.knowntype, int2.knowntype)
-        return SomeInteger(nonneg=int1.nonneg and int2.nonneg,
+        return SomeInteger(nonneg=int1.nonneg or int2.nonneg,
                            knowntype=knowntype)
     and_.can_only_throw = []
 

Modified: pypy/branch/jit-virtual-world/pypy/interpreter/eval.py
==============================================================================
--- pypy/branch/jit-virtual-world/pypy/interpreter/eval.py	(original)
+++ pypy/branch/jit-virtual-world/pypy/interpreter/eval.py	Wed Jan 31 18:36:27 2007
@@ -73,6 +73,8 @@
     """A frame is an environment supporting the execution of a code object.
     Abstract base class."""
 
+    _virtualizable_ = True
+
     def __init__(self, space, w_globals=None, numlocals=-1):
         self.space      = space
         self.w_globals  = w_globals  # wrapped dict of globals

Modified: pypy/branch/jit-virtual-world/pypy/interpreter/pyframe.py
==============================================================================
--- pypy/branch/jit-virtual-world/pypy/interpreter/pyframe.py	(original)
+++ pypy/branch/jit-virtual-world/pypy/interpreter/pyframe.py	Wed Jan 31 18:36:27 2007
@@ -88,12 +88,12 @@
         executioncontext.enter(self)
         try:
             executioncontext.call_trace(self)
-            code = self.pycode.co_code
             # Execution starts just after the last_instr.  Initially,
             # last_instr is -1.  After a generator suspends it points to
             # the YIELD_VALUE instruction.
             next_instr = self.last_instr + 1
-            w_exitvalue = self.dispatch(code, next_instr, executioncontext)
+            w_exitvalue = self.dispatch(self.pycode, next_instr,
+                                        executioncontext)
             rstack.resume_point("execute_frame", self, executioncontext, returns=w_exitvalue)
             executioncontext.return_trace(self, w_exitvalue)
             # on exit, we try to release self.last_exception -- breaks an

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	Wed Jan 31 18:36:27 2007
@@ -4,6 +4,7 @@
 pyfastscope.py and pynestedscope.py.
 """
 
+import sys
 from pypy.interpreter.error import OperationError
 from pypy.interpreter.baseobjspace import UnpackValueError, Wrappable
 from pypy.interpreter import gateway, function, eval
@@ -40,7 +41,7 @@
     return func_with_new_name(opimpl, "opcode_impl_for_%s" % operationname)
 
 
-BYTECODE_TRACE_ENABLED = True   # see also pypy.module.pypyjit
+JITTING = False   # see also pypy.module.pypyjit
 
 
 class __extend__(pyframe.PyFrame):
@@ -49,12 +50,49 @@
     
     ### opcode dispatch ###
 
-    def dispatch(self, co_code, next_instr, ec):
+    def dispatch(self, pycode, next_instr, ec):
+        if JITTING:
+            hint(None, global_merge_point=True)
+
+            # *loads* of nonsense for now
+            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
+
+            pycode = hint(pycode, deepfrozen=True)
+            self.pycode = pycode
+            self.valuestackdepth = depth
+
+            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
+
         while True:
+            hint(None, global_merge_point=True)
             try:
-                w_result = self.dispatch_bytecode(co_code, next_instr, ec)
-                rstack.resume_point("dispatch", self, co_code, ec,
-                                    returns=w_result)
+                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)
+                #XXX
+                #rstack.resume_point("dispatch", self, co_code, ec,
+                #                    returns=w_result)
+            except Return:
+                w_result = self.popvalue()
                 return w_result
             except OperationError, operr:
                 next_instr = self.handle_operation_error(ec, operr)
@@ -78,6 +116,7 @@
                 next_instr = self.handle_asynchronous_error(ec,
                     self.space.w_RuntimeError,
                     self.space.wrap(msg))
+            next_instr = hint(next_instr, promote=True)
 
     def handle_asynchronous_error(self, ec, w_type, w_value=None):
         # catch asynchronous exceptions and turn them
@@ -92,8 +131,7 @@
         if attach_tb:
             pytraceback.record_application_traceback(
                 self.space, operr, self, self.last_instr)
-            if BYTECODE_TRACE_ENABLED:
-                ec.exception_trace(self, operr)
+            ec.exception_trace(self, operr)
 
         block = self.unrollstack(SApplicationException.kind)
         if block is None:
@@ -111,100 +149,93 @@
             return next_instr
 
     def dispatch_bytecode(self, co_code, next_instr, ec):
-        hint(None, global_merge_point=True)
-        next_instr = hint(r_uint(next_instr), promote=True)
         space = self.space
-        while True:
-            hint(None, global_merge_point=True)
-            self.last_instr = intmask(next_instr)
-            if BYTECODE_TRACE_ENABLED:
-                ec.bytecode_trace(self)
-                # For the sequel, force 'next_instr' to be unsigned for performance
-                next_instr = r_uint(self.last_instr)
+        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:
             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
+            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)
 
-            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 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)
+                #next_instr = hint(next_instr, promote=True)
+                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 Return
+
+        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:
-                    return w_returnvalue
+                    w_result = unroller.nomoreblocks()
+                    self.pushvalue(w_result)
+                    raise Return
                 else:
-                    unroller = SReturnValue(w_returnvalue)
                     next_instr = block.handle(self, unroller)
-                    next_instr = hint(next_instr, promote=True)
-                    continue    # now inside a 'finally' block
-
-            if opcode == opcodedesc.YIELD_VALUE.index:
-                #self.last_instr = intmask(next_instr - 1) XXX clean up!
-                w_yieldvalue = self.popvalue()
-                return w_yieldvalue
-
-            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:
-                        return unroller.nomoreblocks()
-                    else:
-                        next_instr = block.handle(self, unroller)
-                        next_instr = hint(next_instr, promote=True)
-                continue
+                    #next_instr = hint(next_instr, promote=True)
+            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
-                            next_instr = hint(next_instr, promote=True)
-                        break
-                else:
-                    self.MISSING_OPCODE(oparg, 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
+                        #next_instr = hint(next_instr, promote=True)
+                    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
-                    next_instr = hint(next_instr, promote=True)
+        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
 
     def unrollstack(self, unroller_kind):
         while len(self.blockstack) > 0:
@@ -223,17 +254,20 @@
 
     ### accessor functions ###
 
+    def getcode(self):
+        return hint(self.pycode, deepfrozen=True)
+
     def getlocalvarname(self, index):
-        return self.pycode.co_varnames[index]
+        return self.getcode().co_varnames[index]
 
     def getconstant_w(self, index):
-        return self.pycode.co_consts_w[index]
+        return self.getcode().co_consts_w[index]
 
     def getname_u(self, index):
-        return self.space.str_w(self.pycode.co_names_w[index])
+        return self.space.str_w(self.getcode().co_names_w[index])
 
     def getname_w(self, index):
-        return self.pycode.co_names_w[index]
+        return self.getcode().co_names_w[index]
 
 
     ################################################################
@@ -913,6 +947,9 @@
     """Signal an application-level OperationError that should not grow
     a new traceback entry nor trigger the trace hook."""
 
+class Return(Exception):
+    """Obscure."""
+
 class BytecodeCorruption(Exception):
     """Detected bytecode corruption.  Never caught; it's an error."""
 

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	Wed Jan 31 18:36:27 2007
@@ -15,78 +15,35 @@
 
 PyCode.jit_enable = False     # new default attribute
 super_dispatch = PyFrame.dispatch
-super_dispatch_bytecode = PyFrame.dispatch_bytecode
 
 
 def setup():
-    # create dispatch_jit() as a copy of dispatch() in which
-    # dispatch_bytecode() has been manually inlined.
-    # Do this with py.code.Source manipulations for now.
-    src = py.code.Source(super_dispatch)
-    CALL_SITE = 'w_result = self.dispatch_bytecode(co_code, next_instr, ec)'
-    for i, line in enumerate(src):
-        if line.strip() == CALL_SITE:
-            break
-    else:
-        raise Exception("fix me!  call to dispatch_bytecode() not found")
-
-    indent = line[:line.index(CALL_SITE)]
-
-    src2 = py.code.Source(PyFrame.dispatch_bytecode)
-    hdr = src2[0].strip()
-    assert hdr == 'def dispatch_bytecode(self, co_code, next_instr, ec):'
-    src2 = src2[1:].deindent().indent(indent)
-    #print src2
-
-    src3 = py.code.Source('%s\n%s\n%s\n' % (src[1:i], src2, src[i+1:]))
-
-    src3 = src3.putaround(
-                  "def maker(BYTECODE_TRACE_ENABLED):\n" # no comma here
-                  "  def dispatch_jit(self, co_code, next_instr, ec):\n",
-                  "#\n" # for indentation :-(
-                  "  return dispatch_jit")
-  
-    #print src3
-    d = {}
-    exec src3.compile() in super_dispatch.func_globals, d
-    PyFrame.dispatch_jit = d['maker'](BYTECODE_TRACE_ENABLED=False)
-
-    class __extend__(PyFrame):
-
-        def dispatch(self, co_code, next_instr, ec):
-            if self.pycode.jit_enable:
-                return self.dispatch_jit(co_code, next_instr, ec)
-            else:
-                return super_dispatch(self, co_code, next_instr, ec)
-
-def setup2():
-    # TEMPORARY: only patches dispatch_bytecode.
-    # make a copy of dispatch_bytecode in which BYTECODE_TRACE_ENABLED is False
+    # make a copy of dispatch in which JITTING is True
     # (hack hack!)
-    src2 = py.code.Source(PyFrame.dispatch_bytecode)
+    src2 = py.code.Source(PyFrame.dispatch)
     hdr = src2[0].strip()
-    assert hdr == 'def dispatch_bytecode(self, co_code, next_instr, ec):'
+    assert hdr == 'def dispatch(self, pycode, next_instr, ec):'
     src2 = src2[1:].deindent()
 
     src2 = src2.putaround(
-                  "def maker(BYTECODE_TRACE_ENABLED):\n" # no comma here
-                  "  def dispatch_jit(self, co_code, next_instr, ec):\n",
+                  "def maker(JITTING):\n"
+                  "  def dispatch_jit(self, pycode, next_instr, ec):\n",
                   "#\n" # for indentation :-(
                   "  return dispatch_jit")
-    #print src2
+    print src2
     d = {}
     exec src2.compile() in super_dispatch.func_globals, d
-    PyFrame.dispatch_jit = d['maker'](BYTECODE_TRACE_ENABLED=False)
+    PyFrame.dispatch_jit = d['maker'](JITTING=True)
 
     class __extend__(PyFrame):
 
-        def dispatch_bytecode(self, co_code, next_instr, ec):
-            if self.pycode.jit_enable:
-                return self.dispatch_jit(co_code, next_instr, ec)
+        def dispatch(self, pycode, next_instr, ec):
+            if pycode.jit_enable:
+                return self.dispatch_jit(pycode, next_instr, ec)
             else:
-                return super_dispatch_bytecode(self, co_code, next_instr, ec)
+                return super_dispatch(self, pycode, next_instr, ec)
 
-setup2()
+setup()
 
 PORTAL = PyFrame.dispatch_jit
 

Added: pypy/branch/jit-virtual-world/pypy/module/pypyjit/test/test_jit_setup.py
==============================================================================
--- (empty file)
+++ pypy/branch/jit-virtual-world/pypy/module/pypyjit/test/test_jit_setup.py	Wed Jan 31 18:36:27 2007
@@ -0,0 +1,18 @@
+from pypy.conftest import gettestobjspace
+
+class AppTestPyPyJIT:
+    def setup_class(cls):
+        space = gettestobjspace(usemodules=('pypyjit',))
+        cls.space = space
+
+    def test_setup(self):
+        # this just checks that setup() is doing its job correctly, and
+        # the resulting code makes sense on top of CPython.
+        import pypyjit
+
+        def f(x, y):
+            return x*y+1
+
+        assert f(6, 7) == 43
+        pypyjit.enable(f.func_code)
+        assert f(6, 7) == 43

Modified: pypy/branch/jit-virtual-world/pypy/objspace/flow/flowcontext.py
==============================================================================
--- pypy/branch/jit-virtual-world/pypy/objspace/flow/flowcontext.py	(original)
+++ pypy/branch/jit-virtual-world/pypy/objspace/flow/flowcontext.py	Wed Jan 31 18:36:27 2007
@@ -262,7 +262,7 @@
                 self.framestack.push(frame)
                 self.crnt_frame = frame
                 try:
-                    w_result = frame.dispatch(frame.pycode.co_code,
+                    w_result = frame.dispatch(frame.pycode,
                                               frame.last_instr,
                                               self)
                 finally:



More information about the Pypy-commit mailing list