aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/tools/python3/src/Objects/frameobject.c
diff options
context:
space:
mode:
authororivej <orivej@yandex-team.ru>2022-02-10 16:45:01 +0300
committerDaniil Cherednik <dcherednik@yandex-team.ru>2022-02-10 16:45:01 +0300
commit2d37894b1b037cf24231090eda8589bbb44fb6fc (patch)
treebe835aa92c6248212e705f25388ebafcf84bc7a1 /contrib/tools/python3/src/Objects/frameobject.c
parent718c552901d703c502ccbefdfc3c9028d608b947 (diff)
downloadydb-2d37894b1b037cf24231090eda8589bbb44fb6fc.tar.gz
Restoring authorship annotation for <orivej@yandex-team.ru>. Commit 2 of 2.
Diffstat (limited to 'contrib/tools/python3/src/Objects/frameobject.c')
-rw-r--r--contrib/tools/python3/src/Objects/frameobject.c1406
1 files changed, 703 insertions, 703 deletions
diff --git a/contrib/tools/python3/src/Objects/frameobject.c b/contrib/tools/python3/src/Objects/frameobject.c
index acc715d08b..4ae17bcfc2 100644
--- a/contrib/tools/python3/src/Objects/frameobject.c
+++ b/contrib/tools/python3/src/Objects/frameobject.c
@@ -1,54 +1,54 @@
-/* Frame object implementation */
-
-#include "Python.h"
+/* Frame object implementation */
+
+#include "Python.h"
#include "pycore_object.h"
#include "pycore_gc.h" // _PyObject_GC_IS_TRACKED()
-
-#include "code.h"
-#include "frameobject.h"
-#include "opcode.h"
+
+#include "code.h"
+#include "frameobject.h"
+#include "opcode.h"
#include "structmember.h" // PyMemberDef
-
-#define OFF(x) offsetof(PyFrameObject, x)
-
-static PyMemberDef frame_memberlist[] = {
- {"f_back", T_OBJECT, OFF(f_back), READONLY},
+
+#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_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 PyObject *
-frame_getlocals(PyFrameObject *f, void *closure)
-{
- if (PyFrame_FastToLocalsWithError(f) < 0)
- return NULL;
- Py_INCREF(f->f_locals);
- return f->f_locals;
-}
-
-int
-PyFrame_GetLineNumber(PyFrameObject *f)
-{
+ {"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 PyObject *
+frame_getlocals(PyFrameObject *f, void *closure)
+{
+ if (PyFrame_FastToLocalsWithError(f) < 0)
+ return NULL;
+ Py_INCREF(f->f_locals);
+ return f->f_locals;
+}
+
+int
+PyFrame_GetLineNumber(PyFrameObject *f)
+{
assert(f != NULL);
if (f->f_trace) {
- return f->f_lineno;
+ return f->f_lineno;
}
else {
- return PyCode_Addr2Line(f->f_code, f->f_lasti);
+ return PyCode_Addr2Line(f->f_code, f->f_lasti);
}
-}
-
-static PyObject *
-frame_getlineno(PyFrameObject *f, void *closure)
-{
- return PyLong_FromLong(PyFrame_GetLineNumber(f));
-}
-
+}
+
+static PyObject *
+frame_getlineno(PyFrameObject *f, void *closure)
+{
+ return PyLong_FromLong(PyFrame_GetLineNumber(f));
+}
+
/* Given the index of the effective opcode,
scan back to construct the oparg with EXTENDED_ARG */
@@ -309,117 +309,117 @@ frame_block_unwind(PyFrameObject *f)
}
-/* Setter for f_lineno - you can set f_lineno from within a trace function in
- * order to jump to a given line of code, subject to some restrictions. Most
- * lines are OK to jump to because they don't make any assumptions about the
- * state of the stack (obvious because you could remove the line and the code
- * would still work without any stack errors), but there are some constructs
- * that limit jumping:
- *
- * o Lines with an 'except' statement on them can't be jumped to, because
- * they expect an exception to be on the top of the stack.
- * o Lines that live in a 'finally' block can't be jumped from or to, since
+/* Setter for f_lineno - you can set f_lineno from within a trace function in
+ * order to jump to a given line of code, subject to some restrictions. Most
+ * lines are OK to jump to because they don't make any assumptions about the
+ * state of the stack (obvious because you could remove the line and the code
+ * would still work without any stack errors), but there are some constructs
+ * that limit jumping:
+ *
+ * o Lines with an 'except' statement on them can't be jumped to, because
+ * they expect an exception to be on the top of the stack.
+ * o Lines that live in a 'finally' block can't be jumped from or to, since
* we cannot be sure which state the interpreter was in or would be in
* during execution of the finally block.
* o 'try', 'with' and 'async with' blocks can't be jumped into because
* the blockstack needs to be set up before their code runs.
* o 'for' and 'async for' loops can't be jumped into because the
- * iterator needs to be on the stack.
- * o Jumps cannot be made from within a trace function invoked with a
- * 'return' or 'exception' event since the eval loop has been exited at
- * that time.
- */
-static int
-frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignored))
-{
- if (p_new_lineno == NULL) {
- PyErr_SetString(PyExc_AttributeError, "cannot delete attribute");
- return -1;
- }
- /* f_lineno must be an integer. */
- if (!PyLong_CheckExact(p_new_lineno)) {
- PyErr_SetString(PyExc_ValueError,
- "lineno must be an integer");
- 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,
- "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,
- "can only jump from a 'line' trace event");
- return -1;
- }
-
+ * iterator needs to be on the stack.
+ * o Jumps cannot be made from within a trace function invoked with a
+ * 'return' or 'exception' event since the eval loop has been exited at
+ * that time.
+ */
+static int
+frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignored))
+{
+ if (p_new_lineno == NULL) {
+ PyErr_SetString(PyExc_AttributeError, "cannot delete attribute");
+ return -1;
+ }
+ /* f_lineno must be an integer. */
+ if (!PyLong_CheckExact(p_new_lineno)) {
+ PyErr_SetString(PyExc_ValueError,
+ "lineno must be an integer");
+ 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,
+ "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,
+ "can only jump from a 'line' trace event");
+ return -1;
+ }
+
int new_lineno;
/* Fail if the line falls outside the code block and
select first line with actual code. */
int overflow;
long l_new_lineno = PyLong_AsLongAndOverflow(p_new_lineno, &overflow);
- if (overflow
-#if SIZEOF_LONG > SIZEOF_INT
- || l_new_lineno > INT_MAX
- || l_new_lineno < INT_MIN
-#endif
+ if (overflow
+#if SIZEOF_LONG > SIZEOF_INT
+ || l_new_lineno > INT_MAX
+ || l_new_lineno < INT_MIN
+#endif
) {
- PyErr_SetString(PyExc_ValueError,
- "lineno out of range");
- return -1;
- }
- new_lineno = (int)l_new_lineno;
-
- if (new_lineno < f->f_code->co_firstlineno) {
- PyErr_Format(PyExc_ValueError,
+ PyErr_SetString(PyExc_ValueError,
+ "lineno out of range");
+ return -1;
+ }
+ new_lineno = (int)l_new_lineno;
+
+ if (new_lineno < f->f_code->co_firstlineno) {
+ PyErr_Format(PyExc_ValueError,
"line %d comes before the current code block",
new_lineno);
- return -1;
- }
-
+ return -1;
+ }
+
/* PyCode_NewWithPosOnlyArgs limits co_code to be under INT_MAX so this
* should never overflow. */
int len = (int)(PyBytes_GET_SIZE(f->f_code->co_code) / sizeof(_Py_CODEUNIT));
int *lines = marklines(f->f_code, len);
if (lines == NULL) {
- return -1;
- }
-
+ return -1;
+ }
+
new_lineno = first_line_not_before(lines, len, new_lineno);
if (new_lineno < 0) {
PyErr_Format(PyExc_ValueError,
"line %d comes after the current code block",
(int)l_new_lineno);
PyMem_Free(lines);
- return -1;
- }
-
+ return -1;
+ }
+
int64_t *blocks = markblocks(f->f_code, len);
if (blocks == NULL) {
PyMem_Free(lines);
- return -1;
- }
-
+ return -1;
+ }
+
int64_t target_block_stack = -1;
int64_t best_block_stack = -1;
int best_addr = -1;
@@ -434,16 +434,16 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore
best_block_stack = target_block_stack;
best_addr = i*sizeof(_Py_CODEUNIT);
}
- }
+ }
else if (msg) {
if (target_block_stack >= 0) {
msg = explain_incompatible_block_stack(target_block_stack);
- }
+ }
else {
msg = "code may be unreachable.";
}
- }
- }
+ }
+ }
}
PyMem_Free(blocks);
PyMem_Free(lines);
@@ -451,7 +451,7 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore
PyErr_SetString(PyExc_ValueError, msg);
return -1;
}
-
+
/* Unwind block stack. */
while (start_block_stack > best_block_stack) {
Kind kind = top_block(start_block_stack);
@@ -471,147 +471,147 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore
PyErr_SetString(PyExc_ValueError,
"can't jump out of an 'except' block");
return -1;
- }
+ }
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_lineno and f_lasti and return OK. */
+ f->f_lineno = new_lineno;
f->f_lasti = best_addr;
- return 0;
-}
-
-static PyObject *
-frame_gettrace(PyFrameObject *f, void *closure)
-{
- PyObject* trace = f->f_trace;
-
- if (trace == NULL)
- trace = Py_None;
-
- Py_INCREF(trace);
-
- return trace;
-}
-
-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)
- v = NULL;
- Py_XINCREF(v);
- Py_XSETREF(f->f_trace, v);
-
- return 0;
-}
-
-
-static PyGetSetDef frame_getsetlist[] = {
- {"f_locals", (getter)frame_getlocals, NULL, NULL},
- {"f_lineno", (getter)frame_getlineno,
- (setter)frame_setlineno, NULL},
- {"f_trace", (getter)frame_gettrace, (setter)frame_settrace, NULL},
- {0}
-};
-
-/* Stack frames are allocated and deallocated at a considerable rate.
- In an attempt to improve the speed of function calls, we:
-
- 1. Hold a single "zombie" frame on each code object. This retains
- the allocated and initialised frame object from an invocation of
- the code object. The zombie is reanimated the next time we need a
- frame object for that code object. Doing this saves the malloc/
- realloc required when using a free_list frame that isn't the
- correct size. It also saves some field initialisation.
-
- In zombie mode, no field of PyFrameObject holds a reference, but
- the following fields are still valid:
-
- * ob_type, ob_size, f_code, f_valuestack;
-
- * f_locals, f_trace are NULL;
-
- * f_localsplus does not require re-allocation and
- the local variables in f_localsplus are NULL.
-
- 2. We also maintain a separate free list of stack frames (just like
- floats are allocated in a special way -- see floatobject.c). When
- a stack frame is on the free list, only the following members have
- a meaning:
- ob_type == &Frametype
- f_back next item on free list, or NULL
- f_stacksize size of value stack
- ob_size size of localsplus
- Note that the value and block stacks are preserved -- this can save
- another malloc() call or two (and two free() calls as well!).
- Also note that, unlike for integers, each frame object is a
- malloc'ed object in its own right -- it is only the actual calls to
- malloc() that we are trying to save here, not the administration.
- After all, while a typical program may make millions of calls, a
- call depth of more than 20 or 30 is probably already exceptional
- unless the program contains run-away recursion. I hope.
-
- Later, PyFrame_MAXFREELIST was added to bound the # of frames saved on
- free_list. Else programs creating lots of cyclic trash involving
- frames could provoke free_list into growing without bound.
-*/
+ return 0;
+}
+
+static PyObject *
+frame_gettrace(PyFrameObject *f, void *closure)
+{
+ PyObject* trace = f->f_trace;
+
+ if (trace == NULL)
+ trace = Py_None;
+
+ Py_INCREF(trace);
+
+ return trace;
+}
+
+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)
+ v = NULL;
+ Py_XINCREF(v);
+ Py_XSETREF(f->f_trace, v);
+
+ return 0;
+}
+
+
+static PyGetSetDef frame_getsetlist[] = {
+ {"f_locals", (getter)frame_getlocals, NULL, NULL},
+ {"f_lineno", (getter)frame_getlineno,
+ (setter)frame_setlineno, NULL},
+ {"f_trace", (getter)frame_gettrace, (setter)frame_settrace, NULL},
+ {0}
+};
+
+/* Stack frames are allocated and deallocated at a considerable rate.
+ In an attempt to improve the speed of function calls, we:
+
+ 1. Hold a single "zombie" frame on each code object. This retains
+ the allocated and initialised frame object from an invocation of
+ the code object. The zombie is reanimated the next time we need a
+ frame object for that code object. Doing this saves the malloc/
+ realloc required when using a free_list frame that isn't the
+ correct size. It also saves some field initialisation.
+
+ In zombie mode, no field of PyFrameObject holds a reference, but
+ the following fields are still valid:
+
+ * ob_type, ob_size, f_code, f_valuestack;
+
+ * f_locals, f_trace are NULL;
+
+ * f_localsplus does not require re-allocation and
+ the local variables in f_localsplus are NULL.
+
+ 2. We also maintain a separate free list of stack frames (just like
+ floats are allocated in a special way -- see floatobject.c). When
+ a stack frame is on the free list, only the following members have
+ a meaning:
+ ob_type == &Frametype
+ f_back next item on free list, or NULL
+ f_stacksize size of value stack
+ ob_size size of localsplus
+ Note that the value and block stacks are preserved -- this can save
+ another malloc() call or two (and two free() calls as well!).
+ Also note that, unlike for integers, each frame object is a
+ malloc'ed object in its own right -- it is only the actual calls to
+ malloc() that we are trying to save here, not the administration.
+ After all, while a typical program may make millions of calls, a
+ call depth of more than 20 or 30 is probably already exceptional
+ unless the program contains run-away recursion. I hope.
+
+ Later, PyFrame_MAXFREELIST was added to bound the # of frames saved on
+ free_list. Else programs creating lots of cyclic trash involving
+ frames could provoke free_list into growing without bound.
+*/
/* 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 */
+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))
- _PyObject_GC_UNTRACK(f);
-
+
+static void _Py_HOT_FUNCTION
+frame_dealloc(PyFrameObject *f)
+{
+ PyObject **p, **valuestack;
+ PyCodeObject *co;
+
+ 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++)
- Py_CLEAR(*p);
-
- /* Free stack */
- if (f->f_stacktop != NULL) {
- for (p = valuestack; p < f->f_stacktop; p++)
- Py_XDECREF(*p);
- }
-
- Py_XDECREF(f->f_back);
- Py_DECREF(f->f_builtins);
- Py_DECREF(f->f_globals);
- Py_CLEAR(f->f_locals);
- Py_CLEAR(f->f_trace);
-
- co = f->f_code;
+ /* Kill all local variables */
+ valuestack = f->f_valuestack;
+ for (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);
+ }
+
+ Py_XDECREF(f->f_back);
+ Py_DECREF(f->f_builtins);
+ Py_DECREF(f->f_globals);
+ Py_CLEAR(f->f_locals);
+ Py_CLEAR(f->f_trace);
+
+ co = f->f_code;
if (co->co_zombieframe == NULL) {
- co->co_zombieframe = f;
+ co->co_zombieframe = f;
}
#if PyFrame_MAXFREELIST > 0
- else if (numfree < PyFrame_MAXFREELIST) {
- ++numfree;
- f->f_back = free_list;
- free_list = f;
- }
+ else if (numfree < PyFrame_MAXFREELIST) {
+ ++numfree;
+ f->f_back = free_list;
+ free_list = f;
+ }
#endif
else {
- PyObject_GC_Del(f);
+ PyObject_GC_Del(f);
}
-
- Py_DECREF(co);
+
+ Py_DECREF(co);
Py_TRASHCAN_END;
-}
-
+}
+
static inline Py_ssize_t
frame_nslots(PyFrameObject *frame)
{
@@ -621,176 +621,176 @@ frame_nslots(PyFrameObject *frame)
+ PyTuple_GET_SIZE(code->co_freevars));
}
-static int
-frame_traverse(PyFrameObject *f, visitproc visit, void *arg)
-{
- Py_VISIT(f->f_back);
- Py_VISIT(f->f_code);
- Py_VISIT(f->f_builtins);
- Py_VISIT(f->f_globals);
- Py_VISIT(f->f_locals);
- Py_VISIT(f->f_trace);
-
- /* locals */
+static int
+frame_traverse(PyFrameObject *f, visitproc visit, void *arg)
+{
+ Py_VISIT(f->f_back);
+ Py_VISIT(f->f_code);
+ Py_VISIT(f->f_builtins);
+ Py_VISIT(f->f_globals);
+ Py_VISIT(f->f_locals);
+ Py_VISIT(f->f_trace);
+
+ /* locals */
PyObject **fastlocals = f->f_localsplus;
for (Py_ssize_t i = frame_nslots(f); --i >= 0; ++fastlocals) {
- Py_VISIT(*fastlocals);
+ Py_VISIT(*fastlocals);
}
-
- /* stack */
- if (f->f_stacktop != NULL) {
+
+ /* stack */
+ if (f->f_stacktop != NULL) {
for (PyObject **p = f->f_valuestack; p < f->f_stacktop; p++) {
- Py_VISIT(*p);
+ Py_VISIT(*p);
}
- }
- return 0;
-}
-
-static int
-frame_tp_clear(PyFrameObject *f)
-{
- /* Before anything else, make sure that this frame is clearly marked
- * as being defunct! Else, e.g., a generator reachable from this
- * frame may also point to this frame, believe itself to still be
- * active, and try cleaning up this frame again.
- */
+ }
+ return 0;
+}
+
+static int
+frame_tp_clear(PyFrameObject *f)
+{
+ /* Before anything else, make sure that this frame is clearly marked
+ * as being defunct! Else, e.g., a generator reachable from this
+ * 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;
-
- Py_CLEAR(f->f_trace);
-
- /* locals */
+ f->f_stacktop = NULL;
+ f->f_executing = 0;
+
+ Py_CLEAR(f->f_trace);
+
+ /* locals */
PyObject **fastlocals = f->f_localsplus;
for (Py_ssize_t i = frame_nslots(f); --i >= 0; ++fastlocals) {
- Py_CLEAR(*fastlocals);
+ Py_CLEAR(*fastlocals);
}
-
- /* stack */
- if (oldtop != NULL) {
+
+ /* stack */
+ if (oldtop != NULL) {
for (PyObject **p = f->f_valuestack; p < oldtop; p++) {
- Py_CLEAR(*p);
+ Py_CLEAR(*p);
}
- }
- return 0;
-}
-
-static PyObject *
+ }
+ return 0;
+}
+
+static PyObject *
frame_clear(PyFrameObject *f, PyObject *Py_UNUSED(ignored))
-{
- if (f->f_executing) {
- PyErr_SetString(PyExc_RuntimeError,
- "cannot clear an executing frame");
- return NULL;
- }
- if (f->f_gen) {
- _PyGen_Finalize(f->f_gen);
- assert(f->f_gen == NULL);
- }
- (void)frame_tp_clear(f);
- Py_RETURN_NONE;
-}
-
-PyDoc_STRVAR(clear__doc__,
-"F.clear(): clear most references held by the frame");
-
-static PyObject *
+{
+ if (f->f_executing) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "cannot clear an executing frame");
+ return NULL;
+ }
+ if (f->f_gen) {
+ _PyGen_Finalize(f->f_gen);
+ assert(f->f_gen == NULL);
+ }
+ (void)frame_tp_clear(f);
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(clear__doc__,
+"F.clear(): clear most references held by the frame");
+
+static PyObject *
frame_sizeof(PyFrameObject *f, PyObject *Py_UNUSED(ignored))
-{
- Py_ssize_t res, extras, ncells, nfrees;
-
+{
+ Py_ssize_t res, extras, ncells, nfrees;
+
PyCodeObject *code = f->f_code;
ncells = PyTuple_GET_SIZE(code->co_cellvars);
nfrees = PyTuple_GET_SIZE(code->co_freevars);
extras = code->co_stacksize + code->co_nlocals + ncells + nfrees;
- /* subtract one as it is already included in PyFrameObject */
- res = sizeof(PyFrameObject) + (extras-1) * sizeof(PyObject *);
-
- return PyLong_FromSsize_t(res);
-}
-
-PyDoc_STRVAR(sizeof__doc__,
-"F.__sizeof__() -> size of F in memory, in bytes");
-
-static PyObject *
-frame_repr(PyFrameObject *f)
-{
- int lineno = PyFrame_GetLineNumber(f);
+ /* subtract one as it is already included in PyFrameObject */
+ res = sizeof(PyFrameObject) + (extras-1) * sizeof(PyObject *);
+
+ return PyLong_FromSsize_t(res);
+}
+
+PyDoc_STRVAR(sizeof__doc__,
+"F.__sizeof__() -> size of F in memory, in bytes");
+
+static PyObject *
+frame_repr(PyFrameObject *f)
+{
+ int lineno = PyFrame_GetLineNumber(f);
PyCodeObject *code = f->f_code;
- return PyUnicode_FromFormat(
- "<frame at %p, file %R, line %d, code %S>",
+ return PyUnicode_FromFormat(
+ "<frame at %p, file %R, line %d, code %S>",
f, code->co_filename, lineno, code->co_name);
-}
-
-static PyMethodDef frame_methods[] = {
- {"clear", (PyCFunction)frame_clear, METH_NOARGS,
- clear__doc__},
- {"__sizeof__", (PyCFunction)frame_sizeof, METH_NOARGS,
- sizeof__doc__},
- {NULL, NULL} /* sentinel */
-};
-
-PyTypeObject PyFrame_Type = {
- PyVarObject_HEAD_INIT(&PyType_Type, 0)
- "frame",
- sizeof(PyFrameObject),
- sizeof(PyObject *),
- (destructor)frame_dealloc, /* tp_dealloc */
+}
+
+static PyMethodDef frame_methods[] = {
+ {"clear", (PyCFunction)frame_clear, METH_NOARGS,
+ clear__doc__},
+ {"__sizeof__", (PyCFunction)frame_sizeof, METH_NOARGS,
+ sizeof__doc__},
+ {NULL, NULL} /* sentinel */
+};
+
+PyTypeObject PyFrame_Type = {
+ PyVarObject_HEAD_INIT(&PyType_Type, 0)
+ "frame",
+ sizeof(PyFrameObject),
+ sizeof(PyObject *),
+ (destructor)frame_dealloc, /* tp_dealloc */
0, /* tp_vectorcall_offset */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
0, /* tp_as_async */
- (reprfunc)frame_repr, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- PyObject_GenericGetAttr, /* tp_getattro */
- PyObject_GenericSetAttr, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
- 0, /* tp_doc */
- (traverseproc)frame_traverse, /* tp_traverse */
- (inquiry)frame_tp_clear, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- frame_methods, /* tp_methods */
- frame_memberlist, /* tp_members */
- frame_getsetlist, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
-};
-
-_Py_IDENTIFIER(__builtins__);
-
+ (reprfunc)frame_repr, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ PyObject_GenericGetAttr, /* tp_getattro */
+ PyObject_GenericSetAttr, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
+ 0, /* tp_doc */
+ (traverseproc)frame_traverse, /* tp_traverse */
+ (inquiry)frame_tp_clear, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ frame_methods, /* tp_methods */
+ frame_memberlist, /* tp_members */
+ frame_getsetlist, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+};
+
+_Py_IDENTIFIER(__builtins__);
+
static inline PyFrameObject*
frame_alloc(PyCodeObject *code)
-{
- PyFrameObject *f;
-
+{
+ PyFrameObject *f;
+
f = code->co_zombieframe;
if (f != NULL) {
code->co_zombieframe = NULL;
_Py_NewReference((PyObject *)f);
assert(f->f_code == code);
return f;
- }
+ }
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
+#endif
{
f = PyObject_GC_NewVar(PyFrameObject, &PyFrame_Type, extras);
if (f == NULL) {
return NULL;
- }
+ }
}
#if PyFrame_MAXFREELIST > 0
else {
@@ -805,17 +805,17 @@ frame_alloc(PyCodeObject *code)
return NULL;
}
f = new_f;
- }
+ }
_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++) {
f->f_localsplus[i] = NULL;
- }
+ }
f->f_locals = NULL;
f->f_trace = NULL;
return f;
@@ -828,27 +828,27 @@ 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);
+ /* 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. */
@@ -888,325 +888,325 @@ _PyFrame_New_NoTrack(PyThreadState *tstate, PyCodeObject *code,
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_lasti = -1;
- f->f_lineno = code->co_firstlineno;
- f->f_iblock = 0;
- f->f_executing = 0;
- f->f_gen = NULL;
- f->f_trace_opcodes = 0;
- f->f_trace_lines = 1;
-
+ 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_lasti = -1;
+ f->f_lineno = code->co_firstlineno;
+ 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);
- 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
-PyFrame_BlockSetup(PyFrameObject *f, int type, int handler, int level)
-{
- PyTryBlock *b;
+ 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
+PyFrame_BlockSetup(PyFrameObject *f, int type, int handler, int level)
+{
+ PyTryBlock *b;
if (f->f_iblock >= CO_MAXBLOCKS) {
Py_FatalError("block stack overflow");
}
- b = &f->f_blockstack[f->f_iblock++];
- b->b_type = type;
- b->b_level = level;
- b->b_handler = handler;
-}
-
-PyTryBlock *
-PyFrame_BlockPop(PyFrameObject *f)
-{
- PyTryBlock *b;
+ b = &f->f_blockstack[f->f_iblock++];
+ b->b_type = type;
+ b->b_level = level;
+ b->b_handler = handler;
+}
+
+PyTryBlock *
+PyFrame_BlockPop(PyFrameObject *f)
+{
+ PyTryBlock *b;
if (f->f_iblock <= 0) {
Py_FatalError("block stack underflow");
}
- b = &f->f_blockstack[--f->f_iblock];
- return b;
-}
-
-/* Convert between "fast" version of locals and dictionary version.
-
- map and values are input arguments. map is a tuple of strings.
- values is an array of PyObject*. At index i, map[i] is the name of
- the variable with value values[i]. The function copies the first
- nmap variable from map/values into dict. If values[i] is NULL,
- the variable is deleted from dict.
-
- If deref is true, then the values being copied are cell variables
- and the value is extracted from the cell variable before being put
- in dict.
- */
-
-static int
-map_to_dict(PyObject *map, Py_ssize_t nmap, PyObject *dict, PyObject **values,
- int deref)
-{
- Py_ssize_t j;
- assert(PyTuple_Check(map));
- assert(PyDict_Check(dict));
- assert(PyTuple_Size(map) >= nmap);
- for (j=0; j < nmap; j++) {
- PyObject *key = PyTuple_GET_ITEM(map, j);
- PyObject *value = values[j];
- assert(PyUnicode_Check(key));
- if (deref && value != NULL) {
- assert(PyCell_Check(value));
- value = PyCell_GET(value);
- }
- if (value == NULL) {
- if (PyObject_DelItem(dict, key) != 0) {
- if (PyErr_ExceptionMatches(PyExc_KeyError))
- PyErr_Clear();
- else
- return -1;
- }
- }
- else {
- if (PyObject_SetItem(dict, key, value) != 0)
- return -1;
- }
- }
- return 0;
-}
-
-/* Copy values from the "locals" dict into the fast locals.
-
- dict is an input argument containing string keys representing
- variables names and arbitrary PyObject* as values.
-
- map and values are input arguments. map is a tuple of strings.
- values is an array of PyObject*. At index i, map[i] is the name of
- the variable with value values[i]. The function copies the first
- nmap variable from map/values into dict. If values[i] is NULL,
- the variable is deleted from dict.
-
- If deref is true, then the values being copied are cell variables
- and the value is extracted from the cell variable before being put
- in dict. If clear is true, then variables in map but not in dict
- are set to NULL in map; if clear is false, variables missing in
- dict are ignored.
-
- Exceptions raised while modifying the dict are silently ignored,
- because there is no good way to report them.
-*/
-
-static void
-dict_to_map(PyObject *map, Py_ssize_t nmap, PyObject *dict, PyObject **values,
- int deref, int clear)
-{
- Py_ssize_t j;
- assert(PyTuple_Check(map));
- assert(PyDict_Check(dict));
- assert(PyTuple_Size(map) >= nmap);
- for (j=0; j < nmap; j++) {
- PyObject *key = PyTuple_GET_ITEM(map, j);
- PyObject *value = PyObject_GetItem(dict, key);
- assert(PyUnicode_Check(key));
- /* We only care about NULLs if clear is true. */
- if (value == NULL) {
- PyErr_Clear();
- if (!clear)
- continue;
- }
- if (deref) {
- assert(PyCell_Check(values[j]));
- if (PyCell_GET(values[j]) != value) {
- if (PyCell_Set(values[j], value) < 0)
- PyErr_Clear();
- }
- } else if (values[j] != value) {
- Py_XINCREF(value);
- Py_XSETREF(values[j], value);
- }
- Py_XDECREF(value);
- }
-}
-
-int
-PyFrame_FastToLocalsWithError(PyFrameObject *f)
-{
- /* Merge fast locals into f->f_locals */
- PyObject *locals, *map;
- PyObject **fast;
- PyCodeObject *co;
- Py_ssize_t j;
- Py_ssize_t ncells, nfreevars;
-
- if (f == NULL) {
- PyErr_BadInternalCall();
- return -1;
- }
- locals = f->f_locals;
- if (locals == NULL) {
- locals = f->f_locals = PyDict_New();
- if (locals == NULL)
- return -1;
- }
- co = f->f_code;
- map = co->co_varnames;
- if (!PyTuple_Check(map)) {
- PyErr_Format(PyExc_SystemError,
- "co_varnames must be a tuple, not %s",
- Py_TYPE(map)->tp_name);
- return -1;
- }
- fast = f->f_localsplus;
- j = PyTuple_GET_SIZE(map);
- if (j > co->co_nlocals)
- j = co->co_nlocals;
- if (co->co_nlocals) {
- if (map_to_dict(map, j, locals, fast, 0) < 0)
- return -1;
- }
- ncells = PyTuple_GET_SIZE(co->co_cellvars);
- nfreevars = PyTuple_GET_SIZE(co->co_freevars);
- if (ncells || nfreevars) {
- if (map_to_dict(co->co_cellvars, ncells,
- locals, fast + co->co_nlocals, 1))
- return -1;
-
- /* If the namespace is unoptimized, then one of the
- following cases applies:
- 1. It does not contain free variables, because it
- uses import * or is a top-level namespace.
- 2. It is a class namespace.
- We don't want to accidentally copy free variables
- into the locals dict used by the class.
- */
- if (co->co_flags & CO_OPTIMIZED) {
- if (map_to_dict(co->co_freevars, nfreevars,
- locals, fast + co->co_nlocals + ncells, 1) < 0)
- return -1;
- }
- }
- return 0;
-}
-
-void
-PyFrame_FastToLocals(PyFrameObject *f)
-{
- int res;
-
- assert(!PyErr_Occurred());
-
- res = PyFrame_FastToLocalsWithError(f);
- if (res < 0)
- PyErr_Clear();
-}
-
-void
-PyFrame_LocalsToFast(PyFrameObject *f, int clear)
-{
- /* Merge f->f_locals into fast locals */
- PyObject *locals, *map;
- PyObject **fast;
- PyObject *error_type, *error_value, *error_traceback;
- PyCodeObject *co;
- Py_ssize_t j;
- Py_ssize_t ncells, nfreevars;
- if (f == NULL)
- return;
- locals = f->f_locals;
- co = f->f_code;
- map = co->co_varnames;
- if (locals == NULL)
- return;
- if (!PyTuple_Check(map))
- return;
- PyErr_Fetch(&error_type, &error_value, &error_traceback);
- fast = f->f_localsplus;
- j = PyTuple_GET_SIZE(map);
- if (j > co->co_nlocals)
- j = co->co_nlocals;
- if (co->co_nlocals)
- dict_to_map(co->co_varnames, j, locals, fast, 0, clear);
- ncells = PyTuple_GET_SIZE(co->co_cellvars);
- nfreevars = PyTuple_GET_SIZE(co->co_freevars);
- if (ncells || nfreevars) {
- dict_to_map(co->co_cellvars, ncells,
- locals, fast + co->co_nlocals, 1, clear);
- /* Same test as in PyFrame_FastToLocals() above. */
- if (co->co_flags & CO_OPTIMIZED) {
- dict_to_map(co->co_freevars, nfreevars,
- locals, fast + co->co_nlocals + ncells, 1,
- clear);
- }
- }
- PyErr_Restore(error_type, error_value, error_traceback);
-}
-
-/* Clear out the free list */
+ b = &f->f_blockstack[--f->f_iblock];
+ return b;
+}
+
+/* Convert between "fast" version of locals and dictionary version.
+
+ map and values are input arguments. map is a tuple of strings.
+ values is an array of PyObject*. At index i, map[i] is the name of
+ the variable with value values[i]. The function copies the first
+ nmap variable from map/values into dict. If values[i] is NULL,
+ the variable is deleted from dict.
+
+ If deref is true, then the values being copied are cell variables
+ and the value is extracted from the cell variable before being put
+ in dict.
+ */
+
+static int
+map_to_dict(PyObject *map, Py_ssize_t nmap, PyObject *dict, PyObject **values,
+ int deref)
+{
+ Py_ssize_t j;
+ assert(PyTuple_Check(map));
+ assert(PyDict_Check(dict));
+ assert(PyTuple_Size(map) >= nmap);
+ for (j=0; j < nmap; j++) {
+ PyObject *key = PyTuple_GET_ITEM(map, j);
+ PyObject *value = values[j];
+ assert(PyUnicode_Check(key));
+ if (deref && value != NULL) {
+ assert(PyCell_Check(value));
+ value = PyCell_GET(value);
+ }
+ if (value == NULL) {
+ if (PyObject_DelItem(dict, key) != 0) {
+ if (PyErr_ExceptionMatches(PyExc_KeyError))
+ PyErr_Clear();
+ else
+ return -1;
+ }
+ }
+ else {
+ if (PyObject_SetItem(dict, key, value) != 0)
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/* Copy values from the "locals" dict into the fast locals.
+
+ dict is an input argument containing string keys representing
+ variables names and arbitrary PyObject* as values.
+
+ map and values are input arguments. map is a tuple of strings.
+ values is an array of PyObject*. At index i, map[i] is the name of
+ the variable with value values[i]. The function copies the first
+ nmap variable from map/values into dict. If values[i] is NULL,
+ the variable is deleted from dict.
+
+ If deref is true, then the values being copied are cell variables
+ and the value is extracted from the cell variable before being put
+ in dict. If clear is true, then variables in map but not in dict
+ are set to NULL in map; if clear is false, variables missing in
+ dict are ignored.
+
+ Exceptions raised while modifying the dict are silently ignored,
+ because there is no good way to report them.
+*/
+
+static void
+dict_to_map(PyObject *map, Py_ssize_t nmap, PyObject *dict, PyObject **values,
+ int deref, int clear)
+{
+ Py_ssize_t j;
+ assert(PyTuple_Check(map));
+ assert(PyDict_Check(dict));
+ assert(PyTuple_Size(map) >= nmap);
+ for (j=0; j < nmap; j++) {
+ PyObject *key = PyTuple_GET_ITEM(map, j);
+ PyObject *value = PyObject_GetItem(dict, key);
+ assert(PyUnicode_Check(key));
+ /* We only care about NULLs if clear is true. */
+ if (value == NULL) {
+ PyErr_Clear();
+ if (!clear)
+ continue;
+ }
+ if (deref) {
+ assert(PyCell_Check(values[j]));
+ if (PyCell_GET(values[j]) != value) {
+ if (PyCell_Set(values[j], value) < 0)
+ PyErr_Clear();
+ }
+ } else if (values[j] != value) {
+ Py_XINCREF(value);
+ Py_XSETREF(values[j], value);
+ }
+ Py_XDECREF(value);
+ }
+}
+
+int
+PyFrame_FastToLocalsWithError(PyFrameObject *f)
+{
+ /* Merge fast locals into f->f_locals */
+ PyObject *locals, *map;
+ PyObject **fast;
+ PyCodeObject *co;
+ Py_ssize_t j;
+ Py_ssize_t ncells, nfreevars;
+
+ if (f == NULL) {
+ PyErr_BadInternalCall();
+ return -1;
+ }
+ locals = f->f_locals;
+ if (locals == NULL) {
+ locals = f->f_locals = PyDict_New();
+ if (locals == NULL)
+ return -1;
+ }
+ co = f->f_code;
+ map = co->co_varnames;
+ if (!PyTuple_Check(map)) {
+ PyErr_Format(PyExc_SystemError,
+ "co_varnames must be a tuple, not %s",
+ Py_TYPE(map)->tp_name);
+ return -1;
+ }
+ fast = f->f_localsplus;
+ j = PyTuple_GET_SIZE(map);
+ if (j > co->co_nlocals)
+ j = co->co_nlocals;
+ if (co->co_nlocals) {
+ if (map_to_dict(map, j, locals, fast, 0) < 0)
+ return -1;
+ }
+ ncells = PyTuple_GET_SIZE(co->co_cellvars);
+ nfreevars = PyTuple_GET_SIZE(co->co_freevars);
+ if (ncells || nfreevars) {
+ if (map_to_dict(co->co_cellvars, ncells,
+ locals, fast + co->co_nlocals, 1))
+ return -1;
+
+ /* If the namespace is unoptimized, then one of the
+ following cases applies:
+ 1. It does not contain free variables, because it
+ uses import * or is a top-level namespace.
+ 2. It is a class namespace.
+ We don't want to accidentally copy free variables
+ into the locals dict used by the class.
+ */
+ if (co->co_flags & CO_OPTIMIZED) {
+ if (map_to_dict(co->co_freevars, nfreevars,
+ locals, fast + co->co_nlocals + ncells, 1) < 0)
+ return -1;
+ }
+ }
+ return 0;
+}
+
+void
+PyFrame_FastToLocals(PyFrameObject *f)
+{
+ int res;
+
+ assert(!PyErr_Occurred());
+
+ res = PyFrame_FastToLocalsWithError(f);
+ if (res < 0)
+ PyErr_Clear();
+}
+
+void
+PyFrame_LocalsToFast(PyFrameObject *f, int clear)
+{
+ /* Merge f->f_locals into fast locals */
+ PyObject *locals, *map;
+ PyObject **fast;
+ PyObject *error_type, *error_value, *error_traceback;
+ PyCodeObject *co;
+ Py_ssize_t j;
+ Py_ssize_t ncells, nfreevars;
+ if (f == NULL)
+ return;
+ locals = f->f_locals;
+ co = f->f_code;
+ map = co->co_varnames;
+ if (locals == NULL)
+ return;
+ if (!PyTuple_Check(map))
+ return;
+ PyErr_Fetch(&error_type, &error_value, &error_traceback);
+ fast = f->f_localsplus;
+ j = PyTuple_GET_SIZE(map);
+ if (j > co->co_nlocals)
+ j = co->co_nlocals;
+ if (co->co_nlocals)
+ dict_to_map(co->co_varnames, j, locals, fast, 0, clear);
+ ncells = PyTuple_GET_SIZE(co->co_cellvars);
+ nfreevars = PyTuple_GET_SIZE(co->co_freevars);
+ if (ncells || nfreevars) {
+ dict_to_map(co->co_cellvars, ncells,
+ locals, fast + co->co_nlocals, 1, clear);
+ /* Same test as in PyFrame_FastToLocals() above. */
+ if (co->co_flags & CO_OPTIMIZED) {
+ dict_to_map(co->co_freevars, nfreevars,
+ locals, fast + co->co_nlocals + ncells, 1,
+ clear);
+ }
+ }
+ PyErr_Restore(error_type, error_value, error_traceback);
+}
+
+/* Clear out the free list */
void
_PyFrame_ClearFreeList(void)
-{
+{
#if PyFrame_MAXFREELIST > 0
- while (free_list != NULL) {
- PyFrameObject *f = free_list;
- free_list = free_list->f_back;
- PyObject_GC_Del(f);
- --numfree;
- }
- assert(numfree == 0);
+ while (free_list != NULL) {
+ PyFrameObject *f = free_list;
+ free_list = free_list->f_back;
+ PyObject_GC_Del(f);
+ --numfree;
+ }
+ assert(numfree == 0);
#endif
-}
-
-void
+}
+
+void
_PyFrame_Fini(void)
-{
+{
_PyFrame_ClearFreeList();
-}
-
-/* Print summary info about the state of the optimized allocator */
-void
-_PyFrame_DebugMallocStats(FILE *out)
-{
+}
+
+/* Print summary info about the state of the optimized allocator */
+void
+_PyFrame_DebugMallocStats(FILE *out)
+{
#if PyFrame_MAXFREELIST > 0
- _PyDebugAllocatorStats(out,
- "free PyFrameObject",
- numfree, sizeof(PyFrameObject));
+ _PyDebugAllocatorStats(out,
+ "free PyFrameObject",
+ numfree, sizeof(PyFrameObject));
#endif
-}
-
+}
+
PyCodeObject *
PyFrame_GetCode(PyFrameObject *frame)