cpython/Python/frame.c
Mark Shannon f9242d50b1
bpo-44990: Change layout of evaluation frames. "Layout B" (GH-27933)
Places the locals between the specials and stack. This is the more "natural" layout for a C struct, makes the code simpler and gives a slight speedup (~1%)
2021-08-25 13:44:20 +01:00

128 lines
3.4 KiB
C

#include "Python.h"
#include "frameobject.h"
#include "pycore_frame.h"
#include "pycore_object.h" // _PyObject_GC_UNTRACK()
int
_PyFrame_Traverse(InterpreterFrame *frame, visitproc visit, void *arg)
{
Py_VISIT(frame->frame_obj);
Py_VISIT(frame->f_globals);
Py_VISIT(frame->f_builtins);
Py_VISIT(frame->f_locals);
Py_VISIT(frame->f_code);
/* locals */
PyObject **locals = _PyFrame_GetLocalsArray(frame);
int i = 0;
/* locals and stack */
for (; i <frame->stacktop; i++) {
Py_VISIT(locals[i]);
}
return 0;
}
PyFrameObject *
_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);
if (f == NULL) {
Py_XDECREF(error_type);
Py_XDECREF(error_value);
Py_XDECREF(error_traceback);
}
else {
PyErr_Restore(error_type, error_value, error_traceback);
}
frame->frame_obj = f;
return f;
}
static InterpreterFrame *
copy_frame_to_heap(InterpreterFrame *frame)
{
assert(frame->stacktop >= frame->f_code->co_nlocalsplus);
Py_ssize_t size = ((char*)&frame->localsplus[frame->stacktop]) - (char *)frame;
InterpreterFrame *copy = PyMem_Malloc(size);
if (copy == NULL) {
PyErr_NoMemory();
return NULL;
}
memcpy(copy, frame, size);
return copy;
}
static inline void
clear_specials(InterpreterFrame *frame)
{
frame->generator = NULL;
Py_XDECREF(frame->frame_obj);
Py_XDECREF(frame->f_locals);
Py_DECREF(frame->f_globals);
Py_DECREF(frame->f_builtins);
Py_DECREF(frame->f_code);
}
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;
f->f_frame = frame;
assert(f->f_back == NULL);
if (frame->previous != NULL) {
/* Link PyFrameObjects.f_back and remove link through InterpreterFrame.previous */
PyFrameObject *back = _PyFrame_GetFrameObject(frame->previous);
if (back == NULL) {
/* Memory error here. */
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);
}
frame->previous = NULL;
}
if (!_PyObject_GC_IS_TRACKED((PyObject *)f)) {
_PyObject_GC_TRACK((PyObject *)f);
}
}
int
_PyFrame_Clear(InterpreterFrame * frame, int take)
{
if (frame->frame_obj) {
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;
}
Py_DECREF(f);
}
assert(_PyFrame_GetStackPointer(frame) >= _PyFrame_Stackbase(frame));
for (int i = 0; i < frame->stacktop; i++) {
Py_XDECREF(frame->localsplus[i]);
}
clear_specials(frame);
if (take) {
PyMem_Free(frame);
}
return 0;
}