aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/tools/python3/src/Objects/frameobject.c
diff options
context:
space:
mode:
authorshadchin <shadchin@yandex-team.ru>2022-04-18 12:39:32 +0300
committershadchin <shadchin@yandex-team.ru>2022-04-18 12:39:32 +0300
commitd4be68e361f4258cf0848fc70018dfe37a2acc24 (patch)
tree153e294cd97ac8b5d7a989612704a0c1f58e8ad4 /contrib/tools/python3/src/Objects/frameobject.c
parent260c02f5ccf242d9d9b8a873afaf6588c00237d6 (diff)
downloadydb-d4be68e361f4258cf0848fc70018dfe37a2acc24.tar.gz
IGNIETFERRO-1816 Update Python 3 from 3.9.12 to 3.10.4
ref:9f96be6d02ee8044fdd6f124b799b270c20ce641
Diffstat (limited to 'contrib/tools/python3/src/Objects/frameobject.c')
-rw-r--r--contrib/tools/python3/src/Objects/frameobject.c435
1 files changed, 201 insertions, 234 deletions
diff --git a/contrib/tools/python3/src/Objects/frameobject.c b/contrib/tools/python3/src/Objects/frameobject.c
index 4ae17bcfc2..d02cf9d3ba 100644
--- a/contrib/tools/python3/src/Objects/frameobject.c
+++ b/contrib/tools/python3/src/Objects/frameobject.c
@@ -1,27 +1,34 @@
/* Frame object implementation */
#include "Python.h"
-#include "pycore_object.h"
-#include "pycore_gc.h" // _PyObject_GC_IS_TRACKED()
+#include "pycore_ceval.h" // _PyEval_BuiltinsFromGlobals()
+#include "pycore_moduleobject.h" // _PyModule_GetDict()
+#include "pycore_object.h" // _PyObject_GC_UNTRACK()
-#include "code.h"
-#include "frameobject.h"
-#include "opcode.h"
+#include "frameobject.h" // PyFrameObject
+#include "opcode.h" // EXTENDED_ARG
#include "structmember.h" // PyMemberDef
#define OFF(x) offsetof(PyFrameObject, x)
static PyMemberDef frame_memberlist[] = {
{"f_back", T_OBJECT, OFF(f_back), READONLY},
- {"f_code", T_OBJECT, OFF(f_code), READONLY|READ_RESTRICTED},
+ {"f_code", T_OBJECT, OFF(f_code), READONLY|PY_AUDIT_READ},
{"f_builtins", T_OBJECT, OFF(f_builtins), READONLY},
{"f_globals", T_OBJECT, OFF(f_globals), READONLY},
- {"f_lasti", T_INT, OFF(f_lasti), READONLY},
{"f_trace_lines", T_BOOL, OFF(f_trace_lines), 0},
{"f_trace_opcodes", T_BOOL, OFF(f_trace_opcodes), 0},
{NULL} /* Sentinel */
};
+static struct _Py_frame_state *
+get_frame_state(void)
+{
+ PyInterpreterState *interp = _PyInterpreterState_GET();
+ return &interp->frame;
+}
+
+
static PyObject *
frame_getlocals(PyFrameObject *f, void *closure)
{
@@ -35,18 +42,33 @@ int
PyFrame_GetLineNumber(PyFrameObject *f)
{
assert(f != NULL);
- if (f->f_trace) {
+ if (f->f_lineno != 0) {
return f->f_lineno;
}
else {
- return PyCode_Addr2Line(f->f_code, f->f_lasti);
+ return PyCode_Addr2Line(f->f_code, f->f_lasti*sizeof(_Py_CODEUNIT));
}
}
static PyObject *
frame_getlineno(PyFrameObject *f, void *closure)
{
- return PyLong_FromLong(PyFrame_GetLineNumber(f));
+ int lineno = PyFrame_GetLineNumber(f);
+ if (lineno < 0) {
+ Py_RETURN_NONE;
+ }
+ else {
+ return PyLong_FromLong(lineno);
+ }
+}
+
+static PyObject *
+frame_getlasti(PyFrameObject *f, void *closure)
+{
+ if (f->f_lasti < 0) {
+ return PyLong_FromLong(-1);
+ }
+ return PyLong_FromLong(f->f_lasti*sizeof(_Py_CODEUNIT));
}
@@ -128,7 +150,7 @@ markblocks(PyCodeObject *code_obj, int len)
case POP_JUMP_IF_FALSE:
case POP_JUMP_IF_TRUE:
case JUMP_IF_NOT_EXC_MATCH:
- j = get_arg(code, i) / sizeof(_Py_CODEUNIT);
+ j = get_arg(code, i);
assert(j < len);
if (blocks[j] == -1 && j < i) {
todo = 1;
@@ -138,7 +160,7 @@ markblocks(PyCodeObject *code_obj, int len)
blocks[i+1] = block_stack;
break;
case JUMP_ABSOLUTE:
- j = get_arg(code, i) / sizeof(_Py_CODEUNIT);
+ j = get_arg(code, i);
assert(j < len);
if (blocks[j] == -1 && j < i) {
todo = 1;
@@ -147,7 +169,7 @@ markblocks(PyCodeObject *code_obj, int len)
blocks[j] = block_stack;
break;
case SETUP_FINALLY:
- j = get_arg(code, i) / sizeof(_Py_CODEUNIT) + i + 1;
+ j = get_arg(code, i) + i + 1;
assert(j < len);
except_stack = push_block(block_stack, Except);
assert(blocks[j] == -1 || blocks[j] == except_stack);
@@ -157,7 +179,7 @@ markblocks(PyCodeObject *code_obj, int len)
break;
case SETUP_WITH:
case SETUP_ASYNC_WITH:
- j = get_arg(code, i) / sizeof(_Py_CODEUNIT) + i + 1;
+ j = get_arg(code, i) + i + 1;
assert(j < len);
except_stack = push_block(block_stack, Except);
assert(blocks[j] == -1 || blocks[j] == except_stack);
@@ -166,7 +188,7 @@ markblocks(PyCodeObject *code_obj, int len)
blocks[i+1] = block_stack;
break;
case JUMP_FORWARD:
- j = get_arg(code, i) / sizeof(_Py_CODEUNIT) + i + 1;
+ j = get_arg(code, i) + i + 1;
assert(j < len);
assert(blocks[j] == -1 || blocks[j] == block_stack);
blocks[j] = block_stack;
@@ -179,7 +201,7 @@ markblocks(PyCodeObject *code_obj, int len)
case FOR_ITER:
blocks[i+1] = block_stack;
block_stack = pop_block(block_stack);
- j = get_arg(code, i) / sizeof(_Py_CODEUNIT) + i + 1;
+ j = get_arg(code, i) + i + 1;
assert(j < len);
assert(blocks[j] == -1 || blocks[j] == block_stack);
blocks[j] = block_stack;
@@ -240,36 +262,22 @@ explain_incompatible_block_stack(int64_t to_stack)
static int *
marklines(PyCodeObject *code, int len)
{
+ PyCodeAddressRange bounds;
+ _PyCode_InitAddressRange(code, &bounds);
+ assert (bounds.ar_end == 0);
+
int *linestarts = PyMem_New(int, len);
if (linestarts == NULL) {
return NULL;
}
- Py_ssize_t size = PyBytes_GET_SIZE(code->co_lnotab) / 2;
- unsigned char *p = (unsigned char*)PyBytes_AS_STRING(code->co_lnotab);
- int line = code->co_firstlineno;
- int addr = 0;
- int index = 0;
- while (--size >= 0) {
- addr += *p++;
- if (index*2 < addr) {
- linestarts[index++] = line;
- }
- while (index*2 < addr) {
- linestarts[index++] = -1;
- if (index >= len) {
- break;
- }
- }
- line += (signed char)*p;
- p++;
- }
- if (index < len) {
- linestarts[index++] = line;
+ for (int i = 0; i < len; i++) {
+ linestarts[i] = -1;
}
- while (index < len) {
- linestarts[index++] = -1;
+
+ while (PyLineTable_NextAddressRange(&bounds)) {
+ assert(bounds.ar_start/(int)sizeof(_Py_CODEUNIT) < len);
+ linestarts[bounds.ar_start/sizeof(_Py_CODEUNIT)] = bounds.ar_line;
}
- assert(index == len);
return linestarts;
}
@@ -291,17 +299,20 @@ first_line_not_before(int *lines, int len, int line)
static void
frame_stack_pop(PyFrameObject *f)
{
- PyObject *v = (*--f->f_stacktop);
+ assert(f->f_stackdepth >= 0);
+ f->f_stackdepth--;
+ PyObject *v = f->f_valuestack[f->f_stackdepth];
Py_DECREF(v);
}
static void
frame_block_unwind(PyFrameObject *f)
{
+ assert(f->f_stackdepth >= 0);
assert(f->f_iblock > 0);
f->f_iblock--;
PyTryBlock *b = &f->f_blockstack[f->f_iblock];
- intptr_t delta = (f->f_stacktop - f->f_valuestack) - b->b_level;
+ intptr_t delta = f->f_stackdepth - b->b_level;
while (delta > 0) {
frame_stack_pop(f);
delta--;
@@ -343,33 +354,36 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore
return -1;
}
- /* Upon the 'call' trace event of a new frame, f->f_lasti is -1 and
- * f->f_trace is NULL, check first on the first condition.
- * Forbidding jumps from the 'call' event of a new frame is a side effect
- * of allowing to set f_lineno only from trace functions. */
- if (f->f_lasti == -1) {
- PyErr_Format(PyExc_ValueError,
+ /*
+ * This code preserves the historical restrictions on
+ * setting the line number of a frame.
+ * Jumps are forbidden on a 'return' trace event (except after a yield).
+ * Jumps from 'call' trace events are also forbidden.
+ * In addition, jumps are forbidden when not tracing,
+ * as this is a debugging feature.
+ */
+ switch(f->f_state) {
+ case FRAME_CREATED:
+ PyErr_Format(PyExc_ValueError,
"can't jump from the 'call' trace event of a new frame");
- return -1;
- }
-
- /* You can only do this from within a trace function, not via
- * _getframe or similar hackery. */
- if (!f->f_trace) {
- PyErr_Format(PyExc_ValueError,
- "f_lineno can only be set by a trace function");
- return -1;
- }
-
- /* Forbid jumps upon a 'return' trace event (except after executing a
- * YIELD_VALUE or YIELD_FROM opcode, f_stacktop is not NULL in that case)
- * and upon an 'exception' trace event.
- * Jumps from 'call' trace events have already been forbidden above for new
- * frames, so this check does not change anything for 'call' events. */
- if (f->f_stacktop == NULL) {
- PyErr_SetString(PyExc_ValueError,
+ return -1;
+ case FRAME_RETURNED:
+ case FRAME_UNWINDING:
+ case FRAME_RAISED:
+ case FRAME_CLEARED:
+ PyErr_SetString(PyExc_ValueError,
"can only jump from a 'line' trace event");
- return -1;
+ return -1;
+ case FRAME_EXECUTING:
+ case FRAME_SUSPENDED:
+ /* You can only do this from within a trace function, not via
+ * _getframe or similar hackery. */
+ if (!f->f_trace) {
+ PyErr_Format(PyExc_ValueError,
+ "f_lineno can only be set by a trace function");
+ return -1;
+ }
+ break;
}
int new_lineno;
@@ -423,7 +437,7 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore
int64_t target_block_stack = -1;
int64_t best_block_stack = -1;
int best_addr = -1;
- int64_t start_block_stack = blocks[f->f_lasti/sizeof(_Py_CODEUNIT)];
+ int64_t start_block_stack = blocks[f->f_lasti];
const char *msg = "cannot find bytecode for specified line";
for (int i = 0; i < len; i++) {
if (lines[i] == new_lineno) {
@@ -432,7 +446,7 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore
msg = NULL;
if (target_block_stack > best_block_stack) {
best_block_stack = target_block_stack;
- best_addr = i*sizeof(_Py_CODEUNIT);
+ best_addr = i;
}
}
else if (msg) {
@@ -475,8 +489,8 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore
start_block_stack = pop_block(start_block_stack);
}
- /* Finally set the new f_lineno and f_lasti and return OK. */
- f->f_lineno = new_lineno;
+ /* Finally set the new f_lasti and return OK. */
+ f->f_lineno = 0;
f->f_lasti = best_addr;
return 0;
}
@@ -497,11 +511,9 @@ frame_gettrace(PyFrameObject *f, void *closure)
static int
frame_settrace(PyFrameObject *f, PyObject* v, void *closure)
{
- /* We rely on f_lineno being accurate when f_trace is set. */
- f->f_lineno = PyFrame_GetLineNumber(f);
-
- if (v == Py_None)
+ if (v == Py_None) {
v = NULL;
+ }
Py_XINCREF(v);
Py_XSETREF(f->f_trace, v);
@@ -514,6 +526,7 @@ static PyGetSetDef frame_getsetlist[] = {
{"f_lineno", (getter)frame_getlineno,
(setter)frame_setlineno, NULL},
{"f_trace", (getter)frame_gettrace, (setter)frame_settrace, NULL},
+ {"f_lasti", (getter)frame_getlasti, NULL, NULL},
{0}
};
@@ -561,31 +574,25 @@ static PyGetSetDef frame_getsetlist[] = {
/* max value for numfree */
#define PyFrame_MAXFREELIST 200
-#if PyFrame_MAXFREELIST > 0
-static PyFrameObject *free_list = NULL;
-static int numfree = 0; /* number of frames currently in free_list */
-#endif
-
static void _Py_HOT_FUNCTION
frame_dealloc(PyFrameObject *f)
{
- PyObject **p, **valuestack;
- PyCodeObject *co;
-
- if (_PyObject_GC_IS_TRACKED(f))
+ if (_PyObject_GC_IS_TRACKED(f)) {
_PyObject_GC_UNTRACK(f);
+ }
Py_TRASHCAN_BEGIN(f, frame_dealloc);
/* Kill all local variables */
- valuestack = f->f_valuestack;
- for (p = f->f_localsplus; p < valuestack; p++)
+ PyObject **valuestack = f->f_valuestack;
+ for (PyObject **p = f->f_localsplus; p < valuestack; p++) {
Py_CLEAR(*p);
+ }
/* Free stack */
- if (f->f_stacktop != NULL) {
- for (p = valuestack; p < f->f_stacktop; p++)
- Py_XDECREF(*p);
+ for (int i = 0; i < f->f_stackdepth; i++) {
+ Py_XDECREF(f->f_valuestack[i]);
}
+ f->f_stackdepth = 0;
Py_XDECREF(f->f_back);
Py_DECREF(f->f_builtins);
@@ -593,19 +600,24 @@ frame_dealloc(PyFrameObject *f)
Py_CLEAR(f->f_locals);
Py_CLEAR(f->f_trace);
- co = f->f_code;
+ PyCodeObject *co = f->f_code;
if (co->co_zombieframe == NULL) {
co->co_zombieframe = f;
}
-#if PyFrame_MAXFREELIST > 0
- else if (numfree < PyFrame_MAXFREELIST) {
- ++numfree;
- f->f_back = free_list;
- free_list = f;
- }
-#endif
else {
- PyObject_GC_Del(f);
+ 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 {
+ PyObject_GC_Del(f);
+ }
}
Py_DECREF(co);
@@ -638,10 +650,8 @@ frame_traverse(PyFrameObject *f, visitproc visit, void *arg)
}
/* stack */
- if (f->f_stacktop != NULL) {
- for (PyObject **p = f->f_valuestack; p < f->f_stacktop; p++) {
- Py_VISIT(*p);
- }
+ for (int i = 0; i < f->f_stackdepth; i++) {
+ Py_VISIT(f->f_valuestack[i]);
}
return 0;
}
@@ -654,9 +664,7 @@ frame_tp_clear(PyFrameObject *f)
* frame may also point to this frame, believe itself to still be
* active, and try cleaning up this frame again.
*/
- PyObject **oldtop = f->f_stacktop;
- f->f_stacktop = NULL;
- f->f_executing = 0;
+ f->f_state = FRAME_CLEARED;
Py_CLEAR(f->f_trace);
@@ -667,18 +675,17 @@ frame_tp_clear(PyFrameObject *f)
}
/* stack */
- if (oldtop != NULL) {
- for (PyObject **p = f->f_valuestack; p < oldtop; p++) {
- Py_CLEAR(*p);
- }
+ for (int i = 0; i < f->f_stackdepth; i++) {
+ Py_CLEAR(f->f_valuestack[i]);
}
+ f->f_stackdepth = 0;
return 0;
}
static PyObject *
frame_clear(PyFrameObject *f, PyObject *Py_UNUSED(ignored))
{
- if (f->f_executing) {
+ if (_PyFrame_IsExecuting(f)) {
PyErr_SetString(PyExc_RuntimeError,
"cannot clear an executing frame");
return NULL;
@@ -770,9 +777,7 @@ _Py_IDENTIFIER(__builtins__);
static inline PyFrameObject*
frame_alloc(PyCodeObject *code)
{
- PyFrameObject *f;
-
- f = code->co_zombieframe;
+ PyFrameObject *f = code->co_zombieframe;
if (f != NULL) {
code->co_zombieframe = NULL;
_Py_NewReference((PyObject *)f);
@@ -783,21 +788,23 @@ frame_alloc(PyCodeObject *code)
Py_ssize_t ncells = PyTuple_GET_SIZE(code->co_cellvars);
Py_ssize_t nfrees = PyTuple_GET_SIZE(code->co_freevars);
Py_ssize_t extras = code->co_stacksize + code->co_nlocals + ncells + nfrees;
-#if PyFrame_MAXFREELIST > 0
- if (free_list == NULL)
-#endif
+ struct _Py_frame_state *state = get_frame_state();
+ if (state->free_list == NULL)
{
f = PyObject_GC_NewVar(PyFrameObject, &PyFrame_Type, extras);
if (f == NULL) {
return NULL;
}
}
-#if PyFrame_MAXFREELIST > 0
else {
- assert(numfree > 0);
- --numfree;
- f = free_list;
- free_list = free_list->f_back;
+#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;
if (Py_SIZE(f) < extras) {
PyFrameObject *new_f = PyObject_GC_Resize(PyFrameObject, f, extras);
if (new_f == NULL) {
@@ -808,132 +815,72 @@ frame_alloc(PyCodeObject *code)
}
_Py_NewReference((PyObject *)f);
}
-#endif
- f->f_code = code;
extras = code->co_nlocals + ncells + nfrees;
f->f_valuestack = f->f_localsplus + extras;
- for (Py_ssize_t i=0; i<extras; i++) {
+ for (Py_ssize_t i=0; i < extras; i++) {
f->f_localsplus[i] = NULL;
}
- f->f_locals = NULL;
- f->f_trace = NULL;
return f;
}
-static inline PyObject *
-frame_get_builtins(PyFrameObject *back, PyObject *globals)
-{
- PyObject *builtins;
-
- if (back != NULL && back->f_globals == globals) {
- /* If we share the globals, we share the builtins.
- Save a lookup and a call. */
- builtins = back->f_builtins;
- assert(builtins != NULL);
- Py_INCREF(builtins);
- return builtins;
- }
-
- builtins = _PyDict_GetItemIdWithError(globals, &PyId___builtins__);
- if (builtins != NULL && PyModule_Check(builtins)) {
- builtins = PyModule_GetDict(builtins);
- assert(builtins != NULL);
- }
- if (builtins != NULL) {
- Py_INCREF(builtins);
- return builtins;
- }
-
- if (PyErr_Occurred()) {
- return NULL;
- }
-
- /* No builtins! Make up a minimal one.
- Give them 'None', at least. */
- builtins = PyDict_New();
- if (builtins == NULL) {
- return NULL;
- }
- if (PyDict_SetItemString(builtins, "None", Py_None) < 0) {
- Py_DECREF(builtins);
- return NULL;
- }
- return builtins;
-}
-
-
PyFrameObject* _Py_HOT_FUNCTION
-_PyFrame_New_NoTrack(PyThreadState *tstate, PyCodeObject *code,
- PyObject *globals, PyObject *locals)
+_PyFrame_New_NoTrack(PyThreadState *tstate, PyFrameConstructor *con, PyObject *locals)
{
-#ifdef Py_DEBUG
- if (code == NULL || globals == NULL || !PyDict_Check(globals) ||
- (locals != NULL && !PyMapping_Check(locals))) {
- PyErr_BadInternalCall();
- return NULL;
- }
-#endif
-
- PyFrameObject *back = tstate->frame;
- PyObject *builtins = frame_get_builtins(back, globals);
- if (builtins == NULL) {
- return NULL;
- }
+ assert(con != NULL);
+ assert(con->fc_globals != NULL);
+ assert(con->fc_builtins != NULL);
+ assert(con->fc_code != NULL);
+ assert(locals == NULL || PyMapping_Check(locals));
- PyFrameObject *f = frame_alloc(code);
+ PyFrameObject *f = frame_alloc((PyCodeObject *)con->fc_code);
if (f == NULL) {
- Py_DECREF(builtins);
return NULL;
}
- f->f_stacktop = f->f_valuestack;
- f->f_builtins = builtins;
- Py_XINCREF(back);
- f->f_back = back;
- Py_INCREF(code);
- Py_INCREF(globals);
- f->f_globals = globals;
- /* Most functions have CO_NEWLOCALS and CO_OPTIMIZED set. */
- if ((code->co_flags & (CO_NEWLOCALS | CO_OPTIMIZED)) ==
- (CO_NEWLOCALS | CO_OPTIMIZED))
- ; /* f_locals = NULL; will be set by PyFrame_FastToLocals() */
- else if (code->co_flags & CO_NEWLOCALS) {
- locals = PyDict_New();
- if (locals == NULL) {
- Py_DECREF(f);
- return NULL;
- }
- f->f_locals = locals;
- }
- else {
- if (locals == NULL)
- locals = globals;
- Py_INCREF(locals);
- f->f_locals = locals;
- }
-
+ f->f_back = (PyFrameObject*)Py_XNewRef(tstate->frame);
+ f->f_code = (PyCodeObject *)Py_NewRef(con->fc_code);
+ f->f_builtins = Py_NewRef(con->fc_builtins);
+ f->f_globals = Py_NewRef(con->fc_globals);
+ f->f_locals = Py_XNewRef(locals);
+ // f_valuestack initialized by frame_alloc()
+ f->f_trace = NULL;
+ f->f_stackdepth = 0;
+ f->f_trace_lines = 1;
+ f->f_trace_opcodes = 0;
+ f->f_gen = NULL;
f->f_lasti = -1;
- f->f_lineno = code->co_firstlineno;
+ f->f_lineno = 0;
f->f_iblock = 0;
- f->f_executing = 0;
- f->f_gen = NULL;
- f->f_trace_opcodes = 0;
- f->f_trace_lines = 1;
-
- assert(f->f_code != NULL);
-
+ f->f_state = FRAME_CREATED;
+ // f_blockstack and f_localsplus initialized by frame_alloc()
return f;
}
+/* Legacy API */
PyFrameObject*
PyFrame_New(PyThreadState *tstate, PyCodeObject *code,
PyObject *globals, PyObject *locals)
{
- PyFrameObject *f = _PyFrame_New_NoTrack(tstate, code, globals, locals);
- if (f)
+ PyObject *builtins = _PyEval_BuiltinsFromGlobals(tstate, globals); // borrowed ref
+ if (builtins == NULL) {
+ return NULL;
+ }
+ PyFrameConstructor desc = {
+ .fc_globals = globals,
+ .fc_builtins = builtins,
+ .fc_name = code->co_name,
+ .fc_qualname = code->co_name,
+ .fc_code = (PyObject *)code,
+ .fc_defaults = NULL,
+ .fc_kwdefaults = NULL,
+ .fc_closure = NULL
+ };
+ PyFrameObject *f = _PyFrame_New_NoTrack(tstate, &desc, locals);
+ if (f) {
_PyObject_GC_TRACK(f);
+ }
return f;
}
@@ -1177,34 +1124,36 @@ PyFrame_LocalsToFast(PyFrameObject *f, int clear)
/* Clear out the free list */
void
-_PyFrame_ClearFreeList(void)
+_PyFrame_ClearFreeList(PyInterpreterState *interp)
{
-#if PyFrame_MAXFREELIST > 0
- while (free_list != NULL) {
- PyFrameObject *f = free_list;
- free_list = free_list->f_back;
+ 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);
- --numfree;
+ --state->numfree;
}
- assert(numfree == 0);
-#endif
+ assert(state->numfree == 0);
}
void
-_PyFrame_Fini(void)
+_PyFrame_Fini(PyInterpreterState *interp)
{
- _PyFrame_ClearFreeList();
+ _PyFrame_ClearFreeList(interp);
+#ifdef Py_DEBUG
+ 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",
- numfree, sizeof(PyFrameObject));
-#endif
+ state->numfree, sizeof(PyFrameObject));
}
@@ -1227,3 +1176,21 @@ PyFrame_GetBack(PyFrameObject *frame)
Py_XINCREF(back);
return back;
}
+
+PyObject*
+_PyEval_BuiltinsFromGlobals(PyThreadState *tstate, PyObject *globals)
+{
+ PyObject *builtins = _PyDict_GetItemIdWithError(globals, &PyId___builtins__);
+ if (builtins) {
+ if (PyModule_Check(builtins)) {
+ builtins = _PyModule_GetDict(builtins);
+ assert(builtins != NULL);
+ }
+ return builtins;
+ }
+ if (PyErr_Occurred()) {
+ return NULL;
+ }
+
+ return _PyEval_GetBuiltins(tstate);
+}