]> granicus.if.org Git - python/commitdiff
Issue #29049: Call _PyObject_GC_TRACK() lazily when calling Python function.
authorINADA Naoki <songofacandy@gmail.com>
Sat, 24 Dec 2016 11:19:08 +0000 (20:19 +0900)
committerINADA Naoki <songofacandy@gmail.com>
Sat, 24 Dec 2016 11:19:08 +0000 (20:19 +0900)
Calling function is up to 5% faster.

Include/frameobject.h
Misc/NEWS
Objects/frameobject.c
Python/ceval.c

index 00c50933dc98f980dc14b878b049ff10b270d4f4..616c611c7e8e673e1fc953c982f55dd934f563d6 100644 (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 */
index 31ff5e3db2741b2d5c221239496146e04592dd97..76a84119898425290782a1d6f14ac341104b4396 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -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.
 
index eed538498c552f56b85da35a6ae21e0952ed1a42..84483195ab2ad48970ab9802b5581ef56fdb3abd 100644 (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
index f7ee04186417dc9174acaff9d1234fe0af2420c6..e48586dec244328745484c7723c4cc042f7e1148 100644 (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 @@ fail: /* Jump here from prelude on failure */
        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;
 }