Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 5a625d0

Browse files
committed
Issue #29049: Call _PyObject_GC_TRACK() lazily when calling Python function.
Calling function is up to 5% faster.
1 parent 2585443 commit 5a625d0

4 files changed

Lines changed: 45 additions & 15 deletions

File tree

Include/frameobject.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,11 @@ PyAPI_DATA(PyTypeObject) PyFrame_Type;
6060
#define PyFrame_Check(op) (Py_TYPE(op) == &PyFrame_Type)
6161

6262
PyAPI_FUNC(PyFrameObject *) PyFrame_New(PyThreadState *, PyCodeObject *,
63-
PyObject *, PyObject *);
63+
PyObject *, PyObject *);
64+
65+
/* only internal use */
66+
PyFrameObject* _PyFrame_New_NoTrack(PyThreadState *, PyCodeObject *,
67+
PyObject *, PyObject *);
6468

6569

6670
/* The rest of the interface is specific for frame objects */

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ What's New in Python 3.7.0 alpha 1?
1010
Core and Builtins
1111
-----------------
1212

13+
- Issue #29049: Call _PyObject_GC_TRACK() lazily when calling Python function.
14+
Calling function is up to 5% faster.
15+
1316
- Issue #28927: bytes.fromhex() and bytearray.fromhex() now ignore all ASCII
1417
whitespace, not only spaces. Patch by Robert Xiao.
1518

Objects/frameobject.c

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,9 @@ frame_dealloc(PyFrameObject *f)
415415
PyObject **p, **valuestack;
416416
PyCodeObject *co;
417417

418-
PyObject_GC_UnTrack(f);
418+
if (_PyObject_GC_IS_TRACKED(f))
419+
_PyObject_GC_UNTRACK(f);
420+
419421
Py_TRASHCAN_SAFE_BEGIN(f)
420422
/* Kill all local variables */
421423
valuestack = f->f_valuestack;
@@ -606,8 +608,8 @@ int _PyFrame_Init()
606608
}
607609

608610
PyFrameObject* _Py_HOT_FUNCTION
609-
PyFrame_New(PyThreadState *tstate, PyCodeObject *code, PyObject *globals,
610-
PyObject *locals)
611+
_PyFrame_New_NoTrack(PyThreadState *tstate, PyCodeObject *code,
612+
PyObject *globals, PyObject *locals)
611613
{
612614
PyFrameObject *back = tstate->frame;
613615
PyFrameObject *f;
@@ -727,10 +729,20 @@ PyFrame_New(PyThreadState *tstate, PyCodeObject *code, PyObject *globals,
727729
f->f_executing = 0;
728730
f->f_gen = NULL;
729731

730-
_PyObject_GC_TRACK(f);
731732
return f;
732733
}
733734

735+
PyFrameObject*
736+
PyFrame_New(PyThreadState *tstate, PyCodeObject *code,
737+
PyObject *globals, PyObject *locals)
738+
{
739+
PyFrameObject *f = _PyFrame_New_NoTrack(tstate, code, globals, locals);
740+
if (f)
741+
_PyObject_GC_TRACK(f);
742+
return f;
743+
}
744+
745+
734746
/* Block management */
735747

736748
void

Python/ceval.c

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3931,7 +3931,7 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
39313931
/* Create the frame */
39323932
tstate = PyThreadState_GET();
39333933
assert(tstate != NULL);
3934-
f = PyFrame_New(tstate, co, globals, locals);
3934+
f = _PyFrame_New_NoTrack(tstate, co, globals, locals);
39353935
if (f == NULL) {
39363936
return NULL;
39373937
}
@@ -4176,9 +4176,15 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
41764176
so recursion_depth must be boosted for the duration.
41774177
*/
41784178
assert(tstate != NULL);
4179-
++tstate->recursion_depth;
4180-
Py_DECREF(f);
4181-
--tstate->recursion_depth;
4179+
if (Py_REFCNT(f) > 1) {
4180+
Py_DECREF(f);
4181+
_PyObject_GC_TRACK(f);
4182+
}
4183+
else {
4184+
++tstate->recursion_depth;
4185+
Py_DECREF(f);
4186+
--tstate->recursion_depth;
4187+
}
41824188
return retval;
41834189
}
41844190

@@ -4904,11 +4910,11 @@ _PyFunction_FastCall(PyCodeObject *co, PyObject **args, Py_ssize_t nargs,
49044910

49054911
assert(globals != NULL);
49064912
/* XXX Perhaps we should create a specialized
4907-
PyFrame_New() that doesn't take locals, but does
4913+
_PyFrame_New_NoTrack() that doesn't take locals, but does
49084914
take builtins without sanity checking them.
49094915
*/
49104916
assert(tstate != NULL);
4911-
f = PyFrame_New(tstate, co, globals, NULL);
4917+
f = _PyFrame_New_NoTrack(tstate, co, globals, NULL);
49124918
if (f == NULL) {
49134919
return NULL;
49144920
}
@@ -4921,10 +4927,15 @@ _PyFunction_FastCall(PyCodeObject *co, PyObject **args, Py_ssize_t nargs,
49214927
}
49224928
result = PyEval_EvalFrameEx(f,0);
49234929

4924-
++tstate->recursion_depth;
4925-
Py_DECREF(f);
4926-
--tstate->recursion_depth;
4927-
4930+
if (Py_REFCNT(f) > 1) {
4931+
Py_DECREF(f);
4932+
_PyObject_GC_TRACK(f);
4933+
}
4934+
else {
4935+
++tstate->recursion_depth;
4936+
Py_DECREF(f);
4937+
--tstate->recursion_depth;
4938+
}
49284939
return result;
49294940
}
49304941

0 commit comments

Comments
 (0)