[Python-checkins] bpo-45786: Allocate space for frame in frame object. (GH-29729)

markshannon webhook-mailer at python.org
Mon Nov 29 07:35:09 EST 2021


https://github.com/python/cpython/commit/60929576e40038ec71d896230f69e4411c82be4b
commit: 60929576e40038ec71d896230f69e4411c82be4b
branch: main
author: Mark Shannon <mark at hotpy.org>
committer: markshannon <mark at hotpy.org>
date: 2021-11-29T12:34:59Z
summary:

bpo-45786: Allocate space for frame in frame object. (GH-29729)

files:
A Misc/NEWS.d/next/Core and Builtins/2021-11-23-15-25-00.bpo-45786.UdEciD.rst
M Include/cpython/frameobject.h
M Include/internal/pycore_frame.h
M Include/internal/pycore_gc.h
M Include/internal/pycore_interp.h
M Lib/test/test_exceptions.py
M Lib/test/test_sys.py
M Modules/gcmodule.c
M Objects/frameobject.c
M Objects/genobject.c
M Python/ceval.c
M Python/frame.c

diff --git a/Include/cpython/frameobject.h b/Include/cpython/frameobject.h
index e4cfac518bb58..67f98a7642beb 100644
--- a/Include/cpython/frameobject.h
+++ b/Include/cpython/frameobject.h
@@ -12,7 +12,9 @@ struct _frame {
     int f_lineno;               /* Current line number. Only valid if non-zero */
     char f_trace_lines;         /* Emit per-line trace events? */
     char f_trace_opcodes;       /* Emit per-opcode trace events? */
-    char f_own_locals_memory;   /* This frame owns the memory for the locals */
+    char f_owns_frame;          /* This frame owns the frame */
+    /* The frame data, if this frame object owns the frame */
+    PyObject *_f_frame_data[1];
 };
 
 /* Standard object interface */
