Patch 1145039.
set_exc_info(), reset_exc_info(): By exploiting the likely (who knows?) invariant that when an exception's `type` is NULL, its `value` and `traceback` are also NULL, save some cycles in heavily-executed code. This is a "a kronar saved is a kronar earned" patch: the speedup isn't reliably measurable, but it obviously does reduce the operation count in the normal (no exception raised) path through PyEval_EvalFrameEx(). The tim-exc_sanity branch tries to push this harder, but is still blowing up (at least in part due to pre-existing subtle bugs that appear to have no other visible consequences!). Not a bugfix candidate.
This commit is contained in:
parent
7e0a62ea90
commit
7df5e7f4b2
|
@ -26,7 +26,16 @@ typedef struct _frame {
|
|||
to the current stack top. */
|
||||
PyObject **f_stacktop;
|
||||
PyObject *f_trace; /* Trace function */
|
||||
|
||||
/* If an exception is raised in this frame, the next three are used to
|
||||
* record the exception info (if any) originally in the thread state. See
|
||||
* comments before set_exc_info() -- it's not obvious.
|
||||
* Invariant: if _type is NULL, then so are _value and _traceback.
|
||||
* Desired invariant: all three are NULL, or all three are non-NULL. That
|
||||
* one isn't currently true, but "should be".
|
||||
*/
|
||||
PyObject *f_exc_type, *f_exc_value, *f_exc_traceback;
|
||||
|
||||
PyThreadState *f_tstate;
|
||||
int f_lasti; /* Last instruction if called */
|
||||
/* As of 2.3 f_lineno is only valid when tracing is active (i.e. when
|
||||
|
|
|
@ -2581,7 +2581,12 @@ fast_yield:
|
|||
}
|
||||
}
|
||||
|
||||
if (tstate->frame->f_exc_type != NULL)
|
||||
reset_exc_info(tstate);
|
||||
else {
|
||||
assert(tstate->frame->f_exc_value == NULL);
|
||||
assert(tstate->frame->f_exc_traceback == NULL);
|
||||
}
|
||||
|
||||
/* pop frame */
|
||||
exit_eval_frame:
|
||||
|
@ -2846,6 +2851,7 @@ PyEval_EvalCodeEx(PyCodeObject *co, PyObject *globals, PyObject *locals,
|
|||
- Once an exception is caught by an except clause, it is transferred
|
||||
from tstate->curexc_ZZZ to tstate->exc_ZZZ, from which sys.exc_info()
|
||||
can pick it up. This is the primary task of set_exc_info().
|
||||
XXX That can't be right: set_exc_info() doesn't look at tstate->curexc_ZZZ.
|
||||
|
||||
- Now let me explain the complicated dance with frame->f_exc_ZZZ.
|
||||
|
||||
|
@ -2900,33 +2906,33 @@ Py_LOCAL(void)
|
|||
set_exc_info(PyThreadState *tstate,
|
||||
PyObject *type, PyObject *value, PyObject *tb)
|
||||
{
|
||||
PyFrameObject *frame;
|
||||
PyFrameObject *frame = tstate->frame;
|
||||
PyObject *tmp_type, *tmp_value, *tmp_tb;
|
||||
|
||||
frame = tstate->frame;
|
||||
assert(type != NULL);
|
||||
assert(frame != NULL);
|
||||
if (frame->f_exc_type == NULL) {
|
||||
/* This frame didn't catch an exception before */
|
||||
/* Save previous exception of this thread in this frame */
|
||||
assert(frame->f_exc_value == NULL);
|
||||
assert(frame->f_exc_traceback == NULL);
|
||||
/* This frame didn't catch an exception before. */
|
||||
/* Save previous exception of this thread in this frame. */
|
||||
if (tstate->exc_type == NULL) {
|
||||
/* XXX Why is this set to Py_None? */
|
||||
Py_INCREF(Py_None);
|
||||
tstate->exc_type = Py_None;
|
||||
}
|
||||
tmp_value = frame->f_exc_value;
|
||||
tmp_tb = frame->f_exc_traceback;
|
||||
Py_XINCREF(tstate->exc_type);
|
||||
Py_INCREF(tstate->exc_type);
|
||||
Py_XINCREF(tstate->exc_value);
|
||||
Py_XINCREF(tstate->exc_traceback);
|
||||
frame->f_exc_type = tstate->exc_type;
|
||||
frame->f_exc_value = tstate->exc_value;
|
||||
frame->f_exc_traceback = tstate->exc_traceback;
|
||||
Py_XDECREF(tmp_value);
|
||||
Py_XDECREF(tmp_tb);
|
||||
}
|
||||
/* Set new exception for this thread */
|
||||
/* Set new exception for this thread. */
|
||||
tmp_type = tstate->exc_type;
|
||||
tmp_value = tstate->exc_value;
|
||||
tmp_tb = tstate->exc_traceback;
|
||||
Py_XINCREF(type);
|
||||
Py_INCREF(type);
|
||||
Py_XINCREF(value);
|
||||
Py_XINCREF(tb);
|
||||
tstate->exc_type = type;
|
||||
|
@ -2946,9 +2952,16 @@ reset_exc_info(PyThreadState *tstate)
|
|||
{
|
||||
PyFrameObject *frame;
|
||||
PyObject *tmp_type, *tmp_value, *tmp_tb;
|
||||
|
||||
/* It's a precondition that the thread state's frame caught an
|
||||
* exception -- verify in a debug build.
|
||||
*/
|
||||
assert(tstate != NULL);
|
||||
frame = tstate->frame;
|
||||
if (frame->f_exc_type != NULL) {
|
||||
/* This frame caught an exception */
|
||||
assert(frame != NULL);
|
||||
assert(frame->f_exc_type != NULL);
|
||||
|
||||
/* Copy the frame's exception info back to the thread state. */
|
||||
tmp_type = tstate->exc_type;
|
||||
tmp_value = tstate->exc_value;
|
||||
tmp_tb = tstate->exc_traceback;
|
||||
|
@ -2961,18 +2974,20 @@ reset_exc_info(PyThreadState *tstate)
|
|||
Py_XDECREF(tmp_type);
|
||||
Py_XDECREF(tmp_value);
|
||||
Py_XDECREF(tmp_tb);
|
||||
|
||||
/* For b/w compatibility */
|
||||
PySys_SetObject("exc_type", frame->f_exc_type);
|
||||
PySys_SetObject("exc_value", frame->f_exc_value);
|
||||
PySys_SetObject("exc_traceback", frame->f_exc_traceback);
|
||||
}
|
||||
|
||||
/* Clear the frame's exception info. */
|
||||
tmp_type = frame->f_exc_type;
|
||||
tmp_value = frame->f_exc_value;
|
||||
tmp_tb = frame->f_exc_traceback;
|
||||
frame->f_exc_type = NULL;
|
||||
frame->f_exc_value = NULL;
|
||||
frame->f_exc_traceback = NULL;
|
||||
Py_XDECREF(tmp_type);
|
||||
Py_DECREF(tmp_type);
|
||||
Py_XDECREF(tmp_value);
|
||||
Py_XDECREF(tmp_tb);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue