[pypy-svn] r57882 - in pypy/branch/garden-call-code-2/pypy/interpreter: . test

pedronis at codespeak.net pedronis at codespeak.net
Sat Sep 6 15:04:14 CEST 2008


Author: pedronis
Date: Sat Sep  6 15:04:07 2008
New Revision: 57882

Modified:
   pypy/branch/garden-call-code-2/pypy/interpreter/eval.py
   pypy/branch/garden-call-code-2/pypy/interpreter/function.py
   pypy/branch/garden-call-code-2/pypy/interpreter/pycode.py
   pypy/branch/garden-call-code-2/pypy/interpreter/test/test_function.py
Log:
Switch away from having fastcall_* methods on PyCode, calling python functions with more than 4 args is now a bit faster.
Noisy slow downs in some other corners though.



Modified: pypy/branch/garden-call-code-2/pypy/interpreter/eval.py
==============================================================================
--- pypy/branch/garden-call-code-2/pypy/interpreter/eval.py	(original)
+++ pypy/branch/garden-call-code-2/pypy/interpreter/eval.py	Sat Sep  6 15:04:07 2008
@@ -62,18 +62,6 @@
 
     def funcrun_obj(self, func, w_obj, args):
         return self.funcrun(func, args.prepend(w_obj))
-        
-    # a performance hack (see gateway.BuiltinCode1/2/3 and pycode.PyCode)
-    def fastcall_0(self, space, func):
-        raise NotImplementedError
-    def fastcall_1(self, space, func, w1):
-        raise NotImplementedError        
-    def fastcall_2(self, space, func, w1, w2):
-        raise NotImplementedError                
-    def fastcall_3(self, space, func, w1, w2, w3):
-        raise NotImplementedError
-    def fastcall_4(self, space, func, w1, w2, w3, w4):
-        raise NotImplementedError                                
 
 class Frame(Wrappable):
     """A frame is an environment supporting the execution of a code object.

Modified: pypy/branch/garden-call-code-2/pypy/interpreter/function.py
==============================================================================
--- pypy/branch/garden-call-code-2/pypy/interpreter/function.py	(original)
+++ pypy/branch/garden-call-code-2/pypy/interpreter/function.py	Sat Sep  6 15:04:07 2008
@@ -6,11 +6,14 @@
 attribute.
 """
 
+from pypy.rlib.unroll import unrolling_iterable
 from pypy.interpreter.error import OperationError
 from pypy.interpreter.baseobjspace import Wrappable
 from pypy.interpreter.eval import Code
 from pypy.interpreter.argument import Arguments, ArgumentsFromValuestack
 
+funccallunrolling = unrolling_iterable(range(4))
+
 class Function(Wrappable):
     """A function is a code object captured with some environment:
     an object space, a dictionary of globals, default arguments,
@@ -44,24 +47,40 @@
         return self.code
     
     def funccall(self, *args_w): # speed hack
+        from pypy.interpreter import gateway
+        from pypy.interpreter.pycode import PyCode
+        
         code = self.getcode() # hook for the jit
         nargs = len(args_w)
         fast_natural_arity = code.fast_natural_arity
         if nargs == fast_natural_arity:
             if nargs == 0:
+                assert isinstance(code, gateway.BuiltinCode0)                
                 return code.fastcall_0(self.space, self)
             elif nargs == 1:
+                assert isinstance(code, gateway.BuiltinCode1)
                 return code.fastcall_1(self.space, self, args_w[0])
             elif nargs == 2:
+                assert isinstance(code, gateway.BuiltinCode2)
                 return code.fastcall_2(self.space, self, args_w[0], args_w[1])
             elif nargs == 3:
+                assert isinstance(code, gateway.BuiltinCode3)                
                 return code.fastcall_3(self.space, self, args_w[0],
                                        args_w[1], args_w[2])
             elif nargs == 4:
+                assert isinstance(code, gateway.BuiltinCode4)                
                 return code.fastcall_4(self.space, self, args_w[0],
                                        args_w[1], args_w[2], args_w[3])
+        elif (nargs|PyCode.FLATPYCALL) == fast_natural_arity:
+            assert isinstance(code, PyCode)            
+            if nargs < 5:
+                new_frame = self.space.createframe(code, self.w_func_globals,
+                                                   self.closure)
+                for i in funccallunrolling:
+                    if i < nargs:
+                        new_frame.fastlocals_w[i] = args_w[i]
+                return new_frame.run()                                    
         elif nargs >= 1 and fast_natural_arity == -1:
-            from pypy.interpreter import gateway
             assert isinstance(code, gateway.BuiltinCodePassThroughArguments1)
             return code.funcrun_obj(self, args_w[0],
                                     Arguments(self.space,
@@ -70,37 +89,33 @@
 
     def funccall_valuestack(self, nargs, frame): # speed hack
         from pypy.interpreter import gateway
+        from pypy.interpreter.pycode import PyCode
+            
         code = self.getcode() # hook for the jit
         fast_natural_arity = code.fast_natural_arity        
         if nargs == fast_natural_arity:
-            from pypy.interpreter.pycode import PyCode
-            if type(code) is PyCode:
-                new_frame = self.space.createframe(code, self.w_func_globals,
-                                                   self.closure)
-                for i in xrange(nargs):
-                    w_arg = frame.peekvalue(nargs-1-i)
-                    new_frame.fastlocals_w[i] = w_arg
-                return new_frame.run()                
-            else:
-                if nargs == 0:
-                    assert isinstance(code, gateway.BuiltinCode0)
-                    return code.fastcall_0(self.space, self)
-                elif nargs == 1:
-                    assert isinstance(code, gateway.BuiltinCode1)
-                    return code.fastcall_1(self.space, self, frame.peekvalue(0))
-                elif nargs == 2:
-                    assert isinstance(code, gateway.BuiltinCode2)
-                    return code.fastcall_2(self.space, self, frame.peekvalue(1),
-                                           frame.peekvalue(0))
-                elif nargs == 3:
-                    assert isinstance(code, gateway.BuiltinCode3)
-                    return code.fastcall_3(self.space, self, frame.peekvalue(2),
-                                           frame.peekvalue(1), frame.peekvalue(0))
-                elif nargs == 4:
-                    assert isinstance(code, gateway.BuiltinCode4)
-                    return code.fastcall_4(self.space, self, frame.peekvalue(3),
-                                           frame.peekvalue(2), frame.peekvalue(1),
-                                            frame.peekvalue(0))
+            if nargs == 0:
+                assert isinstance(code, gateway.BuiltinCode0)
+                return code.fastcall_0(self.space, self)
+            elif nargs == 1:
+                assert isinstance(code, gateway.BuiltinCode1)
+                return code.fastcall_1(self.space, self, frame.peekvalue(0))
+            elif nargs == 2:
+                assert isinstance(code, gateway.BuiltinCode2)
+                return code.fastcall_2(self.space, self, frame.peekvalue(1),
+                                       frame.peekvalue(0))
+            elif nargs == 3:
+                assert isinstance(code, gateway.BuiltinCode3)
+                return code.fastcall_3(self.space, self, frame.peekvalue(2),
+                                       frame.peekvalue(1), frame.peekvalue(0))
+            elif nargs == 4:
+                assert isinstance(code, gateway.BuiltinCode4)
+                return code.fastcall_4(self.space, self, frame.peekvalue(3),
+                                       frame.peekvalue(2), frame.peekvalue(1),
+                                        frame.peekvalue(0))
+        elif (nargs|PyCode.FLATPYCALL) == fast_natural_arity:
+            assert isinstance(code, PyCode)
+            return self._flat_pycall(code, nargs, frame)
         elif fast_natural_arity == -1 and nargs >= 1:
             assert isinstance(code, gateway.BuiltinCodePassThroughArguments1)
             w_obj = frame.peekvalue(nargs-1)
@@ -118,6 +133,15 @@
             if isinstance(args, ArgumentsFromValuestack):
                 args.frame = None
 
+    def _flat_pycall(self, code, nargs, frame):
+        # code is a PyCode
+        new_frame = self.space.createframe(code, self.w_func_globals,
+                                                   self.closure)
+        for i in xrange(nargs):
+            w_arg = frame.peekvalue(nargs-1-i)
+            new_frame.fastlocals_w[i] = w_arg
+        return new_frame.run()                        
+
     def getdict(self):
         if self.w_func_dict is None:
             self.w_func_dict = self.space.newdict()

Modified: pypy/branch/garden-call-code-2/pypy/interpreter/pycode.py
==============================================================================
--- pypy/branch/garden-call-code-2/pypy/interpreter/pycode.py	(original)
+++ pypy/branch/garden-call-code-2/pypy/interpreter/pycode.py	Sat Sep  6 15:04:07 2008
@@ -108,7 +108,7 @@
                             self._args_as_cellvars.append(-1)   # pad
                         self._args_as_cellvars[i] = j
 
-        self._compute_fastcall()
+        self._compute_flatcall()
 
     co_names = property(lambda self: [self.space.unwrap(w_name) for w_name in self.co_names_w]) # for trace
 
@@ -159,51 +159,20 @@
                       freevars, cellvars, hidden_applevel)
 
     _code_new_w = staticmethod(_code_new_w)
+
+    FLATPYCALL = 0x100
     
-    def _compute_fastcall(self):
+    def _compute_flatcall(self):
         # Speed hack!
         self.fast_natural_arity = -99
         if self.co_flags & (CO_VARARGS | CO_VARKEYWORDS):
             return
         if len(self._args_as_cellvars) > 0:
             return
-
-        self.fast_natural_arity = self.co_argcount
-
-    def fastcall_0(self, space, w_func):
-        frame = space.createframe(self, w_func.w_func_globals,
-                                      w_func.closure)
-        return frame.run()
-
-    def fastcall_1(self, space, w_func, w_arg):
-        frame = space.createframe(self, w_func.w_func_globals,
-                                  w_func.closure)
-        frame.fastlocals_w[0] = w_arg # frame.setfastscope([w_arg])
-        return frame.run()
-
-    def fastcall_2(self, space, w_func, w_arg1, w_arg2):
-        frame = space.createframe(self, w_func.w_func_globals,
-                                  w_func.closure)
-        frame.fastlocals_w[0] = w_arg1 # frame.setfastscope([w_arg])
-        frame.fastlocals_w[1] = w_arg2
-        return frame.run()
-
-    def fastcall_3(self, space, w_func, w_arg1, w_arg2, w_arg3):
-        frame = space.createframe(self, w_func.w_func_globals,
-                                  w_func.closure)
-        frame.fastlocals_w[0] = w_arg1 # frame.setfastscope([w_arg])
-        frame.fastlocals_w[1] = w_arg2 
-        frame.fastlocals_w[2] = w_arg3 
-        return frame.run()
-
-    def fastcall_4(self, space, w_func, w_arg1, w_arg2, w_arg3, w_arg4):
-        frame = space.createframe(self, w_func.w_func_globals,
-                                  w_func.closure)
-        frame.fastlocals_w[0] = w_arg1 # frame.setfastscope([w_arg])
-        frame.fastlocals_w[1] = w_arg2 
-        frame.fastlocals_w[2] = w_arg3 
-        frame.fastlocals_w[3] = w_arg4 
-        return frame.run()
+        if self.co_argcount > 0xff:
+            return
+        
+        self.fast_natural_arity = PyCode.FLATPYCALL | self.co_argcount
 
     def funcrun(self, func, args):
         frame = self.space.createframe(self, func.w_func_globals,

Modified: pypy/branch/garden-call-code-2/pypy/interpreter/test/test_function.py
==============================================================================
--- pypy/branch/garden-call-code-2/pypy/interpreter/test/test_function.py	(original)
+++ pypy/branch/garden-call-code-2/pypy/interpreter/test/test_function.py	Sat Sep  6 15:04:07 2008
@@ -474,7 +474,7 @@
             code = PyCode._from_code(self.space, f.func_code)
             fn = Function(self.space, code, self.space.newdict())
 
-            assert fn.code.fast_natural_arity == i                 
+            assert fn.code.fast_natural_arity == i|PyCode.FLATPYCALL
             if i < 5:
 
                  def bomb(*args):
@@ -488,7 +488,7 @@
             check = space.is_true(space.eq(w_res, space.wrap(res)))
             assert check
 
-    def test_fastcall(self):
+    def test_flatcall(self):
         space = self.space
         
         def f(a):
@@ -496,7 +496,7 @@
         code = PyCode._from_code(self.space, f.func_code)
         fn = Function(self.space, code, self.space.newdict())
 
-        assert fn.code.fast_natural_arity == 1
+        assert fn.code.fast_natural_arity == 1|PyCode.FLATPYCALL
 
         def bomb(*args):
             assert False, "shortcutting should have avoided this"
@@ -515,7 +515,7 @@
 
         assert w_res is w_3
 
-    def test_fastcall_method(self):
+    def test_flatcall_method(self):
         space = self.space
         
         def f(self, a):
@@ -523,7 +523,7 @@
         code = PyCode._from_code(self.space, f.func_code)
         fn = Function(self.space, code, self.space.newdict())
 
-        assert fn.code.fast_natural_arity == 2
+        assert fn.code.fast_natural_arity == 2|PyCode.FLATPYCALL
 
         def bomb(*args):
             assert False, "shortcutting should have avoided this"



More information about the Pypy-commit mailing list