Pass reference to func, as well as args, when pushing frame.
diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h
index 85b9cf0f77bcb0..1ad156290a55e9 100644
--- a/Include/internal/pycore_frame.h
+++ b/Include/internal/pycore_frame.h
@@ -87,12 +87,12 @@ static inline void _PyFrame_StackPush(InterpreterFrame *f, PyObject *value) {
 
 void _PyFrame_Copy(InterpreterFrame *src, InterpreterFrame *dest);
 
+/* Consumes reference to func */
 static inline void
 _PyFrame_InitializeSpecials(
     InterpreterFrame *frame, PyFunctionObject *func,
     PyObject *locals, int nlocalsplus)
 {
-    Py_INCREF(func);
     frame->f_func = func;
     frame->f_code = (PyCodeObject *)Py_NewRef(func->func_code);
     frame->f_builtins = func->func_builtins;
@@ -166,9 +166,6 @@ _PyFrame_FastToLocalsWithError(InterpreterFrame *frame);
 void
 _PyFrame_LocalsToFast(InterpreterFrame *frame, int clear);
 
-InterpreterFrame *_PyThreadState_PushFrame(
-    PyThreadState *tstate, PyFunctionObject *func, PyObject *locals);
-
 extern InterpreterFrame *
 _PyThreadState_BumpFramePointerSlow(PyThreadState *tstate, size_t size);
 
@@ -189,6 +186,7 @@ _PyThreadState_BumpFramePointer(PyThreadState *tstate, size_t size)
 
 void _PyThreadState_PopFrame(PyThreadState *tstate, InterpreterFrame *frame);
 
+/* Consume reference to func */
 InterpreterFrame *
 _PyFrame_Push(PyThreadState *tstate, PyFunctionObject *func);
 
diff --git a/Objects/frameobject.c b/Objects/frameobject.c
index 15da1325d1480f..78f3894111bc3c 100644
--- a/Objects/frameobject.c
+++ b/Objects/frameobject.c
@@ -784,6 +784,8 @@ _Py_IDENTIFIER(__builtins__);
 static void
 init_frame(InterpreterFrame *frame, PyFunctionObject *func, PyObject *locals)
 {
+    /* _PyFrame_InitializeSpecials consumes reference to func */
+    Py_INCREF(func);
     PyCodeObject *code = (PyCodeObject *)func->func_code;
     _PyFrame_InitializeSpecials(frame, func, locals, code->co_nlocalsplus);
     for (Py_ssize_t i = 0; i < code->co_nlocalsplus; i++) {
diff --git a/Python/ceval.c b/Python/ceval.c
index 70748e8911f9fe..59c977781d446c 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -2243,6 +2243,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
                 goto error;
             }
             CALL_STAT_INC(frames_pushed);
+            Py_INCREF(getitem);
             _PyFrame_InitializeSpecials(new_frame, getitem,
                                         NULL, code->co_nlocalsplus);
             STACK_SHRINK(2);
@@ -4585,7 +4586,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
                 STACK_SHRINK(call_shape.postcall_shrink);
                 // The frame has stolen all the arguments from the stack,
                 // so there is no need to clean them up.
-                Py_DECREF(function);
                 if (new_frame == NULL) {
                     goto error;
                 }
@@ -4670,7 +4670,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
                 new_frame->localsplus[i] = NULL;
             }
             STACK_SHRINK(call_shape.postcall_shrink);
-            Py_DECREF(func);
             _PyFrame_SetStackPointer(frame, stack_pointer);
             new_frame->previous = frame;
             frame = cframe.current_frame = new_frame;
@@ -4707,7 +4706,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
                 new_frame->localsplus[i] = NULL;
             }
             STACK_SHRINK(call_shape.postcall_shrink);
-            Py_DECREF(func);
             _PyFrame_SetStackPointer(frame, stack_pointer);
             new_frame->previous = frame;
             frame = cframe.current_frame = new_frame;
@@ -6072,7 +6070,7 @@ initialize_locals(PyThreadState *tstate, PyFunctionObject *func,
     return -1;
 }
 
-/* Consumes all the references to the args */
+/* Consumes references to func and all the args */
 static InterpreterFrame *
 _PyEvalFramePushAndInit(PyThreadState *tstate, PyFunctionObject *func,
                         PyObject *locals, PyObject* const* args,
@@ -6126,7 +6124,9 @@ _PyEval_Vector(PyThreadState *tstate, PyFunctionObject *func,
                PyObject* const* args, size_t argcount,
                PyObject *kwnames)
 {
-    /* _PyEvalFramePushAndInit consumes all the references to its arguments */
+    /* _PyEvalFramePushAndInit consumes the references
+     * to func and all its arguments */
+    Py_INCREF(func);
     for (size_t i = 0; i < argcount; i++) {
         Py_INCREF(args[i]);
     }
diff --git a/Python/frame.c b/Python/frame.c
index ca7c5f9c94e07b..76697cfa083138 100644
--- a/Python/frame.c
+++ b/Python/frame.c
@@ -109,6 +109,7 @@ _PyFrame_Clear(InterpreterFrame *frame)
     Py_DECREF(frame->f_code);
 }
 
+/* Consumes reference to func */
 InterpreterFrame *
 _PyFrame_Push(PyThreadState *tstate, PyFunctionObject *func)
 {
@@ -117,6 +118,7 @@ _PyFrame_Push(PyThreadState *tstate, PyFunctionObject *func)
     CALL_STAT_INC(frames_pushed);
     InterpreterFrame *new_frame = _PyThreadState_BumpFramePointer(tstate, size);
     if (new_frame == NULL) {
+        Py_DECREF(func);
         return NULL;
     }
     _PyFrame_InitializeSpecials(new_frame, func, NULL, code->co_nlocalsplus);
diff --git a/Python/pystate.c b/Python/pystate.c
index 77467944e2afba..a85460c15103d1 100644
--- a/Python/pystate.c
+++ b/Python/pystate.c
@@ -2212,26 +2212,6 @@ _PyThreadState_BumpFramePointerSlow(PyThreadState *tstate, size_t size)
     return (InterpreterFrame *)base;
 }
 
-
-InterpreterFrame *
-_PyThreadState_PushFrame(PyThreadState *tstate, PyFunctionObject *func, PyObject *locals)
-{
-    PyCodeObject *code = (PyCodeObject *)func->func_code;
-    int nlocalsplus = code->co_nlocalsplus;
-    size_t size = nlocalsplus + code->co_stacksize +
-        FRAME_SPECIALS_SIZE;
-    CALL_STAT_INC(frames_pushed);
-    InterpreterFrame *frame  = _PyThreadState_BumpFramePointer(tstate, size);
-    if (frame == NULL) {
-        return NULL;
-    }
-    _PyFrame_InitializeSpecials(frame, func, locals, nlocalsplus);
-    for (int i=0; i < nlocalsplus; i++) {
-        frame->localsplus[i] = NULL;
-    }
-    return frame;
-}
-
 void
 _PyThreadState_PopFrame(PyThreadState *tstate, InterpreterFrame * frame)
 {

Minor efficiency improvement. When pushing a frame we transfer the references to the args to the frame. This does the same for the `func`.

Also removes unused function `_PyThreadState_PushFrame`.

This is all internal. 