[pypy-svn] r67483 - in pypy/trunk/pypy: config doc/config objspace/std objspace/std/test

pedronis at codespeak.net pedronis at codespeak.net
Fri Sep 4 16:26:37 CEST 2009


Author: pedronis
Date: Fri Sep  4 16:26:36 2009
New Revision: 67483

Added:
   pypy/trunk/pypy/doc/config/objspace.std.newshortcut.txt   (contents, props changed)
Modified:
   pypy/trunk/pypy/config/pypyoption.py
   pypy/trunk/pypy/objspace/std/test/test_typeobject.py
   pypy/trunk/pypy/objspace/std/typeobject.py
Log:
(micke, pedronis) add a shortcut path to object creation, it speeds up object creation more than 20% for types without a custom __new__



Modified: pypy/trunk/pypy/config/pypyoption.py
==============================================================================
--- pypy/trunk/pypy/config/pypyoption.py	(original)
+++ pypy/trunk/pypy/config/pypyoption.py	Fri Sep  4 16:26:36 2009
@@ -328,6 +328,9 @@
         BoolOption("getattributeshortcut",
                    "track types that override __getattribute__",
                    default=False),
+        BoolOption("newshortcut",
+                   "cache and shortcut calling __new__ from builtin types",
+                   default=False),        
 
         BoolOption("logspaceoptypes",
                    "a instrumentation option: before exit, print the types seen by "
@@ -369,6 +372,7 @@
         config.objspace.std.suggest(builtinshortcut=True)
         config.objspace.std.suggest(optimized_list_getitem=True)
         config.objspace.std.suggest(getattributeshortcut=True)
+        config.objspace.std.suggest(newshortcut=True)        
 
     # extra costly optimizations only go in level 3
     if level == '3':

Added: pypy/trunk/pypy/doc/config/objspace.std.newshortcut.txt
==============================================================================
--- (empty file)
+++ pypy/trunk/pypy/doc/config/objspace.std.newshortcut.txt	Fri Sep  4 16:26:36 2009
@@ -0,0 +1 @@
+Performance only: cache and shortcut calling __new__ from builtin types

Modified: pypy/trunk/pypy/objspace/std/test/test_typeobject.py
==============================================================================
--- pypy/trunk/pypy/objspace/std/test/test_typeobject.py	(original)
+++ pypy/trunk/pypy/objspace/std/test/test_typeobject.py	Fri Sep  4 16:26:36 2009
@@ -991,3 +991,82 @@
         X.__getattribute__ = ga
 
         assert y.x == 'GA'
+
+class TestNewShortcut:
+
+    def setup_class(cls):
+        cls.space = gettestobjspace(
+                        **{"objspace.std.newshortcut": True})   
+
+    def test_mechanics(self):
+        space = self.space
+        w_tup = space.appexec([], """():
+    class A(object):
+        pass
+    class B(object):
+        __new__ = staticmethod(lambda t: 1)
+    class M(type):
+        pass
+    return A, B, M
+""")
+        w_A, w_B, w_M = space.unpackiterable(w_tup)
+
+        assert w_A.w_bltin_new is None
+        assert w_B.w_bltin_new is None
+        assert w_M.w_bltin_new is None                
+
+        _, w_object_newdescr = space.lookup_in_type_where(space.w_object,
+                                                          '__new__')
+        w_object___new__ = space.get(w_object_newdescr, None,
+                                     w_type=space.w_object)
+
+        w_a = space.call_function(w_A)
+        assert w_A.w_bltin_new is w_object___new__
+
+        # will shortcut
+        w_a = space.call_function(w_A)
+
+        w_b = space.call_function(w_B)
+        assert w_B.w_bltin_new is None
+
+        w_m = space.call_function(w_M, space.wrap('C'), space.newlist([]),
+                                  space.newdict())
+        assert w_M.w_bltin_new is None                                  
+
+
+class AppTestNewShortcut:
+
+    def setup_class(cls):
+        cls.space = gettestobjspace(
+                        **{"objspace.std.newshortcut": True})
+
+    def test_reset_logic(self):
+        class X(object):
+            pass
+
+        class Y(X):
+            pass
+
+        y = Y()
+
+        assert isinstance(y, Y)
+
+
+        X.__new__ = staticmethod(lambda t: 1)
+
+        y = Y()
+
+        assert y == 1
+
+    def test_dont_explode_on_non_types(self):
+        class A:
+            __new__ = staticmethod(lambda t: 1)
+
+        class B(A, object):
+            pass
+
+        b = B()
+
+        assert b == 1
+
+        

Modified: pypy/trunk/pypy/objspace/std/typeobject.py
==============================================================================
--- pypy/trunk/pypy/objspace/std/typeobject.py	(original)
+++ pypy/trunk/pypy/objspace/std/typeobject.py	Fri Sep  4 16:26:36 2009
@@ -52,9 +52,14 @@
 
     _immutable_fields_ = ["__flags__"]
 
-    uses_object_getattribute = False
-    # ^^^ for config.objspace.std.getattributeshortcut
+    # for config.objspace.std.getattributeshortcut
     # (False is a conservative default, fixed during real usage)
+    uses_object_getattribute = False
+
+    # used to cache the type __new__ function if it comes from a builtin type
+    # != 'type', in that case call__Type will also assumes the result
+    # of the __new__ is an instance of the type
+    w_bltin_new = None
 
     def __init__(w_self, space, name, bases_w, dict_w,
                  overridetypedef=None):
@@ -87,13 +92,17 @@
     def mutated(w_self):
         space = w_self.space
         if (not space.config.objspace.std.withtypeversion and
-            not space.config.objspace.std.getattributeshortcut):
+            not space.config.objspace.std.getattributeshortcut and
+            not space.config.objspace.std.newshortcut):
             return
 
         if space.config.objspace.std.getattributeshortcut:
             w_self.uses_object_getattribute = False
             # ^^^ conservative default, fixed during real usage
 
+        if space.config.objspace.std.newshortcut:
+            w_self.w_bltin_new = None
+
         if (space.config.objspace.std.withtypeversion
             and w_self.version_tag is not None):
             w_self.version_tag = VersionTag()
@@ -570,10 +579,23 @@
         else:
             return space.type(w_obj)
     # invoke the __new__ of the type
-    w_newfunc = space.getattr(w_type, space.wrap('__new__'))
-    w_newobject = space.call_obj_args(w_newfunc, w_type, __args__)
+    w_bltin_new = w_type.w_bltin_new
+    call_init = True
+    if w_bltin_new is not None:
+        w_newobject = space.call_obj_args(w_bltin_new, w_type, __args__)
+    else:
+        w_newtype, w_newdescr = w_type.lookup_where('__new__')
+        w_newfunc = space.get(w_newdescr, w_type)
+        if (space.config.objspace.std.newshortcut and
+            isinstance(w_newtype, W_TypeObject) and
+            not w_newtype.is_heaptype() and
+            not space.is_w(w_newtype, space.w_type)):
+            w_type.w_bltin_new = w_newfunc
+        w_newobject = space.call_obj_args(w_newfunc, w_type, __args__)
+        call_init = space.is_true(space.isinstance(w_newobject, w_type))
+
     # maybe invoke the __init__ of the type
-    if space.is_true(space.isinstance(w_newobject, w_type)):
+    if call_init:
         w_descr = space.lookup(w_newobject, '__init__')
         w_result = space.get_and_call_args(w_descr, w_newobject, __args__)
         if not space.is_w(w_result, space.w_None):



More information about the Pypy-commit mailing list