@@ -26,7 +28,7 @@ PyAPI_FUNC(PyFrameObject *) PyFrame_New(PyThreadState *, PyCodeObject *,
 
 /* only internal use */
 PyFrameObject*
-_PyFrame_New_NoTrack(struct _interpreter_frame *, int);
+_PyFrame_New_NoTrack(PyCodeObject *code);
 
 
 /* The rest of the interface is specific for frame objects */
diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h
index e36241f4a6a65..0015de8f8fcb4 100644
--- a/Include/internal/pycore_frame.h
+++ b/Include/internal/pycore_frame.h
@@ -69,8 +69,7 @@ static inline void _PyFrame_StackPush(InterpreterFrame *f, PyObject *value) {
 
 #define FRAME_SPECIALS_SIZE ((sizeof(InterpreterFrame)-1)/sizeof(PyObject *))
 
-InterpreterFrame *
-_PyInterpreterFrame_HeapAlloc(PyFunctionObject *func, PyObject *locals);
+InterpreterFrame *_PyFrame_Copy(InterpreterFrame *frame);
 
 static inline void
 _PyFrame_InitializeSpecials(
@@ -139,8 +138,8 @@ _PyFrame_GetFrameObject(InterpreterFrame *frame)
  * take should  be set to 1 for heap allocated
  * frames like the ones in generators and coroutines.
  */
-int
-_PyFrame_Clear(InterpreterFrame * frame, int take);
+void
+_PyFrame_Clear(InterpreterFrame * frame);
 
 int
 _PyFrame_Traverse(InterpreterFrame *frame, visitproc visit, void *arg);
diff --git a/Include/internal/pycore_gc.h b/Include/internal/pycore_gc.h
index 45e85b54c2ec2..129d53921dc49 100644
--- a/Include/internal/pycore_gc.h
+++ b/Include/internal/pycore_gc.h
@@ -167,7 +167,6 @@ extern Py_ssize_t _PyGC_CollectNoFail(PyThreadState *tstate);
 
 
 // Functions to clear types free lists
-extern void _PyFrame_ClearFreeList(PyInterpreterState *interp);
 extern void _PyTuple_ClearFreeList(PyInterpreterState *interp);
 extern void _PyFloat_ClearFreeList(PyInterpreterState *interp);
 extern void _PyList_ClearFreeList(PyInterpreterState *interp);
diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h
index 18f21432008d9..f52ee594106f9 100644
--- a/Include/internal/pycore_interp.h
+++ b/Include/internal/pycore_interp.h
@@ -93,7 +93,6 @@ struct _Py_unicode_state {
 #  define PyTuple_MAXFREELIST 1
 #  define PyList_MAXFREELIST 0
 #  define PyDict_MAXFREELIST 0
-#  define PyFrame_MAXFREELIST 0
 #  define _PyAsyncGen_MAXFREELIST 0
 #  define PyContext_MAXFREELIST 0
 #endif
@@ -158,18 +157,6 @@ struct _Py_dict_state {
 #endif
 };
 
-#ifndef PyFrame_MAXFREELIST
-#  define PyFrame_MAXFREELIST 200
-#endif
-
-struct _Py_frame_state {
-#if PyFrame_MAXFREELIST > 0
-    PyFrameObject *free_list;
-    /* number of frames currently in free_list */
-    int numfree;
-#endif
-};
-
 #ifndef _PyAsyncGen_MAXFREELIST
 #  define _PyAsyncGen_MAXFREELIST 80
 #endif
@@ -332,7 +319,6 @@ struct _is {
     struct _Py_tuple_state tuple;
     struct _Py_list_state list;
     struct _Py_dict_state dict_state;
-    struct _Py_frame_state frame;
     struct _Py_async_gen_state async_gen;
     struct _Py_context_state context;
     struct _Py_exc_state exc_state;
diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py
index 7f087d085a810..c6660043c805f 100644
--- a/Lib/test/test_exceptions.py
+++ b/Lib/test/test_exceptions.py
@@ -209,7 +209,7 @@ def check(self, src, lineno, offset, encoding='utf-8'):
                     src = src.decode(encoding, 'replace')
                 line = src.split('\n')[lineno-1]
                 self.assertIn(line, cm.exception.text)
-    
+
     def test_error_offset_continuation_characters(self):
         check = self.check
         check('"\\\n"(1 for c in I,\\\n\\', 2, 2)
@@ -1342,9 +1342,7 @@ def recurse(cnt):
         """
         with SuppressCrashReport():
             rc, out, err = script_helper.assert_python_failure("-c", code)
-            self.assertIn(b'Fatal Python error: _PyErr_NormalizeException: '
-                          b'Cannot recover from MemoryErrors while '
-                          b'normalizing exceptions.', err)
+            self.assertIn(b'MemoryError', err)
 
     @cpython_only
     def test_MemoryError(self):
diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py
index b0688e1e605fe..db8d0082085cb 100644
--- a/Lib/test/test_sys.py
+++ b/Lib/test/test_sys.py
@@ -1320,9 +1320,10 @@ class C(object): pass
         # sys.floatinfo
         check(sys.float_info, vsize('') + self.P * len(sys.float_info))
         # frame
-        import inspect
-        x = inspect.currentframe()
-        check(x, size('3Pi3c'))
+        def func():
+            return sys._getframe()
+        x = func()
+        check(x, size('3Pi3c8P2iciP'))
         # function
         def func(): pass
         check(func, size('14Pi'))
diff --git a/Misc/NEWS.d/next/Core and Builtins/2021-11-23-15-25-00.bpo-45786.UdEciD.rst b/Misc/NEWS.d/next/Core and Builtins/2021-11-23-15-25-00.bpo-45786.UdEciD.rst
new file mode 100644
index 0000000000000..c88f1165a045e
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2021-11-23-15-25-00.bpo-45786.UdEciD.rst	
@@ -0,0 +1,2 @@
+Allocate space for the interpreter frame in the frame object, to avoid an
+additional allocation when the frame object outlives the frame activation.
diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c
index 7d1a45bcaeabf..b505676636d38 100644
--- a/Modules/gcmodule.c
+++ b/Modules/gcmodule.c
@@ -1038,7 +1038,6 @@ delete_garbage(PyThreadState *tstate, GCState *gcstate,
 static void
 clear_freelists(PyInterpreterState *interp)
 {
-    _PyFrame_ClearFreeList(interp);
     _PyTuple_ClearFreeList(interp);
     _PyFloat_ClearFreeList(interp);
     _PyList_ClearFreeList(interp);
diff --git a/Objects/frameobject.c b/Objects/frameobject.c
index 2a283b3113cb5..926a32a5100bd 100644
--- a/Objects/frameobject.c
+++ b/Objects/frameobject.c
@@ -610,7 +610,7 @@ static PyGetSetDef frame_getsetlist[] = {
     f_back              next item on free list, or NULL
 */
 
-static void _Py_HOT_FUNCTION
+static void
 frame_dealloc(PyFrameObject *f)
 {
     if (_PyObject_GC_IS_TRACKED(f)) {
@@ -621,9 +621,10 @@ frame_dealloc(PyFrameObject *f)
     PyCodeObject *co = NULL;
 
     /* Kill all local variables including specials, if we own them */
-    if (f->f_own_locals_memory) {
-        f->f_own_locals_memory = 0;
-        InterpreterFrame *frame = f->f_frame;
+    if (f->f_owns_frame) {
+        f->f_owns_frame = 0;
+        assert(f->f_frame == (InterpreterFrame *)f->_f_frame_data);
+        InterpreterFrame *frame = (InterpreterFrame *)f->_f_frame_data;
         /* Don't clear code object until the end */
         co = frame->f_code;
         frame->f_code = NULL;
@@ -633,27 +634,10 @@ frame_dealloc(PyFrameObject *f)
         for (int i = 0; i < frame->stacktop; i++) {
             Py_CLEAR(locals[i]);
         }
-        PyMem_Free(frame);
     }
     Py_CLEAR(f->f_back);
     Py_CLEAR(f->f_trace);
-#if PyFrame_MAXFREELIST > 0
-    struct _Py_frame_state *state = get_frame_state();
-#ifdef Py_DEBUG
-    // frame_dealloc() must not be called after _PyFrame_Fini()
-    assert(state->numfree != -1);
-#endif
-    if (state->numfree < PyFrame_MAXFREELIST) {
-        ++state->numfree;
-        f->f_back = state->free_list;
-        state->free_list = f;
-    }
-    else
-#endif
-    {
-        PyObject_GC_Del(f);
-    }
-
+    PyObject_GC_Del(f);
     Py_XDECREF(co);
     Py_TRASHCAN_END;
 }
@@ -663,7 +647,7 @@ frame_traverse(PyFrameObject *f, visitproc visit, void *arg)
 {
     Py_VISIT(f->f_back);
     Py_VISIT(f->f_trace);
-    if (f->f_own_locals_memory == 0) {
+    if (f->f_owns_frame == 0) {
         return 0;
     }
     assert(f->f_frame->frame_obj == NULL);
@@ -715,11 +699,9 @@ static PyObject *
 frame_sizeof(PyFrameObject *f, PyObject *Py_UNUSED(ignored))
 {
     Py_ssize_t res;
-    res = sizeof(PyFrameObject);
-    if (f->f_own_locals_memory) {
-        PyCodeObject *code = f->f_frame->f_code;
-        res += (code->co_nlocalsplus+code->co_stacksize) * sizeof(PyObject *);
-    }
+    res = offsetof(PyFrameObject, _f_frame_data) + offsetof(InterpreterFrame, localsplus);
+    PyCodeObject *code = f->f_frame->f_code;
+    res += (code->co_nlocalsplus+code->co_stacksize) * sizeof(PyObject *);
     return PyLong_FromSsize_t(res);
 }
 
@@ -747,7 +729,8 @@ static PyMethodDef frame_methods[] = {
 PyTypeObject PyFrame_Type = {
     PyVarObject_HEAD_INIT(&PyType_Type, 0)
     "frame",
-    sizeof(PyFrameObject),
+    offsetof(PyFrameObject, _f_frame_data) +
+    offsetof(InterpreterFrame, localsplus),
     sizeof(PyObject *),
     (destructor)frame_dealloc,                  /* tp_dealloc */
     0,                                          /* tp_vectorcall_offset */
@@ -781,67 +764,21 @@ PyTypeObject PyFrame_Type = {
 
 _Py_IDENTIFIER(__builtins__);
 
-static InterpreterFrame *
-allocate_heap_frame(PyFunctionObject *func, PyObject *locals)
+static void
+init_frame(InterpreterFrame *frame, PyFunctionObject *func, PyObject *locals)
 {
     PyCodeObject *code = (PyCodeObject *)func->func_code;
-    int size = code->co_nlocalsplus+code->co_stacksize + FRAME_SPECIALS_SIZE;
-    InterpreterFrame *frame = (InterpreterFrame *)PyMem_Malloc(sizeof(PyObject *)*size);
-    if (frame == NULL) {
-        PyErr_NoMemory();
-        return NULL;
-    }
     _PyFrame_InitializeSpecials(frame, func, locals, code->co_nlocalsplus);
     for (Py_ssize_t i = 0; i < code->co_nlocalsplus; i++) {
         frame->localsplus[i] = NULL;
     }
-    return frame;
 }
 
-static inline PyFrameObject*
-frame_alloc(InterpreterFrame *frame, int owns)
-{
-    PyFrameObject *f;
-#if PyFrame_MAXFREELIST > 0
-    struct _Py_frame_state *state = get_frame_state();
-    if (state->free_list == NULL)
-#endif
-    {
-        f = PyObject_GC_New(PyFrameObject, &PyFrame_Type);
-        if (f == NULL) {
-            if (owns) {
-                Py_XDECREF(frame->f_code);
-                Py_XDECREF(frame->f_builtins);
-                Py_XDECREF(frame->f_globals);
-                Py_XDECREF(frame->f_locals);
-                PyMem_Free(frame);
-            }
-            return NULL;
-        }
-    }
-#if PyFrame_MAXFREELIST > 0
-    else
-    {
-#ifdef Py_DEBUG
-        // frame_alloc() must not be called after _PyFrame_Fini()
-        assert(state->numfree != -1);
-#endif
-        assert(state->numfree > 0);
-        --state->numfree;
-        f = state->free_list;
-        state->free_list = state->free_list->f_back;
-        _Py_NewReference((PyObject *)f);
-    }
-#endif
-    f->f_frame = frame;
-    f->f_own_locals_memory = owns;
-    return f;
-}
-
-PyFrameObject* _Py_HOT_FUNCTION
-_PyFrame_New_NoTrack(InterpreterFrame *frame, int owns)
+PyFrameObject*
+_PyFrame_New_NoTrack(PyCodeObject *code)
 {
-    PyFrameObject *f = frame_alloc(frame, owns);
+    int slots = code->co_nlocalsplus + code->co_stacksize;
+    PyFrameObject *f = PyObject_GC_NewVar(PyFrameObject, &PyFrame_Type, slots);
     if (f == NULL) {
         return NULL;
     }
@@ -876,15 +813,16 @@ PyFrame_New(PyThreadState *tstate, PyCodeObject *code,
     if (func == NULL) {
         return NULL;
     }
-    InterpreterFrame *frame = allocate_heap_frame(func, locals);
-    Py_DECREF(func);
-    if (frame == NULL) {
+    PyFrameObject *f = _PyFrame_New_NoTrack(code);
+    if (f == NULL) {
+        Py_DECREF(func);
         return NULL;
     }
-    PyFrameObject *f = _PyFrame_New_NoTrack(frame, 1);
-    if (f) {
-        _PyObject_GC_TRACK(f);
-    }
+    init_frame((InterpreterFrame *)f->_f_frame_data, func, locals);
+    f->f_frame = (InterpreterFrame *)f->_f_frame_data;
+    f->f_owns_frame = 1;
+    Py_DECREF(func);
+    _PyObject_GC_TRACK(f);
     return f;
 }
 
@@ -1087,42 +1025,15 @@ PyFrame_LocalsToFast(PyFrameObject *f, int clear)
     _PyFrame_LocalsToFast(f->f_frame, clear);
 }
 
-/* Clear out the free list */
-void
-_PyFrame_ClearFreeList(PyInterpreterState *interp)
-{
-#if PyFrame_MAXFREELIST > 0
-    struct _Py_frame_state *state = &interp->frame;
-    while (state->free_list != NULL) {
-        PyFrameObject *f = state->free_list;
-        state->free_list = state->free_list->f_back;
-        PyObject_GC_Del(f);
-        --state->numfree;
-    }
-    assert(state->numfree == 0);
-#endif
-}
-
 void
 _PyFrame_Fini(PyInterpreterState *interp)
 {
-    _PyFrame_ClearFreeList(interp);
-#if defined(Py_DEBUG) && PyFrame_MAXFREELIST > 0
-    struct _Py_frame_state *state = &interp->frame;
-    state->numfree = -1;
-#endif
 }
 
 /* Print summary info about the state of the optimized allocator */
 void
 _PyFrame_DebugMallocStats(FILE *out)
 {
-#if PyFrame_MAXFREELIST > 0
-    struct _Py_frame_state *state = get_frame_state();
-    _PyDebugAllocatorStats(out,
-                           "free PyFrameObject",
-                           state->numfree, sizeof(PyFrameObject));
-#endif
 }
 
 
diff --git a/Objects/genobject.c b/Objects/genobject.c
index 24d5f3579cbf2..04d98a2b4edf1 100644
--- a/Objects/genobject.c
+++ b/Objects/genobject.c
@@ -38,7 +38,7 @@ gen_traverse(PyGenObject *gen, visitproc visit, void *arg)
     Py_VISIT(gen->gi_qualname);
     InterpreterFrame *frame = gen->gi_xframe;
     if (frame != NULL) {
-        assert(frame->frame_obj == NULL || frame->frame_obj->f_own_locals_memory == 0);
+        assert(frame->frame_obj == NULL || frame->frame_obj->f_owns_frame == 0);
         int err = _PyFrame_Traverse(frame, visit, arg);
         if (err) {
             return err;
@@ -136,7 +136,8 @@ gen_dealloc(PyGenObject *gen)
         gen->gi_xframe = NULL;
         frame->generator = NULL;
         frame->previous = NULL;
-        _PyFrame_Clear(frame, 1);
+        _PyFrame_Clear(frame);
+        PyMem_Free(frame);
     }
     if (((PyCodeObject *)gen->gi_code)->co_flags & CO_COROUTINE) {
         Py_CLEAR(((PyCoroObject *)gen)->cr_origin);
@@ -254,7 +255,8 @@ gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult,
 
     frame->generator = NULL;
     gen->gi_xframe = NULL;
-    _PyFrame_Clear(frame, 1);
+    _PyFrame_Clear(frame);
+    PyMem_Free(frame);
     *presult = result;
     return result ? PYGEN_RETURN : PYGEN_ERROR;
 }
@@ -845,7 +847,8 @@ make_gen(PyTypeObject *type, PyFunctionObject *func, InterpreterFrame *frame)
     PyGenObject *gen = PyObject_GC_New(PyGenObject, type);
     if (gen == NULL) {
         assert(frame->frame_obj == NULL);
-        _PyFrame_Clear(frame, 1);
+        _PyFrame_Clear(frame);
+        PyMem_Free(frame);
         return NULL;
     }
     gen->gi_xframe = frame;
@@ -929,10 +932,15 @@ gen_new_with_qualname(PyTypeObject *type, PyFrameObject *f,
 
     /* Take ownership of the frame */
     assert(f->f_frame->frame_obj == NULL);
-    assert(f->f_own_locals_memory);
-    gen->gi_xframe = f->f_frame;
+    assert(f->f_owns_frame);
+    gen->gi_xframe = _PyFrame_Copy((InterpreterFrame *)f->_f_frame_data);
+    if (gen->gi_xframe == NULL) {
+        Py_DECREF(f);
+        Py_DECREF(gen);
+        return NULL;
+    }
     gen->gi_xframe->frame_obj = f;
-    f->f_own_locals_memory = 0;
+    f->f_owns_frame = 0;
     gen->gi_xframe->generator = (PyObject *) gen;
     assert(PyObject_GC_IsTracked((PyObject *)f));
 
diff --git a/Python/ceval.c b/Python/ceval.c
index 9beb1a4368226..0427361a03a8b 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -5694,7 +5694,8 @@ make_coro_frame(PyThreadState *tstate,
     }
     assert(frame->frame_obj == NULL);
     if (initialize_locals(tstate, func, frame->localsplus, args, argcount, kwnames)) {
-        _PyFrame_Clear(frame, 1);
+        _PyFrame_Clear(frame);
+        PyMem_Free(frame);
         return NULL;
     }
     return frame;
@@ -5750,7 +5751,7 @@ _PyEvalFramePushAndInit(PyThreadState *tstate, PyFunctionObject *func,
         localsarray[i] = NULL;
     }
     if (initialize_locals(tstate, func, localsarray, args, argcount, kwnames)) {
-        _PyFrame_Clear(frame, 0);
+        _PyFrame_Clear(frame);
         return NULL;
     }
     return frame;
@@ -5773,11 +5774,8 @@ static int
 _PyEvalFrameClearAndPop(PyThreadState *tstate, InterpreterFrame * frame)
 {
     --tstate->recursion_remaining;
-    assert(frame->frame_obj == NULL || frame->frame_obj->f_own_locals_memory == 0);
-    if (_PyFrame_Clear(frame, 0)) {
-        ++tstate->recursion_remaining;
-        return -1;
-    }
+    assert(frame->frame_obj == NULL || frame->frame_obj->f_owns_frame == 0);
+    _PyFrame_Clear(frame);
     ++tstate->recursion_remaining;
     _PyThreadState_PopFrame(tstate, frame);
     return 0;
diff --git a/Python/frame.c b/Python/frame.c
index 79b0f77a0657e..21f2ced959d80 100644
--- a/Python/frame.c
+++ b/Python/frame.c
@@ -27,22 +27,24 @@ _PyFrame_MakeAndSetFrameObject(InterpreterFrame *frame)
     assert(frame->frame_obj == NULL);
     PyObject *error_type, *error_value, *error_traceback;
     PyErr_Fetch(&error_type, &error_value, &error_traceback);
-    PyFrameObject *f = _PyFrame_New_NoTrack(frame, 0);
+
+    PyFrameObject *f = _PyFrame_New_NoTrack(frame->f_code);
     if (f == NULL) {
         Py_XDECREF(error_type);
         Py_XDECREF(error_value);
         Py_XDECREF(error_traceback);
     }
     else {
+        f->f_owns_frame = 0;
+        f->f_frame = frame;
+        frame->frame_obj = f;
         PyErr_Restore(error_type, error_value, error_traceback);
     }
-    frame->frame_obj = f;
     return f;
 }
 
-
-static InterpreterFrame *
-copy_frame_to_heap(InterpreterFrame *frame)
+InterpreterFrame *
+_PyFrame_Copy(InterpreterFrame *frame)
 {
     assert(frame->stacktop >= frame->f_code->co_nlocalsplus);
     Py_ssize_t size = ((char*)&frame->localsplus[frame->stacktop]) - (char *)frame;
@@ -68,10 +70,11 @@ clear_specials(InterpreterFrame *frame)
 static void
 take_ownership(PyFrameObject *f, InterpreterFrame *frame)
 {
-    assert(f->f_own_locals_memory == 0);
-    assert(frame->frame_obj == NULL);
-
-    f->f_own_locals_memory = 1;
+    assert(f->f_owns_frame == 0);
+    Py_ssize_t size = ((char*)&frame->localsplus[frame->stacktop]) - (char *)frame;
+    memcpy((InterpreterFrame *)f->_f_frame_data, frame, size);
+    frame = (InterpreterFrame *)f->_f_frame_data;
+    f->f_owns_frame = 1;
     f->f_frame = frame;
     assert(f->f_back == NULL);
     if (frame->previous != NULL) {
@@ -82,7 +85,6 @@ take_ownership(PyFrameObject *f, InterpreterFrame *frame)
             assert(PyErr_ExceptionMatches(PyExc_MemoryError));
             /* Nothing we can do about it */
             PyErr_Clear();
-            _PyErr_WriteUnraisableMsg("Out of memory lazily allocating frame->f_back", NULL);
         }
         else {
             f->f_back = (PyFrameObject *)Py_NewRef(back);
@@ -94,8 +96,8 @@ take_ownership(PyFrameObject *f, InterpreterFrame *frame)
     }
 }
 
-int
-_PyFrame_Clear(InterpreterFrame * frame, int take)
+void
+_PyFrame_Clear(InterpreterFrame * frame)
 {
     /* It is the responsibility of the owning generator/coroutine
      * to have cleared the generator pointer */
@@ -104,15 +106,9 @@ _PyFrame_Clear(InterpreterFrame * frame, int take)
         PyFrameObject *f = frame->frame_obj;
         frame->frame_obj = NULL;
         if (Py_REFCNT(f) > 1) {
-            if (!take) {
-                frame = copy_frame_to_heap(frame);
-                if (frame == NULL) {
-                    return -1;
-                }
-            }
             take_ownership(f, frame);
             Py_DECREF(f);
-            return 0;
+            return;
         }
         Py_DECREF(f);
     }
@@ -121,8 +117,4 @@ _PyFrame_Clear(InterpreterFrame * frame, int take)
         Py_XDECREF(frame->localsplus[i]);
     }
     clear_specials(frame);
-    if (take) {
-        PyMem_Free(frame);
-    }
-    return 0;
 }



More information about the Python-checkins mailing list