[pypy-svn] r35900 - in pypy/dist: lib-python/modified-2.4.1 pypy/config pypy/interpreter pypy/interpreter/astcompiler pypy/module/__builtin__ pypy/module/__builtin__/test pypy/objspace/std

mwh at codespeak.net mwh at codespeak.net
Tue Dec 19 19:19:45 CET 2006


Author: mwh
Date: Tue Dec 19 19:19:44 2006
New Revision: 35900

Modified:
   pypy/dist/lib-python/modified-2.4.1/opcode.py
   pypy/dist/pypy/config/pypyoption.py
   pypy/dist/pypy/interpreter/astcompiler/pycodegen.py
   pypy/dist/pypy/interpreter/module.py
   pypy/dist/pypy/interpreter/pyopcode.py
   pypy/dist/pypy/module/__builtin__/__init__.py
   pypy/dist/pypy/module/__builtin__/test/test_builtin.py
   pypy/dist/pypy/objspace/std/dictmultiobject.py
   pypy/dist/pypy/objspace/std/objspace.py
Log:
merge builtin-call-speedup-2.  gives ~10% on richards, a bit less on pystone.
--objspace-opcodes-CALL_LIKELY_BUILTIN to enable.


Modified: pypy/dist/lib-python/modified-2.4.1/opcode.py
==============================================================================
--- pypy/dist/lib-python/modified-2.4.1/opcode.py	(original)
+++ pypy/dist/lib-python/modified-2.4.1/opcode.py	Tue Dec 19 19:19:44 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/dist/pypy/config/pypyoption.py
==============================================================================
--- pypy/dist/pypy/config/pypyoption.py	(original)
+++ pypy/dist/pypy/config/pypyoption.py	Tue Dec 19 19:19:44 2006
@@ -38,6 +38,10 @@
                  cmdline='--compiler'),
 
     OptionDescription("opcodes", "opcodes to enable in the interpreter", [
+        BoolOption("CALL_LIKELY_BUILTIN", "emit a special bytecode for likely calls to builtin functions",
+                   default=False,
+                   requires=[("objspace.usepycfiles", False),
+                             ("objspace.std.withmultidict", True)])
         ]),
 
     BoolOption("nofaking", "disallow faking in the object space",

Modified: pypy/dist/pypy/interpreter/astcompiler/pycodegen.py
==============================================================================
--- pypy/dist/pypy/interpreter/astcompiler/pycodegen.py	(original)
+++ pypy/dist/pypy/interpreter/astcompiler/pycodegen.py	Tue Dec 19 19:19:44 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.opcodes.CALL_LIKELY_BUILTIN:
+            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/dist/pypy/interpreter/module.py
==============================================================================
--- pypy/dist/pypy/interpreter/module.py	(original)
+++ pypy/dist/pypy/interpreter/module.py	Tue Dec 19 19:19:44 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/dist/pypy/interpreter/pyopcode.py
==============================================================================
--- pypy/dist/pypy/interpreter/pyopcode.py	(original)
+++ pypy/dist/pypy/interpreter/pyopcode.py	Tue Dec 19 19:19:44 2006
@@ -874,6 +874,36 @@
     def SET_LINENO(f, lineno, *ignored):
         pass
 
+    def CALL_LIKELY_BUILTIN(f, oparg, *ignored):
+        from pypy.module.__builtin__ import OPTIMIZED_BUILTINS, Module
+        from pypy.objspace.std.dictmultiobject import W_DictMultiObject
+        w_globals = f.w_globals
+        num = oparg >> 8
+        assert isinstance(w_globals, W_DictMultiObject)
+        w_value = w_globals.implementation.get_builtin_indexed(num)
+        if w_value is None:
+            w_builtins = f.builtin
+            assert isinstance(w_builtins, Module)
+            w_builtin_dict = w_builtins.w_dict
+            assert isinstance(w_builtin_dict, W_DictMultiObject)
+            w_value = w_builtin_dict.implementation.get_builtin_indexed(num)
+##                 if w_value is not None:
+##                     print "CALL_LIKELY_BUILTIN fast"
+        if w_value is None:
+            varname = OPTIMIZED_BUILTINS[num]
+            message = "global name '%s' is not defined" % varname
+            raise OperationError(f.space.w_NameError,
+                                 f.space.wrap(message))
+        nargs = oparg & 0xff
+        w_function = w_value
+        try:
+            w_result = f.space.call_valuestack(w_function, nargs, f.valuestack)
+            # XXX XXX fix the problem of resume points!
+            #rstack.resume_point("CALL_FUNCTION", f, nargs, returns=w_result)
+        finally:
+            f.valuestack.drop(nargs)
+        f.valuestack.push(w_result)
+
 ##     def EXTENDED_ARG(f, oparg, *ignored):
 ##         opcode = f.nextop()
 ##         oparg = oparg<<16 | f.nextarg()

Modified: pypy/dist/pypy/module/__builtin__/__init__.py
==============================================================================
--- pypy/dist/pypy/module/__builtin__/__init__.py	(original)
+++ pypy/dist/pypy/module/__builtin__/__init__.py	Tue Dec 19 19:19:44 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/dist/pypy/module/__builtin__/test/test_builtin.py
==============================================================================
--- pypy/dist/pypy/module/__builtin__/test/test_builtin.py	(original)
+++ pypy/dist/pypy/module/__builtin__/test/test_builtin.py	Tue Dec 19 19:19:44 2006
@@ -449,6 +449,42 @@
         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.opcodes.CALL_LIKELY_BUILTIN": True})
+        assert cls.space.config.objspace.opcodes.CALL_LIKELY_BUILTIN
+
+    # 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"]()
+
+    def test_delete_from_builtins(self):
+        s = """ """
+        # XXX write this test!
+
 class TestInternal:
 
     def setup_method(self,method):

Modified: pypy/dist/pypy/objspace/std/dictmultiobject.py
==============================================================================
--- pypy/dist/pypy/objspace/std/dictmultiobject.py	(original)
+++ pypy/dist/pypy/objspace/std/dictmultiobject.py	Tue Dec 19 19:19:44 2006
@@ -1,6 +1,7 @@
 import py
 from pypy.objspace.std.objspace import *
 from pypy.interpreter import gateway
+from pypy.module.__builtin__.__init__ import BUILTIN_TO_INDEX, OPTIMIZED_BUILTINS
 
 from pypy.rlib.objectmodel import r_dict, we_are_translated
 
@@ -54,6 +55,7 @@
 ##     def itervalues(self):
 ##         pass
 
+
     def keys(self):
         return [w_k for w_k in self.iterkeys()]
     def values(self):
@@ -61,6 +63,14 @@
     def items(self):
         return [(w_key, w_value) or w_key, w_value in self.iteritems()]
 
+#   the following method only makes sense when the option to use the
+#   CALL_LIKELY_BUILTIN opcode is set. Otherwise it won't even be seen
+#   by the annotator
+    def get_builtin_indexed(self, i):
+        w_key = self.space.wrap(OPTIMIZED_BUILTINS[i])
+        return self.get(w_key)
+
+
 class EmptyDictImplementation(DictImplementation):
     def __init__(self, space):
         self.space = space
@@ -312,8 +322,7 @@
     def setitem(self, w_key, w_value):
         space = self.space
         if space.is_w(space.type(w_key), space.w_str):
-            self.content[space.str_w(w_key)] = w_value
-            return self
+            return self.setitem_str(w_key, w_value)
         else:
             return self._as_rdict().setitem(w_key, w_value)
 
@@ -375,6 +384,37 @@
             newimpl.setitem(self.space.wrap(k), w_v)
         return newimpl
 
+class WaryDictImplementation(StrDictImplementation):
+    def __init__(self, space):
+        StrDictImplementation.__init__(self, space)
+        self.shadowed = [None] * len(BUILTIN_TO_INDEX)
+
+    def setitem_str(self, w_key, w_value):
+        key = self.space.str_w(w_key)
+        i = BUILTIN_TO_INDEX.get(key, -1)
+        if i != -1:
+            self.shadowed[i] = w_value
+        self.content[key] = w_value
+        return self
+
+    def delitem(self, w_key):
+        space = self.space
+        w_key_type = space.type(w_key)
+        if space.is_w(w_key_type, space.w_str):
+            key = space.str_w(w_key)
+            del self.content[key]
+            i = BUILTIN_TO_INDEX.get(key, -1)
+            if i != -1:
+                self.shadowed[i] = None
+            return self
+        elif _is_sane_hash(space, w_key_type):
+            raise KeyError
+        else:
+            return self._as_rdict().delitem(w_key)
+
+    def get_builtin_indexed(self, i):
+        return self.shadowed[i]
+
 class RDictImplementation(DictImplementation):
     def __init__(self, space):
         self.space = space
@@ -721,8 +761,10 @@
 class W_DictMultiObject(W_Object):
     from pypy.objspace.std.dicttype import dict_typedef as typedef
 
-    def __init__(w_self, space, sharing=False):
-        if space.config.objspace.std.withdictmeasurement:
+    def __init__(w_self, space, wary=False, sharing=False):
+        if space.config.objspace.opcodes.CALL_LIKELY_BUILTIN and wary:
+            w_self.implementation = WaryDictImplementation(space)
+        elif space.config.objspace.std.withdictmeasurement:
             w_self.implementation = MeasuringDictImplementation(space)
         elif space.config.objspace.std.withsharingdict and sharing:
             w_self.implementation = SharedDictImplementation(space)

Modified: pypy/dist/pypy/objspace/std/objspace.py
==============================================================================
--- pypy/dist/pypy/objspace/std/objspace.py	(original)
+++ pypy/dist/pypy/objspace/std/objspace.py	Tue Dec 19 19:19:44 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.opcodes.CALL_LIKELY_BUILTIN and track_builtin_shadowing:
+            from pypy.objspace.std.dictmultiobject import W_DictMultiObject
+            return W_DictMultiObject(self, wary=True)
         return self.DictObjectCls(self)
 
     def newslice(self, w_start, w_end, w_step):



More information about the Pypy-commit mailing list