summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeremy Hylton <jeremy@alum.mit.edu>2000-04-26 20:39:20 (GMT)
committerJeremy Hylton <jeremy@alum.mit.edu>2000-04-26 20:39:20 (GMT)
commit9e392e2412308c7923195f226510bb1f174be215 (patch)
tree234c290c12a4cba247e7fd044e0cbb0998180636
parent50422b403c4ebea87f7af840e5c5cf147155639e (diff)
downloadcpython-9e392e2412308c7923195f226510bb1f174be215.zip
cpython-9e392e2412308c7923195f226510bb1f174be215.tar.gz
cpython-9e392e2412308c7923195f226510bb1f174be215.tar.bz2
potentially useless optimization
The previous checkin (2.84) added a PyErr_Format call that made the cost of raising an AttributeError much more expensive. In general this doesn't matter, except that checks for __init__ and __del__ methods, where exceptions are caught and cleared in C, also got much more expensive. The fix is to split instance_getattr1 into two calls: instance_getattr2 checks the instance and the class for the attribute and returns it or returns NULL on error. It does not raise an exception. instance_getattr1 does rexec checks, then calls instance_getattr2. It raises an exception if instance_getattr2 returns NULL. PyInstance_New and instance_dealloc now call instance_getattr2 directly.
-rw-r--r--Objects/classobject.c31
1 files changed, 20 insertions, 11 deletions
diff --git a/Objects/classobject.c b/Objects/classobject.c
index 4fb1167..6c7dba5 100644
--- a/Objects/classobject.c
+++ b/Objects/classobject.c
@@ -38,6 +38,7 @@ PERFORMANCE OF THIS SOFTWARE.
static PyObject *class_lookup
Py_PROTO((PyClassObject *, PyObject *, PyClassObject **));
static PyObject *instance_getattr1 Py_PROTO((PyInstanceObject *, PyObject *));
+static PyObject *instance_getattr2 Py_PROTO((PyInstanceObject *, PyObject *));
static PyObject *getattrstr, *setattrstr, *delattrstr;
@@ -456,9 +457,8 @@ PyInstance_New(class, arg, kw)
}
if (initstr == NULL)
initstr = PyString_InternFromString("__init__");
- init = instance_getattr1(inst, initstr);
+ init = instance_getattr2(inst, initstr);
if (init == NULL) {
- PyErr_Clear();
if ((arg != NULL && (!PyTuple_Check(arg) ||
PyTuple_Size(arg) != 0))
|| (kw != NULL && (!PyDict_Check(kw) ||
@@ -515,7 +515,7 @@ instance_dealloc(inst)
PyErr_Fetch(&error_type, &error_value, &error_traceback);
if (delstr == NULL)
delstr = PyString_InternFromString("__del__");
- if ((del = instance_getattr1(inst, delstr)) != NULL) {
+ if ((del = instance_getattr2(inst, delstr)) != NULL) {
PyObject *res = PyEval_CallObject(del, (PyObject *)NULL);
if (res == NULL) {
PyObject *f, *t, *v, *tb;
@@ -571,7 +571,6 @@ instance_getattr1(inst, name)
{
register PyObject *v;
register char *sname = PyString_AsString(name);
- PyClassObject *class;
if (sname[0] == '_' && sname[1] == '_') {
if (strcmp(sname, "__dict__") == 0) {
if (PyEval_GetRestricted()) {
@@ -587,17 +586,27 @@ instance_getattr1(inst, name)
return (PyObject *)inst->in_class;
}
}
+ v = instance_getattr2(inst, name);
+ if (v == NULL) {
+ PyErr_Format(PyExc_AttributeError,"'%.50s' instance has no attribute '%.400s'",
+ PyString_AS_STRING(inst->in_class->cl_name), sname);
+ }
+ return v;
+}
+
+static PyObject *
+instance_getattr2(inst, name)
+ register PyInstanceObject *inst;
+ PyObject *name;
+{
+ register PyObject *v;
+ PyClassObject *class;
class = NULL;
v = PyDict_GetItem(inst->in_dict, name);
if (v == NULL) {
v = class_lookup(inst->in_class, name, &class);
- if (v == NULL) {
- PyErr_Format(PyExc_AttributeError,
- "'%.50s' instance has no attribute '%.400s'",
- PyString_AsString(inst->in_class->cl_name),
- sname);
- return NULL;
- }
+ if (v == NULL)
+ return v;
}
Py_INCREF(v);
if (class != NULL) {