[pypy-svn] r54285 - in pypy/branch/faster-binop/pypy: config doc/config objspace objspace/std objspace/std/test
arigo at codespeak.net
arigo at codespeak.net
Wed Apr 30 19:03:33 CEST 2008
Author: arigo
Date: Wed Apr 30 19:03:32 2008
New Revision: 54285
Added:
pypy/branch/faster-binop/pypy/doc/config/objspace.std.getattributeshortcut.txt (contents, props changed)
Modified:
pypy/branch/faster-binop/pypy/config/pypyoption.py
pypy/branch/faster-binop/pypy/objspace/descroperation.py
pypy/branch/faster-binop/pypy/objspace/std/callmethod.py
pypy/branch/faster-binop/pypy/objspace/std/objspace.py
pypy/branch/faster-binop/pypy/objspace/std/test/test_callmethod.py
pypy/branch/faster-binop/pypy/objspace/std/test/test_userobject.py
pypy/branch/faster-binop/pypy/objspace/std/typeobject.py
Log:
Playing around with a possible getattr optimization.
Not too happy about the code duplication.
Modified: pypy/branch/faster-binop/pypy/config/pypyoption.py
==============================================================================
--- pypy/branch/faster-binop/pypy/config/pypyoption.py (original)
+++ pypy/branch/faster-binop/pypy/config/pypyoption.py Wed Apr 30 19:03:32 2008
@@ -284,6 +284,9 @@
BoolOption("builtinshortcut",
"a shortcut for operations between built-in types",
default=False),
+ BoolOption("getattributeshortcut",
+ "track types that override __getattribute__",
+ default=False),
BoolOption("oldstyle",
"specify whether the default metaclass should be classobj",
Added: pypy/branch/faster-binop/pypy/doc/config/objspace.std.getattributeshortcut.txt
==============================================================================
--- (empty file)
+++ pypy/branch/faster-binop/pypy/doc/config/objspace.std.getattributeshortcut.txt Wed Apr 30 19:03:32 2008
@@ -0,0 +1 @@
+Performance only: track types that override __getattribute__.
Modified: pypy/branch/faster-binop/pypy/objspace/descroperation.py
==============================================================================
--- pypy/branch/faster-binop/pypy/objspace/descroperation.py (original)
+++ pypy/branch/faster-binop/pypy/objspace/descroperation.py Wed Apr 30 19:03:32 2008
@@ -129,7 +129,11 @@
return space.get_and_call_function(w_delete, w_descr, w_obj)
def getattr(space, w_obj, w_name):
+ # may be overridden in StdObjSpace
w_descr = space.lookup(w_obj, '__getattribute__')
+ return space._handle_getattribute(w_descr, w_obj, w_name)
+
+ def _handle_getattribute(space, w_descr, w_obj, w_name):
try:
if w_descr is None: # obscure case
raise OperationError(space.w_AttributeError, space.w_None)
Modified: pypy/branch/faster-binop/pypy/objspace/std/callmethod.py
==============================================================================
--- pypy/branch/faster-binop/pypy/objspace/std/callmethod.py (original)
+++ pypy/branch/faster-binop/pypy/objspace/std/callmethod.py Wed Apr 30 19:03:32 2008
@@ -32,10 +32,25 @@
w_obj = f.popvalue()
w_name = f.getname_w(nameindex)
w_value = None
- w_getattribute = space.lookup(w_obj, '__getattribute__')
- if w_getattribute is object_getattribute(space):
+
+ if space.config.objspace.std.getattributeshortcut:
+ w_type = space.type(w_obj)
+ fastpath = w_type.uses_object_getattribute
+ # conservatively, 'uses_object_getattribute' can be False
+ # even if __getattribute__ was not overridden. In this
+ # case, the code below calls space.getattr(), which will
+ # set 'uses_object_getattribute' to True for the next time.
+ else:
+ w_getattribute = space.lookup(w_obj, '__getattribute__')
+ if w_getattribute is object_getattribute(space):
+ w_type = space.type(w_obj)
+ fastpath = True
+ else:
+ fastpath = False
+
+ if fastpath:
name = space.str_w(w_name)
- w_descr = space.lookup(w_obj, name)
+ w_descr = w_type.lookup(name)
if w_descr is None:
# this handles directly the common case
# module.function(args..)
Modified: pypy/branch/faster-binop/pypy/objspace/std/objspace.py
==============================================================================
--- pypy/branch/faster-binop/pypy/objspace/std/objspace.py (original)
+++ pypy/branch/faster-binop/pypy/objspace/std/objspace.py Wed Apr 30 19:03:32 2008
@@ -683,6 +683,51 @@
return w_obj.boolval
return DescrOperation.is_true(self, w_obj)
+ def getattr(self, w_obj, w_name):
+ if not self.config.objspace.std.getattributeshortcut:
+ return DescrOperation.getattr(self, w_obj, w_name)
+
+ # an optional shortcut for performance
+ from pypy.objspace.descroperation import raiseattrerror
+ from pypy.objspace.descroperation import object_getattribute
+ w_type = self.type(w_obj)
+ if not w_type.uses_object_getattribute:
+ # slow path: look for a custom __getattribute__ on the class
+ w_descr = w_type.lookup('__getattribute__')
+ # if it was not actually overriden in the class, we remember this
+ # fact for the next time.
+ if w_descr is object_getattribute(self):
+ w_type.uses_object_getattribute = True
+ return self._handle_getattribute(w_descr, w_obj, w_name)
+
+ # fast path: XXX this is duplicating most of the logic
+ # from the default __getattribute__ and the getattr() method...
+ name = self.str_w(w_name)
+ w_descr = w_type.lookup(name)
+ e = None
+ if w_descr is not None:
+ if not self.is_data_descr(w_descr):
+ w_value = w_obj.getdictvalue_attr_is_in_class(self, w_name)
+ if w_value is not None:
+ return w_value
+ try:
+ return self.get(w_descr, w_obj)
+ except OperationError, e:
+ if not e.match(self, self.w_AttributeError):
+ raise
+ else:
+ w_value = w_obj.getdictvalue(self, w_name)
+ if w_value is not None:
+ return w_value
+
+ w_descr = self.lookup(w_obj, '__getattr__')
+ if w_descr is not None:
+ return space.get_and_call_function(w_descr, w_obj, w_name)
+ elif e is not None:
+ raise e
+ else:
+ raiseattrerror(self, w_obj, name)
+
def finditem(self, w_obj, w_key):
# performance shortcut to avoid creating the OperationError(KeyError)
if type(w_obj) is self.DictObjectCls:
Modified: pypy/branch/faster-binop/pypy/objspace/std/test/test_callmethod.py
==============================================================================
--- pypy/branch/faster-binop/pypy/objspace/std/test/test_callmethod.py (original)
+++ pypy/branch/faster-binop/pypy/objspace/std/test/test_callmethod.py Wed Apr 30 19:03:32 2008
@@ -6,8 +6,10 @@
# The exec hacking is needed to have the code snippets compiled
# by our own compiler, not CPython's
+ OPTIONS = {"objspace.opcodes.CALL_METHOD": True}
+
def setup_class(cls):
- cls.space = gettestobjspace(**{"objspace.opcodes.CALL_METHOD": True})
+ cls.space = gettestobjspace(**cls.OPTIONS)
def test_call_method(self):
exec """if 1:
@@ -106,6 +108,11 @@
"""
+class AppTestCallMethodWithGetattributeShortcut(AppTestCallMethod):
+ OPTIONS = AppTestCallMethod.OPTIONS.copy()
+ OPTIONS["objspace.std.getattributeshortcut"] = True
+
+
class TestCallMethod:
def setup_class(cls):
Modified: pypy/branch/faster-binop/pypy/objspace/std/test/test_userobject.py
==============================================================================
--- pypy/branch/faster-binop/pypy/objspace/std/test/test_userobject.py (original)
+++ pypy/branch/faster-binop/pypy/objspace/std/test/test_userobject.py Wed Apr 30 19:03:32 2008
@@ -216,3 +216,8 @@
def teardown_class(cls):
from pypy.objspace.std import multimethod
multimethod.Installer = cls.prev_installer
+
+
+class AppTestWithGetAttributeShortcut(AppTestUserObject):
+ OPTIONS = {"objspace.std.getattributeshortcut": True}
+
Modified: pypy/branch/faster-binop/pypy/objspace/std/typeobject.py
==============================================================================
--- pypy/branch/faster-binop/pypy/objspace/std/typeobject.py (original)
+++ pypy/branch/faster-binop/pypy/objspace/std/typeobject.py Wed Apr 30 19:03:32 2008
@@ -50,6 +50,10 @@
lazyloaders = {} # can be overridden by specific instances
+ uses_object_getattribute = False
+ # ^^^ for config.objspace.std.getattributeshortcut
+ # (False is a conservative default, fixed during real usage)
+
def __init__(w_self, space, name, bases_w, dict_w,
overridetypedef=None):
w_self.space = space
@@ -221,6 +225,9 @@
def mutated(w_self):
space = w_self.space
+ if space.config.objspace.std.getattributeshortcut:
+ w_self.uses_object_getattribute = False
+ # ^^^ conservative default, fixed during real usage
if not space.config.objspace.std.withtypeversion:
return
# Invariant: version_tag is None if and only if
More information about the Pypy-commit
mailing list