Commit 7df5e7f4 authored by Tim Peters's avatar Tim Peters

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.
parent 7e0a62ea
...@@ -26,7 +26,16 @@ typedef struct _frame { ...@@ -26,7 +26,16 @@ typedef struct _frame {
to the current stack top. */ to the current stack top. */
PyObject **f_stacktop; PyObject **f_stacktop;
PyObject *f_trace; /* Trace function */ 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; PyObject *f_exc_type, *f_exc_value, *f_exc_traceback;
PyThreadState *f_tstate; PyThreadState *f_tstate;
int f_lasti; /* Last instruction if called */ int f_lasti; /* Last instruction if called */
/* As of 2.3 f_lineno is only valid when tracing is active (i.e. when /* As of 2.3 f_lineno is only valid when tracing is active (i.e. when
......
...@@ -2581,7 +2581,12 @@ fast_yield: ...@@ -2581,7 +2581,12 @@ fast_yield:
} }
} }
if (tstate->frame->f_exc_type != NULL)
reset_exc_info(tstate); reset_exc_info(tstate);
else {
assert(tstate->frame->f_exc_value == NULL);
assert(tstate->frame->f_exc_traceback == NULL);
}
/* pop frame */ /* pop frame */
exit_eval_frame: exit_eval_frame:
...@@ -2846,6 +2851,7 @@ PyEval_EvalCodeEx(PyCodeObject *co, PyObject *globals, PyObject *locals, ...@@ -2846,6 +2851,7 @@ PyEval_EvalCodeEx(PyCodeObject *co, PyObject *globals, PyObject *locals,
- Once an exception is caught by an except clause, it is transferred - 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() 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(). 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. - Now let me explain the complicated dance with frame->f_exc_ZZZ.
...@@ -2900,33 +2906,33 @@ Py_LOCAL(void) ...@@ -2900,33 +2906,33 @@ Py_LOCAL(void)
set_exc_info(PyThreadState *tstate, set_exc_info(PyThreadState *tstate,
PyObject *type, PyObject *value, PyObject *tb) PyObject *type, PyObject *value, PyObject *tb)
{ {
PyFrameObject *frame; PyFrameObject *frame = tstate->frame;
PyObject *tmp_type, *tmp_value, *tmp_tb; PyObject *tmp_type, *tmp_value, *tmp_tb;
frame = tstate->frame; assert(type != NULL);
assert(frame != NULL);
if (frame->f_exc_type == NULL) { if (frame->f_exc_type == NULL) {
/* This frame didn't catch an exception before */ assert(frame->f_exc_value == NULL);
/* Save previous exception of this thread in this frame */ 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) { if (tstate->exc_type == NULL) {
/* XXX Why is this set to Py_None? */
Py_INCREF(Py_None); Py_INCREF(Py_None);
tstate->exc_type = Py_None; tstate->exc_type = Py_None;
} }
tmp_value = frame->f_exc_value; Py_INCREF(tstate->exc_type);
tmp_tb = frame->f_exc_traceback;
Py_XINCREF(tstate->exc_type);
Py_XINCREF(tstate->exc_value); Py_XINCREF(tstate->exc_value);
Py_XINCREF(tstate->exc_traceback); Py_XINCREF(tstate->exc_traceback);
frame->f_exc_type = tstate->exc_type; frame->f_exc_type = tstate->exc_type;
frame->f_exc_value = tstate->exc_value; frame->f_exc_value = tstate->exc_value;
frame->f_exc_traceback = tstate->exc_traceback; 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_type = tstate->exc_type;
tmp_value = tstate->exc_value; tmp_value = tstate->exc_value;
tmp_tb = tstate->exc_traceback; tmp_tb = tstate->exc_traceback;
Py_XINCREF(type); Py_INCREF(type);
Py_XINCREF(value); Py_XINCREF(value);
Py_XINCREF(tb); Py_XINCREF(tb);
tstate->exc_type = type; tstate->exc_type = type;
...@@ -2946,9 +2952,16 @@ reset_exc_info(PyThreadState *tstate) ...@@ -2946,9 +2952,16 @@ reset_exc_info(PyThreadState *tstate)
{ {
PyFrameObject *frame; PyFrameObject *frame;
PyObject *tmp_type, *tmp_value, *tmp_tb; 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; frame = tstate->frame;
if (frame->f_exc_type != NULL) { assert(frame != NULL);
/* This frame caught an exception */ assert(frame->f_exc_type != NULL);
/* Copy the frame's exception info back to the thread state. */
tmp_type = tstate->exc_type; tmp_type = tstate->exc_type;
tmp_value = tstate->exc_value; tmp_value = tstate->exc_value;
tmp_tb = tstate->exc_traceback; tmp_tb = tstate->exc_traceback;
...@@ -2961,18 +2974,20 @@ reset_exc_info(PyThreadState *tstate) ...@@ -2961,18 +2974,20 @@ reset_exc_info(PyThreadState *tstate)
Py_XDECREF(tmp_type); Py_XDECREF(tmp_type);
Py_XDECREF(tmp_value); Py_XDECREF(tmp_value);
Py_XDECREF(tmp_tb); Py_XDECREF(tmp_tb);
/* For b/w compatibility */ /* For b/w compatibility */
PySys_SetObject("exc_type", frame->f_exc_type); PySys_SetObject("exc_type", frame->f_exc_type);
PySys_SetObject("exc_value", frame->f_exc_value); PySys_SetObject("exc_value", frame->f_exc_value);
PySys_SetObject("exc_traceback", frame->f_exc_traceback); PySys_SetObject("exc_traceback", frame->f_exc_traceback);
}
/* Clear the frame's exception info. */
tmp_type = frame->f_exc_type; tmp_type = frame->f_exc_type;
tmp_value = frame->f_exc_value; tmp_value = frame->f_exc_value;
tmp_tb = frame->f_exc_traceback; tmp_tb = frame->f_exc_traceback;
frame->f_exc_type = NULL; frame->f_exc_type = NULL;
frame->f_exc_value = NULL; frame->f_exc_value = NULL;
frame->f_exc_traceback = NULL; frame->f_exc_traceback = NULL;
Py_XDECREF(tmp_type); Py_DECREF(tmp_type);
Py_XDECREF(tmp_value); Py_XDECREF(tmp_value);
Py_XDECREF(tmp_tb); Py_XDECREF(tmp_tb);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment