[pypy-svn] r34975 - in pypy/branch/builtin-call-speedup: lib-python/modified-2.4.1 pypy/config pypy/interpreter pypy/interpreter/astcompiler pypy/module/__builtin__ pypy/module/__builtin__/test pypy/objspace/std

cfbolz at codespeak.net cfbolz at codespeak.net
Sat Nov 25 23:39:04 CET 2006


Author: cfbolz
Date: Sat Nov 25 23:38:59 2006
New Revision: 34975

Added:
   pypy/branch/builtin-call-speedup/pypy/objspace/std/warydictobject.py
Modified:
   pypy/branch/builtin-call-speedup/lib-python/modified-2.4.1/opcode.py
   pypy/branch/builtin-call-speedup/pypy/config/pypyoption.py
   pypy/branch/builtin-call-speedup/pypy/interpreter/astcompiler/pycodegen.py
   pypy/branch/builtin-call-speedup/pypy/interpreter/module.py
   pypy/branch/builtin-call-speedup/pypy/interpreter/pycode.py
   pypy/branch/builtin-call-speedup/pypy/module/__builtin__/__init__.py
   pypy/branch/builtin-call-speedup/pypy/module/__builtin__/test/test_builtin.py
   pypy/branch/builtin-call-speedup/pypy/objspace/std/model.py
   pypy/branch/builtin-call-speedup/pypy/objspace/std/objspace.py
Log:
first round of trying to make builtin lookups faster (nearly as fast as a local
lookup) while still behaving correctly when builtins are shadowed.


Modified: pypy/branch/builtin-call-speedup/lib-python/modified-2.4.1/opcode.py
==============================================================================
--- pypy/branch/builtin-call-speedup/lib-python/modified-2.4.1/opcode.py	(original)
+++ pypy/branch/builtin-call-speedup/lib-python/modified-2.4.1/opcode.py	Sat Nov 25 23:38:59 2006
@@ -187,4 +187,7 @@
 def_op('EXTENDED_ARG', 143)
 EXTENDED_ARG = 143
 
+# pypy modification, experimental bytecode
+def_op('CALL_LIKELY_BUILTIN', 144)    # #args + (#kwargs << 8)
+
 del def_op, name_op, jrel_op, jabs_op

Modified: pypy/branch/builtin-call-speedup/pypy/config/pypyoption.py
==============================================================================
--- pypy/branch/builtin-call-speedup/pypy/config/pypyoption.py	(original)
+++ pypy/branch/builtin-call-speedup/pypy/config/pypyoption.py	Sat Nov 25 23:38:59 2006
@@ -59,6 +59,9 @@
                    "keep track of bytecode usage",
                    default=False),
 
+        BoolOption("withfastbuiltins", "speed up calls to builtin functions",
+                   default=False, requires=[("objspace.usepycfiles", False)]),
+
         BoolOption("usepycfiles", "Write and read pyc files when importing",
                    default=True),
        

Modified: pypy/branch/builtin-call-speedup/pypy/interpreter/astcompiler/pycodegen.py
==============================================================================
--- pypy/branch/builtin-call-speedup/pypy/interpreter/astcompiler/pycodegen.py	(original)
+++ pypy/branch/builtin-call-speedup/pypy/interpreter/astcompiler/pycodegen.py	Sat Nov 25 23:38:59 2006
@@ -30,6 +30,8 @@
 TRY_FINALLY = 3
 END_FINALLY = 4
 
+from pypy.module.__builtin__.__init__ import BUILTIN_TO_INDEX
+
 def compileFile(filename, display=0):
     f = open(filename, 'U')
     buf = f.read()
@@ -1005,6 +1007,8 @@
         self.emit('EXEC_STMT')
 
     def visitCallFunc(self, node):
+        if self.emit_builtin_call(node):
+            return
         pos = 0
         kw = 0
         self.set_lineno(node)
@@ -1024,6 +1028,35 @@
         opcode = callfunc_opcode_info[ have_star*2 + have_dstar]
         self.emitop_int(opcode, kw << 8 | pos)
 
+    def emit_builtin_call(self, node):
+        if not self.space.config.objspace.withfastbuiltins:
+            return False
+        if node.star_args is not None or node.dstar_args is not None:
+            return False
+        pos = 0
+        # check for kw args
+        for arg in node.args:
+            if isinstance(arg, ast.Keyword):
+                return False
+            else:
+                pos = pos + 1
+        func = node.node
+        if not isinstance(func, ast.Name):
+            return False
+        
+        name = func.varname
+        scope = self.scope.check_name(name)
+        # YYY
+        index = BUILTIN_TO_INDEX.get(name, -1)
+        if ((scope == SC_GLOBAL or
+            (scope == SC_DEFAULT and self.optimized and self.localsfullyknown)) 
+            and index != -1):
+            for arg in node.args:
+                arg.accept(self)
+            self.emitop_int("CALL_LIKELY_BUILTIN", index << 8 | pos)
+            return True
+        return False
+
     def visitPrint(self, node):
         self.set_lineno(node)
         if node.dest:

Modified: pypy/branch/builtin-call-speedup/pypy/interpreter/module.py
==============================================================================
--- pypy/branch/builtin-call-speedup/pypy/interpreter/module.py	(original)
+++ pypy/branch/builtin-call-speedup/pypy/interpreter/module.py	Sat Nov 25 23:38:59 2006
@@ -10,7 +10,7 @@
     def __init__(self, space, w_name, w_dict=None):
         self.space = space
         if w_dict is None: 
-            w_dict = space.newdict()
+            w_dict = space.newdict(track_builtin_shadowing=True)
         self.w_dict = w_dict 
         self.w_name = w_name 
         if w_name is not None:

Modified: pypy/branch/builtin-call-speedup/pypy/interpreter/pycode.py
==============================================================================
--- pypy/branch/builtin-call-speedup/pypy/interpreter/pycode.py	(original)
+++ pypy/branch/builtin-call-speedup/pypy/interpreter/pycode.py	Sat Nov 25 23:38:59 2006
@@ -51,6 +51,7 @@
 
 NESTED    = 1
 GENERATOR = 2
+CALLSPECIAL = 4
 
 frame_classes = []
 
@@ -59,6 +60,8 @@
     from pypy.interpreter.pyopcode import PyInterpFrame
     from pypy.interpreter.nestedscope import PyNestedScopeFrame
     from pypy.interpreter.generator import GeneratorFrameMixin
+    from pypy.interpreter.generator import GeneratorFrameMixin
+    from pypy.interpreter.specialcode import CallLikelyBuiltinMixin
 
     class PyGeneratorFrame(GeneratorFrameMixin, PyInterpFrame):
         pass
@@ -66,11 +69,30 @@
     class PyNestedScopeGeneratorFrame(GeneratorFrameMixin, PyNestedScopeFrame):
         pass
 
-    frame_classes.extend([None]*4)
+    class PyCallSpecialInterpFrame(PyInterpFrame, CallLikelyBuiltinMixin):
+        pass
+
+    class PyCallSpecialNestedScopeFrame(
+        PyNestedScopeFrame, CallLikelyBuiltinMixin):
+        pass
+
+    class PyCallSpecialGeneratorFrame(
+        PyGeneratorFrame, CallLikelyBuiltinMixin):
+        pass
+
+    class PyCallSpecialNestedScopeGeneratorFrame(
+        PyNestedScopeGeneratorFrame, CallLikelyBuiltinMixin):
+        pass
+
+    frame_classes.extend([None] * 8)
     frame_classes[0]                = PyInterpFrame
     frame_classes[NESTED]           = PyNestedScopeFrame
     frame_classes[GENERATOR]        = PyGeneratorFrame
     frame_classes[NESTED|GENERATOR] = PyNestedScopeGeneratorFrame
+    frame_classes[CALLSPECIAL]      = PyCallSpecialInterpFrame
+    frame_classes[NESTED|CALLSPECIAL]           = PyCallSpecialNestedScopeFrame
+    frame_classes[GENERATOR|CALLSPECIAL]        = PyCallSpecialGeneratorFrame
+    frame_classes[NESTED|GENERATOR|CALLSPECIAL] = PyCallSpecialNestedScopeGeneratorFrame
 
 
 class PyCode(eval.Code):
@@ -257,6 +279,8 @@
             choose |= NESTED
         if self.co_flags & CO_GENERATOR:
             choose |= GENERATOR
+        if self.space.config.objspace.withfastbuiltins:
+            choose |= CALLSPECIAL
         Frame = frame_classes[choose]
         return Frame
 

Modified: pypy/branch/builtin-call-speedup/pypy/module/__builtin__/__init__.py
==============================================================================
--- pypy/branch/builtin-call-speedup/pypy/module/__builtin__/__init__.py	(original)
+++ pypy/branch/builtin-call-speedup/pypy/module/__builtin__/__init__.py	Sat Nov 25 23:38:59 2006
@@ -1,6 +1,22 @@
 from pypy.interpreter.error import OperationError
 from pypy.interpreter import module
-from pypy.interpreter.mixedmodule import MixedModule 
+from pypy.interpreter.mixedmodule import MixedModule
+
+# put builtins here that should be optimized somehow
+
+OPTIMIZED_BUILTINS = ["len", "range", "xrange", "min", "max", "enumerate",
+        "isinstance", "type", "zip", "file", "open", "abs", "chr", "unichr",
+        "ord", "pow", "repr", "hash", "oct", "hex", "round", "cmp", "getattr",
+        "setattr", "delattr", "callable", "int", "str", "float"]
+
+assert len(OPTIMIZED_BUILTINS) <= 256
+
+BUILTIN_TO_INDEX = {}
+
+for i, name in enumerate(OPTIMIZED_BUILTINS):
+    BUILTIN_TO_INDEX[name] = i
+
+assert len(OPTIMIZED_BUILTINS) == len(BUILTIN_TO_INDEX)
 
 class Module(MixedModule):
     """Built-in functions, exceptions, and other objects."""
@@ -141,6 +157,9 @@
     def setup_after_space_initialization(self):
         """NOT_RPYTHON"""
         space = self.space
+        self.builtins_by_index = [None] * len(OPTIMIZED_BUILTINS)
+        for i, name in enumerate(OPTIMIZED_BUILTINS):
+            self.builtins_by_index[i] = space.getattr(self, space.wrap(name))
         # call installations for pickle support
         for name in self.loaders.keys():
             if name.startswith('_install_pickle_support_for_'):

Modified: pypy/branch/builtin-call-speedup/pypy/module/__builtin__/test/test_builtin.py
==============================================================================
--- pypy/branch/builtin-call-speedup/pypy/module/__builtin__/test/test_builtin.py	(original)
+++ pypy/branch/builtin-call-speedup/pypy/module/__builtin__/test/test_builtin.py	Sat Nov 25 23:38:59 2006
@@ -433,6 +433,38 @@
         raises(TypeError, hasattr, x, None)
         raises(TypeError, hasattr, x, 42)
 
+class AppTestBuiltinOptimized(object):
+    def setup_class(cls):
+        from pypy.conftest import gettestobjspace
+        cls.space = gettestobjspace(**{"objspace.withfastbuiltins": True})
+        assert cls.space.config.objspace.withfastbuiltins
+
+    # hum, we need to invoke the compiler explicitely
+    def test_xrange_len(self):
+        s = """def test():
+        x = xrange(33)
+        assert len(x) == 33
+        x = xrange(33.2)
+        assert len(x) == 33
+        x = xrange(33,0,-1)
+        assert len(x) == 33
+        x = xrange(33,0)
+        assert len(x) == 0
+        x = xrange(33,0.2)
+        assert len(x) == 0
+        x = xrange(0,33)
+        assert len(x) == 33
+        x = xrange(0,33,-1)
+        assert len(x) == 0
+        x = xrange(0,33,2)
+        assert len(x) == 17
+        x = xrange(0,32,2)
+        assert len(x) == 16
+        """
+        ns = {}
+        exec s in ns
+        ns["test"]()
+
 class TestInternal:
 
     def setup_method(self,method):

Modified: pypy/branch/builtin-call-speedup/pypy/objspace/std/model.py
==============================================================================
--- pypy/branch/builtin-call-speedup/pypy/objspace/std/model.py	(original)
+++ pypy/branch/builtin-call-speedup/pypy/objspace/std/model.py	Sat Nov 25 23:38:59 2006
@@ -65,6 +65,7 @@
         from pypy.objspace.std import dictobject
         from pypy.objspace.std import dictstrobject
         from pypy.objspace.std import dictmultiobject
+        from pypy.objspace.std import warydictobject
         from pypy.objspace.std import stringobject
         from pypy.objspace.std import strsliceobject
         from pypy.objspace.std import strjoinobject
@@ -109,8 +110,13 @@
         self.typeorder[setobject.W_FrozensetObject] = []
         self.typeorder[setobject.W_SetIterObject] = []
 
+        # XXX add to option_to_typename somehow
+        if config.objspace.withfastbuiltins:
+            self.typeorder[warydictobject.W_WaryDictObject] = []
+
         imported_but_not_registered = {
             dictobject.W_DictObject: True,
+            warydictobject.W_WaryDictObject: True,
             dictobject.W_DictIterObject: True,
         }
         for option, value in config.objspace.std:

Modified: pypy/branch/builtin-call-speedup/pypy/objspace/std/objspace.py
==============================================================================
--- pypy/branch/builtin-call-speedup/pypy/objspace/std/objspace.py	(original)
+++ pypy/branch/builtin-call-speedup/pypy/objspace/std/objspace.py	Sat Nov 25 23:38:59 2006
@@ -363,7 +363,10 @@
     def newlist(self, list_w):
         return W_ListObject(list_w)
 
-    def newdict(self):
+    def newdict(self, track_builtin_shadowing=False):
+        if self.config.objspace.withfastbuiltins and track_builtin_shadowing:
+            from pypy.objspace.std.warydictobject import W_WaryDictObject
+            return W_WaryDictObject(self)
         return self.DictObjectCls(self)
 
     def newslice(self, w_start, w_end, w_step):

Added: pypy/branch/builtin-call-speedup/pypy/objspace/std/warydictobject.py
==============================================================================
--- (empty file)
+++ pypy/branch/builtin-call-speedup/pypy/objspace/std/warydictobject.py	Sat Nov 25 23:38:59 2006
@@ -0,0 +1,43 @@
+
+from pypy.objspace.std.objspace import *
+from pypy.interpreter import gateway
+from pypy.objspace.std.dictobject import W_DictObject
+from pypy.objspace.std.stringobject import W_StringObject
+
+from pypy.rlib.objectmodel import r_dict
+
+class W_WaryDictObject(W_DictObject):
+    def __init__(w_self, space, wary_of=None, w_otherdict=None):
+        from pypy.module.__builtin__.__init__ import BUILTIN_TO_INDEX
+        W_DictObject.__init__(w_self, space, w_otherdict)
+        if wary_of is None:
+            wary_of = BUILTIN_TO_INDEX
+        if w_otherdict is None:
+            w_self.shadowed = [False] * len(wary_of)
+        else:
+            w_self.shadowed = [True] * len(wary_of)
+        w_self.wary_of = wary_of
+
+registerimplementation(W_WaryDictObject)
+
+def setitem__WaryDict_ANY_ANY(space, w_dict, w_key, w_newvalue):
+    if space.is_true(space.isinstance(w_key, space.w_str)):
+        s = space.str_w(w_key)
+        i = w_dict.wary_of.get(s, -1)
+        if i != -1:
+            w_dict.shadowed[i] = True
+    w_dict.content[w_key] = w_newvalue
+
+def delitem__WaryDict_ANY(space, w_dict, w_lookup):
+    try:
+        if space.is_true(space.isinstance(w_lookup, space.w_str)):
+            s = space.str_w(w_lookup)
+            i = w_dict.wary_of.get(s, -1)
+            if i != -1:
+                w_dict.shadowed[i] = False
+        del w_dict.content[w_lookup]
+    except KeyError:
+        raise OperationError(space.w_KeyError, w_lookup)
+
+from pypy.objspace.std import dicttype
+register_all(vars(), dicttype)



More information about the Pypy-commit mailing list