Issue #29049: Call _PyObject_GC_TRACK() lazily when calling Python function.

Calling function is up to 5% faster.
This commit is contained in:
INADA Naoki 2016-12-24 20:19:08 +09:00
parent 2585443b6f
commit 5a625d0aa6
4 changed files with 45 additions and 15 deletions

View file

@ -60,7 +60,11 @@ PyAPI_DATA(PyTypeObject) PyFrame_Type;
#define PyFrame_Check(op) (Py_TYPE(op) == &PyFrame_Type)
PyAPI_FUNC(PyFrameObject *) PyFrame_New(PyThreadState *, PyCodeObject *,
PyObject *, PyObject *);
PyObject *, PyObject *);
/* only internal use */
PyFrameObject* _PyFrame_New_NoTrack(PyThreadState *, PyCodeObject *,
PyObject *, PyObject *);
/* The rest of the interface is specific for frame objects */

View file

@ -10,6 +10,9 @@ What's New in Python 3.7.0 alpha 1?
Core and Builtins
-----------------
- Issue #29049: Call _PyObject_GC_TRACK() lazily when calling Python function.
Calling function is up to 5% faster.
- Issue #28927: bytes.fromhex() and bytearray.fromhex() now ignore all ASCII
whitespace, not only spaces. Patch by Robert Xiao.

View file

@ -415,7 +415,9 @@ frame_dealloc(PyFrameObject *f)
PyObject **p, **valuestack;
PyCodeObject *co;
PyObject_GC_UnTrack(f);
if (_PyObject_GC_IS_TRACKED(f))
_PyObject_GC_UNTRACK(f);
Py_TRASHCAN_SAFE_BEGIN(f)
/* Kill all local variables */
valuestack = f->f_valuestack;
@ -606,8 +608,8 @@ int _PyFrame_Init()
}
PyFrameObject* _Py_HOT_FUNCTION
PyFrame_New(PyThreadState *tstate, PyCodeObject *code, PyObject *globals,
PyObject *locals)
_PyFrame_New_NoTrack(PyThreadState *tstate, PyCodeObject *code,
PyObject *globals, PyObject *locals)
{
PyFrameObject *back = tstate->frame;
PyFrameObject *f;
@ -727,10 +729,20 @@ PyFrame_New(PyThreadState *tstate, PyCodeObject *code, PyObject *globals,
f->f_executing = 0;
f->f_gen = NULL;
_PyObject_GC_TRACK(f);
return f;
}
PyFrameObject*
PyFrame_New(PyThreadState *tstate, PyCodeObject *code,
PyObject *globals, PyObject *locals)
{
PyFrameObject *f = _PyFrame_New_NoTrack(tstate, code, globals, locals);
if (f)
_PyObject_GC_TRACK(f);
return f;
}
/* Block management */
void

View file

@ -3931,7 +3931,7 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
/* Create the frame */
tstate = PyThreadState_GET();
assert(tstate != NULL);
f = PyFrame_New(tstate, co, globals, locals);
f = _PyFrame_New_NoTrack(tstate, co, globals, locals);
if (f == NULL) {
return NULL;
}
@ -4176,9 +4176,15 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
so recursion_depth must be boosted for the duration.
*/
assert(tstate != NULL);
++tstate->recursion_depth;
Py_DECREF(f);
--tstate->recursion_depth;
if (Py_REFCNT(f) > 1) {
Py_DECREF(f);
_PyObject_GC_TRACK(f);
}
else {
++tstate->recursion_depth;
Py_DECREF(f);
--tstate->recursion_depth;
}
return retval;
}
@ -4904,11 +4910,11 @@ _PyFunction_FastCall(PyCodeObject *co, PyObject **args, Py_ssize_t nargs,
assert(globals != NULL);
/* XXX Perhaps we should create a specialized
PyFrame_New() that doesn't take locals, but does
_PyFrame_New_NoTrack() that doesn't take locals, but does
take builtins without sanity checking them.
*/
assert(tstate != NULL);
f = PyFrame_New(tstate, co, globals, NULL);
f = _PyFrame_New_NoTrack(tstate, co, globals, NULL);
if (f == NULL) {
return NULL;
}
@ -4921,10 +4927,15 @@ _PyFunction_FastCall(PyCodeObject *co, PyObject **args, Py_ssize_t nargs,
}
result = PyEval_EvalFrameEx(f,0);
++tstate->recursion_depth;
Py_DECREF(f);
--tstate->recursion_depth;
if (Py_REFCNT(f) > 1) {
Py_DECREF(f);
_PyObject_GC_TRACK(f);
}
else {
++tstate->recursion_depth;
Py_DECREF(f);
--tstate->recursion_depth;
}
return result;
}