From: <pj...@us...> - 2009-10-07 02:48:55
|
Revision: 6844 http://jython.svn.sourceforge.net/jython/?rev=6844&view=rev Author: pjenvey Date: 2009-10-07 02:48:36 +0000 (Wed, 07 Oct 2009) Log Message: ----------- optimize attr lookup on Deriveds inheriting object.__getattribute__: don't bother going through the descriptor. Derived's __findattr_ex__ now lives in a Deriveds util class (like java.util.Arrays/Collections but trickier to pronounce) so it can toggle the package private fast path flag on PyType fixes #1102 Modified Paths: -------------- trunk/jython/src/org/python/core/PyObject.java trunk/jython/src/org/python/core/PyType.java trunk/jython/src/templates/object.derived Added Paths: ----------- trunk/jython/src/org/python/core/Deriveds.java Added: trunk/jython/src/org/python/core/Deriveds.java =================================================================== --- trunk/jython/src/org/python/core/Deriveds.java (rev 0) +++ trunk/jython/src/org/python/core/Deriveds.java 2009-10-07 02:48:36 UTC (rev 6844) @@ -0,0 +1,63 @@ +/* Copyright (c) Jython Developers */ +package org.python.core; + +/** + * Derived classes utility methods. + */ +public class Deriveds { + + /** + * Derived's __findattr_ex__ implementation. + * + * This resides here (in org.python.core) because it manipulates PyType, and doesn't + * call any of the Derived classes' superclass methods. + */ + public static PyObject __findattr_ex__(PyObject self, String name) { + PyType type = self.getType(); + PyException firstAttributeError = null; + PyString pyName = null; + + try { + if (type.getUsesObjectGetattribute()) { + // Fast path: don't bother calling through the descriptor if using the + // generic __getattribute__ + PyObject result = self.object___findattr__(name); + if (result != null) { + return result; + } + // pass through to __getattr__ + } else { + PyObject getattribute = type.lookup("__getattribute__"); + if (getattribute == null) { + // This shouldn't happen + throw Py.SystemError(String.format("__getattribute__ not found on type %s", + type.getName())); + } + + if (getattribute == PyObject.objectGetattribute) { + type.setUsesObjectGetattribute(true); + } + pyName = PyString.fromInterned(name); + return getattribute.__get__(self, type).__call__(pyName); + } + } catch (PyException pye) { + if (!pye.match(Py.AttributeError)) { + throw pye; + } else { + // saved to avoid swallowing custom AttributeErrors, and pass through to + // __getattr__ + firstAttributeError = pye; + } + } + + PyObject getattr = type.lookup("__getattr__"); + if (getattr != null) { + return getattr.__get__(self, type).__call__(pyName != null + ? pyName : PyString.fromInterned(name)); + } + if (firstAttributeError != null) { + throw firstAttributeError; + } + return null; + } +} Modified: trunk/jython/src/org/python/core/PyObject.java =================================================================== --- trunk/jython/src/org/python/core/PyObject.java 2009-10-06 20:32:55 UTC (rev 6843) +++ trunk/jython/src/org/python/core/PyObject.java 2009-10-07 02:48:36 UTC (rev 6844) @@ -38,6 +38,9 @@ /** Primitives classes their wrapper classes. */ private static final Map<Class<?>, Class<?>> primitiveMap = Generic.map(); + /** object.__getattribute__ descriptor, cached for use by Deriveds.__findattr_ex__. */ + static final PyObject objectGetattribute; + static { primitiveMap.put(Character.TYPE, Character.class); primitiveMap.put(Boolean.TYPE, Boolean.class); @@ -51,8 +54,9 @@ if (Py.BOOTSTRAP_TYPES.size() > 0) { Py.writeWarning("init", "Bootstrap types weren't encountered in bootstrapping: " + Py.BOOTSTRAP_TYPES); + } - } + objectGetattribute = TYPE.__findattr__("__getattribute__"); } public PyObject(PyType objtype) { @@ -3693,7 +3697,6 @@ // name must be interned final PyObject object___findattr__(String name) { - PyObject descr = objtype.lookup(name); PyObject res; @@ -3727,7 +3730,6 @@ final void object___setattr__(String name, PyObject value) { PyObject descr = objtype.lookup(name); - boolean set = false; if (descr != null) { @@ -3771,7 +3773,6 @@ final void object___delattr__(String name) { PyObject descr = objtype.lookup(name); - boolean delete = false; if (descr != null) { Modified: trunk/jython/src/org/python/core/PyType.java =================================================================== --- trunk/jython/src/org/python/core/PyType.java 2009-10-06 20:32:55 UTC (rev 6843) +++ trunk/jython/src/org/python/core/PyType.java 2009-10-07 02:48:36 UTC (rev 6844) @@ -78,6 +78,9 @@ /** Whether finalization is required for this type's instances (implements __del__). */ private boolean needs_finalizer; + /** Whether this type's __getattribute__ is object.__getattribute__. */ + private volatile boolean usesObjectGetattribute; + /** The number of __slots__ defined. */ private int numSlots; @@ -685,6 +688,7 @@ mro = savedMro; throw t; } + postSetattr("__getattribute__"); } private void setIsBaseType(boolean isBaseType) { @@ -1329,6 +1333,12 @@ } }); } + } else if (name == "__getattribute__") { + traverse_hierarchy(false, new OnType() { + public boolean onType(PyType type) { + return (type.usesObjectGetattribute = false); + } + }); } } @@ -1381,6 +1391,12 @@ } }); } + } else if (name == "__getattribute__") { + traverse_hierarchy(false, new OnType() { + public boolean onType(PyType type) { + return (type.usesObjectGetattribute = false); + } + }); } } @@ -1480,6 +1496,14 @@ return doc; } + boolean getUsesObjectGetattribute() { + return usesObjectGetattribute; + } + + void setUsesObjectGetattribute(boolean usesObjectGetattribute) { + this.usesObjectGetattribute = usesObjectGetattribute; + } + public Object __tojava__(Class<?> c) { if (underlying_class != null && (c == Object.class || c == Class.class || c == Serializable.class)) { Modified: trunk/jython/src/templates/object.derived =================================================================== --- trunk/jython/src/templates/object.derived 2009-10-06 20:32:55 UTC (rev 6843) +++ trunk/jython/src/templates/object.derived 2009-10-07 02:48:36 UTC (rev 6844) @@ -314,44 +314,7 @@ } public PyObject __findattr_ex__(String name) { - PyType self_type = getType(); - // TODO: We should speed this up. As the __getattribute__ slot almost never - // changes, it is a good candidate for caching, as PyClass does with - // __getattr__. See #1102. - PyObject getattribute = self_type.lookup("__getattribute__"); - PyString py_name = null; - PyException firstAttributeError = null; - try { - if (getattribute != null) { - py_name = PyString.fromInterned(name); - return getattribute.__get__(this,self_type).__call__(py_name); - } else { - Py.Warning(String.format("__getattribute__ not found on type %s", - self_type.getName())); - PyObject ret = super.__findattr_ex__(name); - if (ret != null) { - return ret; - } // else: pass through to __getitem__ invocation - } - } catch (PyException e) { - if (!e.match(Py.AttributeError)) { - throw e; - } else { - firstAttributeError = e; // saved to avoid swallowing custom AttributeErrors - // and pass through to __getattr__ invocation. - } - } - PyObject getattr = self_type.lookup("__getattr__"); - if (getattr != null) { - if (py_name == null) { - py_name = PyString.fromInterned(name); - } - return getattr.__get__(this,self_type).__call__(py_name); - } - if (firstAttributeError != null) { - throw firstAttributeError; - } - return null; + return Deriveds.__findattr_ex__(this, name); } public void __setattr__(String name,PyObject value) { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |