mirror of
https://github.com/python/cpython.git
synced 2025-08-04 17:08:35 +00:00
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.
This commit is contained in:
parent
50422b403c
commit
9e392e2412
1 changed files with 20 additions and 11 deletions
|
@ -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) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue